Как связать приложение React с подкаталогом на сервере?
У меня есть приложение 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 файла), чтобы заставить его работать в подкаталоге?
Полный исходный код приложения здесь в случае, если это помогает.
Спасибо!
Ответы
Ответ 1
Если вы используете 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. Таким образом, производственные сборки указывают на правильный путь.
Ответ 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>
);
Вам также может потребоваться обновить путь к вашему файлу bundle.js в 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>
Ответ 3
- Добавьте "homepage": " https://yourdomain/subdirectory/ " в package.json
- Обновите маршруты, установите подкаталог в маршруте,
<Router basename={'/directory-name'}>
<Route path='/' component={Home} />
</Router>
-
Добавьте базу в public/index.html. Это помогает установить путь без проблем.
<base href="%PUBLIC_URL%/">
-
сделать все CSS, JS, изображения и все ресурсы загрузки "./assets/your resource."
-
Только посмотрите, если вы используете историю. добавить базовое имя в историю
const historyConfig = {
basename: 'your subdirectory'
};
const history = createBrowserHistory(historyConfig);
Ответ 4
Используйте html-webpack-plugin, чтобы сгенерировать окончательный index.html
с правильными именами пакетов, которые были введены в него.
Затем установите output.publicPath в свою конфигурацию webpack, чтобы сообщить webpack о том, что ваши ресурсы будут развернуты:
output: {
path: 'build',
publicPath: "/vensa/",
filename: 'bundle.js'
},
Ответ 5
Или вы можете использовать переменную окружения, чтобы настроить все ваши ссылки вручную.
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 не поддерживает базовое имя в настоящее время.
<Router history={browserHistory} basename={'foobar'}>
<Route path="/" component={App} />
</Router>
Ответ 6
Добавляя к ответу trenthogan, мы можем присвоить basename для location.pathname
const loc = window.location || {};
<Router history={browserHistory} basename={loc.pathname || 'foobar'}>
<Route path="/" component={App} />
</Router>
С этим изменением приложение будет работать, даже если путь к подкаталогу изменится в будущем.
Ответ 7
В моей ситуации мне нужно было поддерживать сценарий, в котором может быть от 0 до многих подпапок с неизвестными именами, а в производстве используются только статические файлы.
В моем App.js я определил эту простую функцию:
const getBasename = path => path.substr(0, path.lastIndexOf('/'));
Который я использую для определения базового имени:
<Router basename={getBasename(window.location.pathname)}>
Это работает как без подпапок, так и со многими подпапками, а также может управлять перезагрузками.
Ответ 8
Спасибо @trenthogan, это круто. Но, будучи новичком, я был озадачен тем, куда на самом деле поместить код, поскольку я работал из учебника без ROUTER. Вот что сработало для меня, как только я все выяснил...
в моем index.js...
import React from 'react';
import ReactDOM from 'react-dom';
import './css/index.css';
import App from './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();
Который ранее выглядел как...
import React from 'react';
import ReactDOM from 'react-dom';
import './css/index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
Ответ 9
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
}
...