ssr with react and express and required stats.json 解释
ssr with react and express and requiring stats.json explanation
我正在查看底部的代码示例,这是一个 react ssr 示例:
在configureProduction
函数中,有这一行:
const clientStats = require('./assets/stats.json');
需要的 stats.json 文件是什么?
import express from 'express';
import { join } from 'path';
import { log } from 'winston';
/**
* Configures hot reloading and assets paths for local development environment.
* Use the `npm start` command to start the local development server.
*
* @param app Express app
*/
const configureDevelopment = app => {
const clientConfig = require('../webpack/client');
const serverConfig = require('../webpack/server');
const publicPath = clientConfig.output.publicPath;
const outputPath = clientConfig.output.path;
const multiCompiler = require('webpack')([clientConfig, serverConfig]);
const clientCompiler = multiCompiler.compilers[0];
app.use(require('webpack-dev-middleware')(multiCompiler, {publicPath}));
app.use(require('webpack-hot-middleware')(clientCompiler));
app.use(publicPath, express.static(outputPath));
app.use(require('webpack-hot-server-middleware')(multiCompiler, {
serverRendererOptions: { outputPath }
}));
app.set('views', join(__dirname, '../public/views'));
};
/**
* Configures assets paths for production environment.
* This environment is used in deployment and inside the docker container.
* Use the `npm run build` command to create a production build.
*
* @param app Express app
*/
const configureProduction = app => {
const clientStats = require('./assets/stats.json');
const serverRender = require('./assets/app.server.js').default;
const publicPath = '/';
const outputPath = join(__dirname, 'assets');
app.use(publicPath, express.static(outputPath));
app.use(serverRender({
clientStats,
outputPath
}));
app.set('views', join(__dirname, 'views'));
};
const app = express();
log('info', `Configuring server for environment: ${process.env.NODE_ENV}...`);
if (process.env.NODE_ENV === 'development') {
configureDevelopment(app);
} else {
configureProduction(app);
}
log('info', 'Configuring server engine...');
app.set('view engine', 'ejs');
app.set('port', process.env.PORT || 3000);
app.listen(app.get('port'), () => log('info', `Server listening on port ${app.get('port')}...`));
这可能是由 webpack 插件 (https://github.com/danethurber/webpack-manifest-plugin) 在构建 client-side 包后生成的文件,该文件名经过哈希处理并且是服务器所必需的,因此它知道如何呈现然后 bootstrap 客户端的基本模板。
当然这是猜测,因为我们无权访问您的 json
文件、webpack
配置或 package.json
..
此存储库使用类似的方法:https://github.com/CheesecakeLabs/react-redux-boilerplate/
它构建客户端,生成相同类型的文件,然后使用该 JSON 文件作为信息点构建服务器包,以了解客户端包的命名方式。
JSON 文件应该类似于:
{
"apple-touch-icon.png": "114dec1694406188ff0cb2698607cbca.png",
"production.css": "production.fbee6dc76218b122f7ff.css",
"production.css.map": "production.fbee6dc76218b122f7ff.css.map",
"production.js": "production.fbee6dc76218b122f7ff.js",
"production.js.map": "production.fbee6dc76218b122f7ff.js.map",
"safari-pinned-tab.svg": "f157afc1cf258044878dab6647d2800b.svg"
}
stats.json
文件由 webpack-stats-plugin
生成,Node 进程可以将其用于 "identify the correct bundle path in your server": https://github.com/FormidableLabs/webpack-stats-plugin
您正在查看的项目如下
https://github.com/rherwig/template-react-16-ssr/blob/master/src/index.js
如果您查看下面的 client.production.js
文件
代码使用
plugins: [
new ExtractCssChunks(),
new webpack.optimize.CommonsChunkPlugin({
names: ['bootstrap'],
filename: '[name].js',
minChunks: Infinity
}),
new StatsWebpackPlugin('stats.json'),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
})
]
如您所见,它使用 StatsWebpackPlugin
将统计信息保存在 stats.json
中。现在让我们看看用法
const serverRender = require('./assets/app.server.js').default;
app.use(serverRender({
clientStats,
outputPath
}));
所以它将 clientStats
和 outputPath
传递给 serverRender
,这是 assets/app.server.js
的默认导出。现在,如果您查看文件
https://github.com/rherwig/template-react-16-ssr/blob/master/src/server/index.js
export default ({ clientStats }) => async (req, res) => {
const app = (
<App/>
);
const appString = ReactDOM.renderToString(app);
const chunkNames = flushChunkNames();
const { js, styles, cssHash } = flushChunks(clientStats, { chunkNames });
....
};
它将 clientStats
传递给来自 webpack-flush-chunks
的 flushChunks
。即获取生成文件的css
、js
包含脚本。然后用于渲染模板
res.render('index', {
appString,
js,
styles,
cssHash
});
如果您查看 index.ejs
模板
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<%- styles %>
<title>React 16 | Sample</title>
</head>
<body>
<div id="react-root"><%- appString %></div>
<%- cssHash %>
<%- js %>
</body>
</html>
它在渲染页面上使用CSS, JS 链接。所有这些都是必需的,因为我们需要由插件 ExtractCssChunks
和 webpack.optimize.CommonsChunkPlugin
生成的块的信息
我正在查看底部的代码示例,这是一个 react ssr 示例:
在configureProduction
函数中,有这一行:
const clientStats = require('./assets/stats.json');
需要的 stats.json 文件是什么?
import express from 'express';
import { join } from 'path';
import { log } from 'winston';
/**
* Configures hot reloading and assets paths for local development environment.
* Use the `npm start` command to start the local development server.
*
* @param app Express app
*/
const configureDevelopment = app => {
const clientConfig = require('../webpack/client');
const serverConfig = require('../webpack/server');
const publicPath = clientConfig.output.publicPath;
const outputPath = clientConfig.output.path;
const multiCompiler = require('webpack')([clientConfig, serverConfig]);
const clientCompiler = multiCompiler.compilers[0];
app.use(require('webpack-dev-middleware')(multiCompiler, {publicPath}));
app.use(require('webpack-hot-middleware')(clientCompiler));
app.use(publicPath, express.static(outputPath));
app.use(require('webpack-hot-server-middleware')(multiCompiler, {
serverRendererOptions: { outputPath }
}));
app.set('views', join(__dirname, '../public/views'));
};
/**
* Configures assets paths for production environment.
* This environment is used in deployment and inside the docker container.
* Use the `npm run build` command to create a production build.
*
* @param app Express app
*/
const configureProduction = app => {
const clientStats = require('./assets/stats.json');
const serverRender = require('./assets/app.server.js').default;
const publicPath = '/';
const outputPath = join(__dirname, 'assets');
app.use(publicPath, express.static(outputPath));
app.use(serverRender({
clientStats,
outputPath
}));
app.set('views', join(__dirname, 'views'));
};
const app = express();
log('info', `Configuring server for environment: ${process.env.NODE_ENV}...`);
if (process.env.NODE_ENV === 'development') {
configureDevelopment(app);
} else {
configureProduction(app);
}
log('info', 'Configuring server engine...');
app.set('view engine', 'ejs');
app.set('port', process.env.PORT || 3000);
app.listen(app.get('port'), () => log('info', `Server listening on port ${app.get('port')}...`));
这可能是由 webpack 插件 (https://github.com/danethurber/webpack-manifest-plugin) 在构建 client-side 包后生成的文件,该文件名经过哈希处理并且是服务器所必需的,因此它知道如何呈现然后 bootstrap 客户端的基本模板。
当然这是猜测,因为我们无权访问您的 json
文件、webpack
配置或 package.json
..
此存储库使用类似的方法:https://github.com/CheesecakeLabs/react-redux-boilerplate/ 它构建客户端,生成相同类型的文件,然后使用该 JSON 文件作为信息点构建服务器包,以了解客户端包的命名方式。
JSON 文件应该类似于:
{
"apple-touch-icon.png": "114dec1694406188ff0cb2698607cbca.png",
"production.css": "production.fbee6dc76218b122f7ff.css",
"production.css.map": "production.fbee6dc76218b122f7ff.css.map",
"production.js": "production.fbee6dc76218b122f7ff.js",
"production.js.map": "production.fbee6dc76218b122f7ff.js.map",
"safari-pinned-tab.svg": "f157afc1cf258044878dab6647d2800b.svg"
}
stats.json
文件由 webpack-stats-plugin
生成,Node 进程可以将其用于 "identify the correct bundle path in your server": https://github.com/FormidableLabs/webpack-stats-plugin
您正在查看的项目如下
https://github.com/rherwig/template-react-16-ssr/blob/master/src/index.js
如果您查看下面的 client.production.js
文件
代码使用
plugins: [
new ExtractCssChunks(),
new webpack.optimize.CommonsChunkPlugin({
names: ['bootstrap'],
filename: '[name].js',
minChunks: Infinity
}),
new StatsWebpackPlugin('stats.json'),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
})
]
如您所见,它使用 StatsWebpackPlugin
将统计信息保存在 stats.json
中。现在让我们看看用法
const serverRender = require('./assets/app.server.js').default;
app.use(serverRender({
clientStats,
outputPath
}));
所以它将 clientStats
和 outputPath
传递给 serverRender
,这是 assets/app.server.js
的默认导出。现在,如果您查看文件
https://github.com/rherwig/template-react-16-ssr/blob/master/src/server/index.js
export default ({ clientStats }) => async (req, res) => {
const app = (
<App/>
);
const appString = ReactDOM.renderToString(app);
const chunkNames = flushChunkNames();
const { js, styles, cssHash } = flushChunks(clientStats, { chunkNames });
....
};
它将 clientStats
传递给来自 webpack-flush-chunks
的 flushChunks
。即获取生成文件的css
、js
包含脚本。然后用于渲染模板
res.render('index', {
appString,
js,
styles,
cssHash
});
如果您查看 index.ejs
模板
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<%- styles %>
<title>React 16 | Sample</title>
</head>
<body>
<div id="react-root"><%- appString %></div>
<%- cssHash %>
<%- js %>
</body>
</html>
它在渲染页面上使用CSS, JS 链接。所有这些都是必需的,因为我们需要由插件 ExtractCssChunks
和 webpack.optimize.CommonsChunkPlugin