ReactJS 服务器端渲染与热重载 (webpack-dev-server)
ReactJS server side rendering with hot reloading (webpack-dev-server)
我正在尝试使用 ReactJS 构建我的第一个服务器端渲染。我的代码基于 this Redux tutorial
应用程序在 运行 npm start
(webpack && node server.js
) 时运行良好。
我想使用热重载来在开发环境中快速调试应用程序。所以我在我的 npm 配置中添加了 start
选项 (webpack-dev-server --inline --hot
)。请注意,我没有 index.html 文件,因为 react-router 正在选择要加载的正确 JSX 文件。
npm start 打开我的 public 文件夹并显示文件,但没有启动我的应用程序。通常我会点击 index.html 文件,但我有 none。
看不懂是怎么回事,不知道怎么解决。帮助表示赞赏。
package.json:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.config.prod.js -p",
"start": "webpack-dev-server --inline --hot",
"dev": "webpack && node server.js"
},
webpack.config.js:
module.exports = {
entry: './client.js',
output: {
filename: 'bundle.js',
path: __dirname + '/public'
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-0']
}
}
]
}
};
server.js
require('babel-register')({
presets: ['react', 'es2015', 'stage-0']
});
var express = require('express');
var config = require('config');
var app = express();
var serverConfig = config.get('serverConfig');
app.use(express.static('public'));
app.use(require('./routes/index.jsx'));
app.listen(serverConfig.port, function () {
console.log('FactoryWays server running on port ' + serverConfig.port);
console.log('Press CTRL-C to stop the server.');
});
client.js
var ReactDOM = require('react-dom');
var React = require('react');
var routes = require('./routes/routes.jsx');
var Redux = require('redux');
var Provider = require('react-redux').Provider;
function reducer(state) { return state; }
var store = Redux.createStore(reducer, window.PROPS);
ReactDOM.render(
<Provider store={store}>
{routes}
</Provider>, document
);
routes/index.jsx:
var router = require('express').Router();
var React = require('react');
var ReactDOMServer = require('react-dom/server');
var ReactRouter = require('react-router');
var Redux = require('redux');
var Provider = require('react-redux').Provider;
function reducer(state) { return state; }
router.get('*', function(request, response) {
var initialState = { title: 'Universal React' };
var store = Redux.createStore(reducer, initialState);
ReactRouter.match({
routes: require('./routes.jsx'),
location: request.url
}, function(error, redirectLocation, renderProps) {
if (renderProps) {
var html = ReactDOMServer.renderToString(
<Provider store={store}>
<ReactRouter.RouterContext {...renderProps} />
</Provider>
);
response.send(html);
} else {
response.status(404).send('Not Found');
}
});
});
module.exports = router;
routes/routes.jsx:
var React = require('react');
var ReactRouter = require('react-router');
var Router = ReactRouter.Router;
var Route = ReactRouter.Route;
var IndexRoute = ReactRouter.IndexRoute;
var browserHistory = ReactRouter.browserHistory;
module.exports = (
<Router history={browserHistory}>
<Route path='/' component={require('../views/Layout.jsx')}>
<IndexRoute component={require('../views/Index.jsx')} />
</Route>
</Router>
);
views/Layout.jsx:
var React = require('react');
var Link = require('react-router').Link;
var connect = require('react-redux').connect;
var Layout = React.createClass({
_handleClick: function() {
alert();
},
render: function() {
var custom = this.props.custom;
return (
<html>
<head>
<title>{custom.title}</title>
<link rel='stylesheet' href='/style.css' />
</head>
<body>
<h1>{custom.title}</h1>
<p>Isn't server-side rendering remarkable?</p>
<button onClick={this._handleClick}>Click Me</button>
{this.props.children}
<ul>
<li>
<Link to='/'>Home</Link>
</li>
<li>
<Link to='/about'>About</Link>
</li>
</ul>
<script dangerouslySetInnerHTML={{
__html: 'window.PROPS=' + JSON.stringify(custom)
}} />
<script src='/bundle.js' />
</body>
</html>
);
}
});
var wrapper = connect(
function(state) {
return { custom: state };
}
);
module.exports = wrapper(Layout);
Notice that I don't have a index.html file as react-router is choosing the proper JSX file to load
如果你 运行宁 webpack-dev-server
,你仍然需要一个。
Webpack 用于将 JavaScript 捆绑在一起。而已。在你的情况下(基于你的 webpack.config.js
文件),它在你的 public
目录中输出一个 bundle.js
文件。
Webpack Dev Server 是一个用于辅助开发的简单静态文件服务器。它对 server.js
.
中的服务器配置一无所知
您 package.json 中的两个命令需要不同的设置:
npm start
npm start
运行s webpack-dev-server
。默认情况下,webpack-dev-server
将提供当前目录的内容,因此您需要将 index.html
放在项目的根目录中。 index.html
的内容很简单:只是样板文件 HTML,其中包含一个 script
标记链接到您的 bundle.js
文件。
npm dev
然而,当您 运行 宁 npm dev
时,您正在运行自己的服务器,定义在 server.js
中。在这种情况下,它被配置为为您生成和提供 index.html
(以及您需要的所有其他静态文件)。
如果你想做hot-reloading和运行你自己的服务器,你可以添加webpack-dev-middleware到你的Express服务器。
我正在尝试使用 ReactJS 构建我的第一个服务器端渲染。我的代码基于 this Redux tutorial
应用程序在 运行 npm start
(webpack && node server.js
) 时运行良好。
我想使用热重载来在开发环境中快速调试应用程序。所以我在我的 npm 配置中添加了 start
选项 (webpack-dev-server --inline --hot
)。请注意,我没有 index.html 文件,因为 react-router 正在选择要加载的正确 JSX 文件。
npm start 打开我的 public 文件夹并显示文件,但没有启动我的应用程序。通常我会点击 index.html 文件,但我有 none。
看不懂是怎么回事,不知道怎么解决。帮助表示赞赏。
package.json:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.config.prod.js -p",
"start": "webpack-dev-server --inline --hot",
"dev": "webpack && node server.js"
},
webpack.config.js:
module.exports = {
entry: './client.js',
output: {
filename: 'bundle.js',
path: __dirname + '/public'
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-0']
}
}
]
}
};
server.js
require('babel-register')({
presets: ['react', 'es2015', 'stage-0']
});
var express = require('express');
var config = require('config');
var app = express();
var serverConfig = config.get('serverConfig');
app.use(express.static('public'));
app.use(require('./routes/index.jsx'));
app.listen(serverConfig.port, function () {
console.log('FactoryWays server running on port ' + serverConfig.port);
console.log('Press CTRL-C to stop the server.');
});
client.js
var ReactDOM = require('react-dom');
var React = require('react');
var routes = require('./routes/routes.jsx');
var Redux = require('redux');
var Provider = require('react-redux').Provider;
function reducer(state) { return state; }
var store = Redux.createStore(reducer, window.PROPS);
ReactDOM.render(
<Provider store={store}>
{routes}
</Provider>, document
);
routes/index.jsx:
var router = require('express').Router();
var React = require('react');
var ReactDOMServer = require('react-dom/server');
var ReactRouter = require('react-router');
var Redux = require('redux');
var Provider = require('react-redux').Provider;
function reducer(state) { return state; }
router.get('*', function(request, response) {
var initialState = { title: 'Universal React' };
var store = Redux.createStore(reducer, initialState);
ReactRouter.match({
routes: require('./routes.jsx'),
location: request.url
}, function(error, redirectLocation, renderProps) {
if (renderProps) {
var html = ReactDOMServer.renderToString(
<Provider store={store}>
<ReactRouter.RouterContext {...renderProps} />
</Provider>
);
response.send(html);
} else {
response.status(404).send('Not Found');
}
});
});
module.exports = router;
routes/routes.jsx:
var React = require('react');
var ReactRouter = require('react-router');
var Router = ReactRouter.Router;
var Route = ReactRouter.Route;
var IndexRoute = ReactRouter.IndexRoute;
var browserHistory = ReactRouter.browserHistory;
module.exports = (
<Router history={browserHistory}>
<Route path='/' component={require('../views/Layout.jsx')}>
<IndexRoute component={require('../views/Index.jsx')} />
</Route>
</Router>
);
views/Layout.jsx:
var React = require('react');
var Link = require('react-router').Link;
var connect = require('react-redux').connect;
var Layout = React.createClass({
_handleClick: function() {
alert();
},
render: function() {
var custom = this.props.custom;
return (
<html>
<head>
<title>{custom.title}</title>
<link rel='stylesheet' href='/style.css' />
</head>
<body>
<h1>{custom.title}</h1>
<p>Isn't server-side rendering remarkable?</p>
<button onClick={this._handleClick}>Click Me</button>
{this.props.children}
<ul>
<li>
<Link to='/'>Home</Link>
</li>
<li>
<Link to='/about'>About</Link>
</li>
</ul>
<script dangerouslySetInnerHTML={{
__html: 'window.PROPS=' + JSON.stringify(custom)
}} />
<script src='/bundle.js' />
</body>
</html>
);
}
});
var wrapper = connect(
function(state) {
return { custom: state };
}
);
module.exports = wrapper(Layout);
Notice that I don't have a index.html file as react-router is choosing the proper JSX file to load
如果你 运行宁 webpack-dev-server
,你仍然需要一个。
Webpack 用于将 JavaScript 捆绑在一起。而已。在你的情况下(基于你的 webpack.config.js
文件),它在你的 public
目录中输出一个 bundle.js
文件。
Webpack Dev Server 是一个用于辅助开发的简单静态文件服务器。它对 server.js
.
您 package.json 中的两个命令需要不同的设置:
npm start
npm start
运行s webpack-dev-server
。默认情况下,webpack-dev-server
将提供当前目录的内容,因此您需要将 index.html
放在项目的根目录中。 index.html
的内容很简单:只是样板文件 HTML,其中包含一个 script
标记链接到您的 bundle.js
文件。
npm dev
然而,当您 运行 宁 npm dev
时,您正在运行自己的服务器,定义在 server.js
中。在这种情况下,它被配置为为您生成和提供 index.html
(以及您需要的所有其他静态文件)。
如果你想做hot-reloading和运行你自己的服务器,你可以添加webpack-dev-middleware到你的Express服务器。