Skip to content

Instantly share code, notes, and snippets.

@agwells
Created February 19, 2020 10:35
Show Gist options
  • Save agwells/d2fc78cd0a9fd33be3a32a6d49fe336f to your computer and use it in GitHub Desktop.
Save agwells/d2fc78cd0a9fd33be3a32a6d49fe336f to your computer and use it in GitHub Desktop.
Webpack config to compile Create React App code to execute in Node
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const NodemonPlugin = require('nodemon-webpack-plugin');
// Directory the compiled SSR server and assets will go in
const SSR_BUILD_PATH = './ssr-build'
const originalNodeEnv = process.env.NODE_ENV;
// This must be "production" for the CRA webpack config to be correct.
process.env.NODE_ENV = 'production';
const makeConfig = require('react-scripts/config/webpack.config.js');
const baseConfig = makeConfig('production');
// Now we can change it back (so that if we're running this in watch mode,
// it'll use "production" for compiling, but "development" for running the server)
process.env.NODE_ENV = originalNodeEnv;
// Remove the eslint loader since we do linting elsewhere.
// (This greatly speeds up build times)
baseConfig.module.rules.splice(1, 1);
// Override some parts of the default CRA config.
const config = {
...baseConfig,
bail: true,
// We don't need to minimize anything, because this HTML won't be served over the internet directly
optimization: {
minimize: false,
nodeEnv: false,
namedModules: true,
namedChunks: true,
moduleIds: 'named',
chunkIds: 'named',
},
// We want the compiled code to run in a Node environment
target: 'node',
// Start the dependency graph from this file (instead of `src/index.tsx`)
entry: path.resolve('./src/server/index.ts'),
output: {
// Name to use for the compiled bundle (executing this will be like
// executing `src/server/index.ts`)
filename: 'server.js',
// Put build products here
path: path.resolve(SSR_BUILD_PATH),
// The base URL path for the app (so links to static assets will be relative
// to this.)
publicPath: '/',
},
// Don't mock any node libraries (we don't need to mock them because we're
// actually running in Node. :-P)
node: false,
// Don't bundle in `node_modules` (the running app can just load in the files
// from `node_modules` itself)
externals: [
nodeExternals(),
],
// Keep only these two plugins. The others are related to features we don't
// need when compiling for SSR (like linting, generating the manifest, etc)
plugins: [
...baseConfig.plugins.filter((plugin) =>
['HtmlWebpackPlugin', 'MiniCssExtractPlugin'].includes(
plugin.constructor.name
)
),
// Use nodemon for hot-reloading SSR server, when running Webpack in "watch" mode
new NodemonPlugin({ script: path.resolve(SSR_BUILD_PATH, 'server.js') }),
],
};
module.exports = config;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment