server: create production build with webpack directly

This commit is contained in:
Jesse Chan
2021-11-28 22:48:22 -08:00
parent a94bbb4198
commit 477919856b
8 changed files with 201 additions and 49 deletions

View File

@@ -118,7 +118,7 @@ module.exports = {
// We don't currently advertise code splitting but Webpack supports it.
filename: 'static/js/[name].[chunkhash:8].js',
chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
assetModuleFilename: 'static/media/[name].[hash:8].[ext]',
assetModuleFilename: 'static/media/[name].[hash:8][ext]',
// Point sourcemap entries to original disk location (format as URL on Windows)
devtoolModuleFilenameTemplate: (info) => path.relative(paths.appSrc, info.absoluteResourcePath).replace(/\\/g, '/'),
},
@@ -147,7 +147,7 @@ module.exports = {
new webpack.optimize.MinChunkSizePlugin({
minChunkSize: 10000,
}),
new WebpackBar(),
new WebpackBar({name: 'client'}),
],
optimization: {
minimize: true,

119
package-lock.json generated
View File

@@ -65,7 +65,7 @@
"@types/tar-fs": "^2.0.1",
"@typescript-eslint/eslint-plugin": "^5.4.0",
"@typescript-eslint/parser": "^5.4.0",
"@vercel/ncc": "^0.32.0",
"@vercel/webpack-asset-relocator-loader": "^1.7.0",
"autoprefixer": "^10.4.0",
"axios": "^0.24.0",
"axios-mock-adapter": "^1.20.0",
@@ -154,6 +154,7 @@
"terser-webpack-plugin": "^5.2.5",
"tldts": "^5.7.53",
"ts-jest": "^27.0.7",
"ts-loader": "^9.2.6",
"ts-node-dev": "^1.1.8",
"tsconfig-paths": "^3.12.0",
"typed-emitter": "^1.4.0",
@@ -4489,14 +4490,11 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@vercel/ncc": {
"version": "0.32.0",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.32.0.tgz",
"integrity": "sha512-S/SxTHHTbBQSOutpgnqEn+LyTfZcq9xMRAnzY05HpGVjxjmfmvg6SWZZkbW/GJIFznMmHGeGOrI1MEBD7efIkA==",
"dev": true,
"bin": {
"ncc": "dist/ncc/cli.js"
}
"node_modules/@vercel/webpack-asset-relocator-loader": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@vercel/webpack-asset-relocator-loader/-/webpack-asset-relocator-loader-1.7.0.tgz",
"integrity": "sha512-1Dy3BdOliDwxA7VZSIg55E1d/us2KvsCQOZV25fgufG//CsnZBGiSAL7qewTQf7YVHH0A9PHgzwMmKIZ8aFYVw==",
"dev": true
},
"node_modules/@webassemblyjs/ast": {
"version": "1.11.1",
@@ -17752,6 +17750,62 @@
"node": ">=10"
}
},
"node_modules/ts-loader": {
"version": "9.2.6",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.2.6.tgz",
"integrity": "sha512-QMTC4UFzHmu9wU2VHZEmWWE9cUajjfcdcws+Gh7FhiO+Dy0RnR1bNz0YCHqhI0yRowCE9arVnNxYHqELOy9Hjw==",
"dev": true,
"dependencies": {
"chalk": "^4.1.0",
"enhanced-resolve": "^5.0.0",
"micromatch": "^4.0.0",
"semver": "^7.3.4"
},
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"typescript": "*",
"webpack": "^5.0.0"
}
},
"node_modules/ts-loader/node_modules/enhanced-resolve": {
"version": "5.8.3",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz",
"integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==",
"dev": true,
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/ts-loader/node_modules/semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/ts-loader/node_modules/tapable": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/ts-node": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
@@ -22271,10 +22325,10 @@
}
}
},
"@vercel/ncc": {
"version": "0.32.0",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.32.0.tgz",
"integrity": "sha512-S/SxTHHTbBQSOutpgnqEn+LyTfZcq9xMRAnzY05HpGVjxjmfmvg6SWZZkbW/GJIFznMmHGeGOrI1MEBD7efIkA==",
"@vercel/webpack-asset-relocator-loader": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@vercel/webpack-asset-relocator-loader/-/webpack-asset-relocator-loader-1.7.0.tgz",
"integrity": "sha512-1Dy3BdOliDwxA7VZSIg55E1d/us2KvsCQOZV25fgufG//CsnZBGiSAL7qewTQf7YVHH0A9PHgzwMmKIZ8aFYVw==",
"dev": true
},
"@webassemblyjs/ast": {
@@ -32377,6 +32431,45 @@
}
}
},
"ts-loader": {
"version": "9.2.6",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.2.6.tgz",
"integrity": "sha512-QMTC4UFzHmu9wU2VHZEmWWE9cUajjfcdcws+Gh7FhiO+Dy0RnR1bNz0YCHqhI0yRowCE9arVnNxYHqELOy9Hjw==",
"dev": true,
"requires": {
"chalk": "^4.1.0",
"enhanced-resolve": "^5.0.0",
"micromatch": "^4.0.0",
"semver": "^7.3.4"
},
"dependencies": {
"enhanced-resolve": {
"version": "5.8.3",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz",
"integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==",
"dev": true,
"requires": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
}
},
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
}
},
"tapable": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
"dev": true
}
}
},
"ts-node": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",

View File

