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

IT技术 reactjs webpack
2021-03-24 11:27:44

我有一个我一直在我的本地主机上开发的 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 个文件中的一个或全部)以使其在子目录中工作的(最佳方法)是什么?

该应用程序的完整源代码在这里,以防万一。

谢谢!

6个回答

如果您使用的是 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,您还需要"homepage": "/foobar/",在 package.json 文件中进行设置因此,生产构建指向正确的路径。

这工作神圣的耶稣它工作谢谢伙计我搜索了这个解决方案好几天了
2021-05-26 11:27:44
@sparshturkane 嘿!你能分享一个这样的工作例子吗?我也坚持这个。
2021-06-02 11:27:44
这适用于生产,但我仍在寻找在端口 :3000 上进行开发的解决方案,例如,我使用了一种解决方法:手动添加具有相对路径的包的包含(开发构建生成一个绝对路径到根) :我将 <script type="text/javascript" src="static/js/bundle.js"></script> 添加到 index.html
2021-06-15 11:27:44
谢谢@trenthogan,太棒了。但是作为新手,当我在没有 ROUTER 的教程中工作时,我被难倒在何处实际放置代码。这是有效的……在我的 index.js 中 import React from 'react'; 从 'react-dom' 导入 ReactDOM;导入'./css/index.css'; 从'./App'导入应用程序;import * as serviceWorker from './serviceWorker'; import { BrowserRouter as Router, Route } from 'react-router-dom'; ReactDOM.render( <Router basename={' foobar '}> <Route path="/" component={App} /> </Router>, document.getElementById('root')); serviceWorker.unregister();
2021-06-16 11:27:44
@DipenDedania 例如 <BrowserRouter basename="/calendar" /> <Link to="/today" /> .. 呈现 <a href="/calendar/today"> 来自文档。
2021-06-18 11:27:44
  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. 仅查看是否使用历史记录。在历史中添加基本名称

    const historyConfig = {
        basename: 'your subdirectory'
    };
    const history = createBrowserHistory(historyConfig);
谢谢,我正在使用历史,没有人提到
2021-06-03 11:27:44

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

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

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

我用来定义基本名称:

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

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

package.json 中主页的值是多少?
2021-05-24 11:27:44
如果您的子路线只有 1 级深,这是否仅适用?似乎你不能做像 '/app-root-dir/users/myname' 这样的事情,因为它会使 '/app-root-dir/users' 成为基本路由。
2021-05-25 11:27:44

为了让 React 应用程序在子目录中运行,我最近不得不做类似的事情。试试下面的方法,看看你的进展如何。

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>

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

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

output: {
  path: 'build',
  publicPath: "/vensa/",
  filename: 'bundle.js'
},
这看起来很棒,它如何自动生成带有正确前缀路径的 HTML 文件。我也需要改变路线吗?我越来越[Error] Warning: [react-router] Location "/vensa/" did not match any routes
2021-05-27 11:27:44
是的,我看到github.com/reactjs/react-router/blob/master/docs/guides/...但不确定如何将它与我目前使用的 browserHistory 一起使用。你知道@Brandon 吗?
2021-05-29 11:27:44
不要使用预先创建的browserHistory. 而是通过createHistory像这里的第一个示例一样称呼自己来创建自己的对象github.com/reactjs/react-router/blob/master/docs/guides/... 使用history您创建的对象而不是browserHistory.
2021-06-10 11:27:44
是的,我相信当您为路由器创建 History 对象时,您可以传递一个 basepath 选项/vensa,然后路由器应该可以工作。
2021-06-18 11:27:44