如何将React应用程序捆绑到服务器上的子目录中?

问题描述 投票:13回答:8

我有一个我在本地主机上开发的React应用程序。我想将它复制到服务器到名为vensa的子目录中。

我的webpack配置文件看起来像这样..

const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry: [
    './src/index.js'
  ],
  output: {
    path: 'build',
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel'
      },
      {
        test: /\.scss$/,
        loader: ExtractTextPlugin.extract('style', 'css!sass')
      },
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract('style', 'css')
      },
      {
        test: /\.(png|eot|svg|ttf|woff(2)?)(\?v=\d+\.\d+\.\d+)?/,
        loader: 'url'
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin('vensa-dashboard.css')
  ],
  devServer: {
    historyApiFallback: true,
    contentBase: './build'
  }
};

index.html文件看起来像这样......

<!DOCTYPE html>
<html>
<head>
  <title>Vensa Development Test</title>
  <link rel="stylesheet" href="/vensa-dashboard.css">
</head>
<body>
  <div class="container"></div>
  <script src="/bundle.js"></script>
</body>
</html>

和我的routes.js文件是......

import React from 'react';
import { Route, IndexRoute } from 'react-router';
import VensaDashboard from './components/VensaDashboard';
import Inbox from './components/Inbox';
import Todo from './components/Todo';
import Home from './components/Home';

export default (
  <Route path="/" component={VensaDashboard}>
    <IndexRoute component={Home} />
    <Route path="/message" component={Inbox} />
    <Route path="/todo/:todoPage" component={Todo} />
  </Route>
);

但是,如果我只运行webpack -p并将3个文件复制到该子目录,它不起作用,因为根路径是/,它找不到js和css文件。我不确定要更改(可能是这3个文件中的一个或全部)的最佳方式(才能让它在子目录中工作)?

该应用程序的完整源代码是here以防万一。

谢谢!

reactjs webpack
8个回答
24
投票

如果您使用的是React Router v4,您应该能够使用basename = {foobar}进行设置。

<Router history={browserHistory} basename={'foobar'}>
  <Route path="/" component={App} />
</Router>

链接到文档:https://reacttraining.com/react-router/web/api/BrowserRouter

注意:如果在子目录中使用create-react-app,您还需要在package.json文件中设置"homepage": "/foobar/",。因此,生产构建指向正确的道路。


2
投票

我最近不得不做类似的事情,以便在子目录中运行一个反应应用程序。试试下面的内容,看看你是如何进行的。

import React from 'react';
import { Router, Route, IndexRoute, useRouterHistory  } from 'react-router';
import { createHistory } from 'history';
import VensaDashboard from './components/VensaDashboard';
import Inbox from './components/Inbox';
import Todo from './components/Todo';
import Home from './components/Home';

// specify basename below if running in a subdirectory or set as "/" if app runs in root
const appHistory = useRouterHistory(createHistory)({
  basename: "/vensa"
});

export default (
  <Router history={appHistory} />
    <Route path="/" component={VensaDashboard}>
      <IndexRoute component={Home} />
      <Route path="/message" component={Inbox} />
      <Route path="/todo/:todoPage" component={Todo} />
    </Route>
  </Router>
);

您可能还需要在index.html中更新bundle.js文件的路径,如下所示

<!DOCTYPE html>
<html>
<head>
  <title>Vensa Development Test</title>
  <link rel="stylesheet" href="/vensa-dashboard.css">
</head>
<body>
  <div class="container"></div>
  <script src="bundle.js"></script>
</body>
</html>

1
投票

使用html-webpack-plugin生成最终的index.html,并自动注入正确的包名称。

然后在webpack配置中设置output.publicPath,告诉webpack将资产部署到的子目录:

output: {
  path: 'build',
  publicPath: "/vensa/",
  filename: 'bundle.js'
},

1
投票

或者您可以使用环境变量手动调整所有链接。

const ENV = process.env.NODE_ENV || 'local'; //development
const config = {
    publicPath: ENV !== 'production' ? '/' : '/dev/'
};
plugins: ([
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify(ENV),
            'process.env.config': JSON.stringify(config)
        })
})

然后你的一条路线:

<Route path={process.env.config.publicPath + "account/"} component={Account} />

然后你的链接:

<Link class="panel-close" href={process.env.config.publicPath + "account/"} >Account</Link>

这对我很有用。特别是因为我正在使用preact,其preact-router目前并不真正支持basename。

<Router history={browserHistory} basename={'foobar'}>
  <Route path="/" component={App} />
</Router>

1
投票

添加到trenthogan的回复中,我们可以将basename分配给location.pathname

const loc = window.location || {};
<Router history={browserHistory} basename={loc.pathname || 'foobar'}>
  <Route path="/" component={App} />
</Router>

通过此更改,即使子目录路径将来发生更改,该应用也将正常工作。


0
投票

在我的情况下,我需要支持一个场景,其中可能有0到多个具有未知名称的子文件夹,并且生产仅使用静态文件。

在我的App.js中,我定义了这个简单的函数:

const getBasename = path => path.substr(0, path.lastIndexOf('/'));

我用它来定义基名:

<Router basename={getBasename(window.location.pathname)}>

这适用于没有子文件夹以及许多子文件夹,它也可以管理重新加载。


0
投票
  1. 在package.json中添加“主页”:“https://yourdomain/subdirectory/
  2. 更新路由,在路由中设置子目录,
<Router basename={'/directory-name'}>
  <Route path='/' component={Home} />
</Router>
  1. 在public / index.html中添加base。它有助于设置路径没有问题。 <base href="%PUBLIC_URL%/">
  2. 使所有css,js,图像和所有资源加载'./assets/your resource。'
  3. 只看您是否使用历史记录。在历史记录中添加basename
    const historyConfig = {
        basename: 'your subdirectory'
    };
    const history = createBrowserHistory(historyConfig);

-1
投票
var sourcePath = path.resolve(__dirname, 'src', 'index.js');
var buildPath = path.resolve(__dirname, 'vensa');

module.exports = {
    entry: [sourcePath],
    output: {
        path: buildPath,
        filename: '[name]-[hash].js',
        hash: true
    }
    ...
© www.soinside.com 2019 - 2024. All rights reserved.