@@ -48,9 +48,7 @@
]
},
"scripts": {
"build": "npm run build-assets && npm run build-ts",
"build-assets": "node client/scripts/build.js",
"build-ts": "ncc build server/bin/start.ts -m -t -e geoip-country",
"build": "node scripts/build.js",
"build-pkg": "rm -rf dist && npm run build && pkg . --out-path dist-pkg",
"format-source": "prettier -w .",
"check-source-formatting": "prettier -c .",
@@ -116,7 +114,7 @@
"@types/tar-fs": "^2.0.1",
"@typescript-eslint/eslint-plugin": "^5.4.0",
"@typescript-eslint/parser": "^5.4.0",
"@vercel/ncc": "^0.32.0",
"@vercel/webpack-asset-relocator-loader": "^1.7.0",
"autoprefixer": "^10.4.0",
"axios": "^0.24.0",
"axios-mock-adapter": "^1.20.0",
@@ -205,6 +203,7 @@
"terser-webpack-plugin": "^5.2.5",
"tldts": "^5.7.53",
"ts-jest": "^27.0.7",
"ts-loader": "^9.2.6",
"ts-node-dev": "^1.1.8",
"tsconfig-paths": "^3.12.0",
"typed-emitter": "^1.4.0",

View File

@@ -14,8 +14,9 @@ const fs = require('fs-extra');
const webpack = require('webpack');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
const paths = require('../../shared/config/paths');
const config = require('../config/webpack.config.prod');
const paths = require('../shared/config/paths');
const clientConfig = require('../client/config/webpack.config.prod');
const serverConfig = require('../server/config/webpack.config.prod');
const {measureFileSizesBeforeBuild, printFileSizesAfterBuild} = FileSizeReporter;
@@ -39,7 +40,7 @@ const copyPublicFolder = () => {
const build = (previousFileSizes) => {
console.log('Creating an optimized production build...');
const compiler = webpack(config);
const compiler = webpack([clientConfig, serverConfig]);
return new Promise((resolve, reject) => {
compiler.run((err, stats) => {
if (err) {
@@ -60,7 +61,7 @@ measureFileSizesBeforeBuild(paths.appBuild)
.then((previousFileSizes) => {
// Remove all content but keep the directory so that
// if you're in it, you don't end up in Trash
fs.emptyDirSync(paths.appBuild);
fs.emptyDirSync(paths.dist);
// Merge with the public folder
copyPublicFolder();
// Start the webpack build
@@ -68,25 +69,20 @@ measureFileSizesBeforeBuild(paths.appBuild)
})
.then(
({stats, previousFileSizes}) => {
if (stats.hasErrors()) {
stats.compilation.errors.forEach((err) => {
console.error(err);
});
console.log(
stats.toString({
chunks: false,
colors: true,
}),
);
if (stats.hasErrors()) {
process.exit(1);
}
if (stats.hasWarnings()) {
console.log(chalk.yellow('Compiled with warnings.\n'));
stats.compilation.warnings.forEach((warning) => {
console.warn(warning);
});
}
console.log('File sizes after gzip:\n');
console.log('\nClient file sizes after gzip:\n');
printFileSizesAfterBuild(
stats,
stats.stats[0],
previousFileSizes,
paths.appBuild,
WARN_AFTER_BUNDLE_GZIP_SIZE,

View File

@@ -5,10 +5,7 @@ import chalk from 'chalk';
import enforcePrerequisites from './enforce-prerequisites';
import migrateData from './migrations/run';
if (process.env.NODE_ENV !== 'development') {
// Use production mode by default
process.env.NODE_ENV = 'production';
if (process.env.NODE_ENV == 'production') {
// Catch unhandled rejections and exceptions
// Traces are pretty useless with minimized production codes
// This avoids printing a large section of junk

View File

@@ -0,0 +1,73 @@
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
const WebpackBar = require('webpackbar');
const paths = require('../../shared/config/paths');
// Assert this just to be safe.
if (process.env.NODE_ENV !== 'production') {
throw new Error('Production builds must have NODE_ENV=production.');
}
module.exports = {
mode: 'production',
entry: path.resolve(__dirname, '../bin/start.ts'),
externals: {
'geoip-country': 'node-commonjs geoip-country',
},
resolve: {
extensions: ['.cjs', '.mjs', '.js', '.ts', '.json'],
alias: {
'@server': path.resolve(__dirname, '..'),
'@shared': path.resolve(__dirname, '../../shared'),
},
},
module: {
rules: [
{
test: /\.ts$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
context: path.resolve(__dirname, '..'),
},
},
{
test: /\.m?js$/,
parser: {amd: false},
use: {
loader: '@vercel/webpack-asset-relocator-loader',
options: {
outputAssetBase: 'data',
production: true, // optional, default is undefined
},
},
},
],
},
output: {
path: paths.dist,
filename: 'index.js',
libraryTarget: 'commonjs2',
},
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
output: {
comments: false,
},
},
extractComments: false,
}),
],
},
plugins: [new WebpackBar({name: 'server'})],
target: 'node',
ignoreWarnings: [
{
module: /node_modules\/yargs/,
},
],
};

View File

@@ -4,11 +4,8 @@ declare const PATHS: {
appPublic: string;
appHtml: string;
appIndex: string;
appPackageJson: string;
appSrc: string;
clientSrc: string;
testsSetup: string;
appNodeModules: string;
dist: string;
};
export = PATHS;

View File

@@ -31,11 +31,8 @@ const PATHS = {
appPublic: resolveApp('client/src/public/'),
appHtml: resolveApp('client/src/index.html'),
appIndex: resolveApp('client/src/javascript/app.tsx'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('./'),
clientSrc: resolveApp('client/src'),
testsSetup: resolveApp('tests/setupTests.js'),
appNodeModules: resolveApp('node_modules'),
dist: resolveApp('dist'),
};
module.exports = PATHS;