ssr with react和express并要求stats.json解释

时间:2018-02-18 08:37:59

标签: reactjs isomorphic-javascript

我正在查看底部的代码示例,它是一个反应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')}...`));

3 个答案:

答案 0 :(得分:2)

这可能是在构建客户端包之后由webpack插件(https://github.com/danethurber/webpack-manifest-plugin)生成的文件,该文件名是经过哈希处理并且是服务器所必需的,因此它知道如何呈现基本模板然后将引导客户端。

当然这是猜测,因为我们无法访问您的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"
}

答案 1 :(得分:2)

stats.json文件由webpack-stats-plugin生成,并且可由节点进程用于"在服务器中识别正确的捆绑路径" https://github.com/FormidableLabs/webpack-stats-plugin

答案 2 :(得分:1)

您正在查看的项目位于

之下

https://github.com/rherwig/template-react-16-ssr/blob/master/src/index.js

如果您查看下面的client.production.js文件

https://github.com/rherwig/template-react-16-ssr/blob/4402eb87fb2e45c16b0b6bd7d093d68ed529077b/webpack/client.production.js#L36

代码使用

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
    }));

所以它将clientStatsoutputPath传递给serverRenderassets/app.server.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 }); .... }; 。现在,如果你看文件

https://github.com/rherwig/template-react-16-ssr/blob/master/src/server/index.js

clientStats

它将flushChunks传递给来自webpack-flush-chunkscss。这是为生成的文件获取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> 模板

ExtractCssChunks

它使用渲染页面上的CSS,JS链接。所有这些都是必需的,因为我们需要因插件生成的块信息webpack.optimize.CommonsChunkPlugin<html> <head> <title>Page Title</title> </head> <body> <p> First number:<br> <input type="number" id="fir"> <br> Second number:<br> <input type="number" id="sec"> <br> Increment:<br> <input type="number" id="inc"> <br> </p> <button id="btn">Click</button> </body> </html>