I am looking at the code example at the bottom which is a react ssr example:
in the configureProduction
function, it has this line:
const clientStats = require('./assets/stats.json');
What is this stats.json file that is being required?
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')}...`));
This is likely to be a file generated by a webpack plugin (https://github.com/danethurber/webpack-manifest-plugin) after building the client-side bundle, that file name is hashed and necessary to the server so it knows how to render the base template which will then bootstrap the client.
Of course that's a guess since we don't have access to your json
file, webpack
configuration or package.json
..
This repository uses a similar approach: https://github.com/CheesecakeLabs/react-redux-boilerplate/ It builds the client, generates the same kind of file and then builds the server bundle using that JSON file as information point to understand how the client bundle is named.
The JSON file should be similar to this:
{
"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"
}
The stats.json
file is generated by the webpack-stats-plugin
and can be use by the Node process to "identify the correct bundle path in your server": https://github.com/FormidableLabs/webpack-stats-plugin
The project you are looking at is below
https://github.com/rherwig/template-react-16-ssr/blob/master/src/index.js
If you look at the client.production.js
file on below
https://github.com/rherwig/template-react-16-ssr/blob/4402eb87fb2e45c16b0b6bd7d093d68ed529077b/webpack/client.production.js#L36
The code uses
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')
}
})
]
As you can see it uses StatsWebpackPlugin
to save the stats in stats.json
. Now let's look at the usage
const serverRender = require('./assets/app.server.js').default;
app.use(serverRender({
clientStats,
outputPath
}));
So it is passing the clientStats
and outputPath
to the serverRender
, which the default export of the assets/app.server.js
. Now if you look at file
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 });
....
};
It passes the clientStats
to flushChunks
which is from webpack-flush-chunks
. Which is to get the css
, js
include scripts for the generated files. This is then used to render the template
res.render('index', {
appString,
js,
styles,
cssHash
});
If you look at the index.ejs
template
<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>
It uses the CSS, JS links on the rendered page. All this was needed because we need information of chunks which generated because of the plugins ExtractCssChunks
and webpack.optimize.CommonsChunkPlugin
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With