Upgrade to webpack 5

This commit is contained in:
2026-03-21 23:28:20 +01:00
parent 2772d82d2e
commit 3addbc1a4e
8 changed files with 942 additions and 1504 deletions
+776 -1441
View File
File diff suppressed because it is too large Load Diff
+8 -6
View File
@@ -26,7 +26,7 @@
"webpack-admin": "npm run webpack-prod -- --env.admin", "webpack-admin": "npm run webpack-prod -- --env.admin",
"webpack-stats": "npm run webpack-prod -- --env.debug --json > stats.json", "webpack-stats": "npm run webpack-prod -- --env.debug --json > stats.json",
"webpack-verbose": "npm run webpack-prod -- --verbose", "webpack-verbose": "npm run webpack-prod -- --verbose",
"wds": "webpack-dev-server --config webpack.dev.js --progress --color --debug --port 8091 --local", "wds": "webpack-dev-server --config webpack.dev.js --progress --color --port 8091",
"build": "gulp build", "build": "gulp build",
"build-sprites": "gulp sprites && npm run build", "build-sprites": "gulp sprites && npm run build",
"build-beta": "npm run build -- --beta --tools", "build-beta": "npm run build -- --beta --tools",
@@ -45,7 +45,10 @@
"latest-angular": "npm i @angular/common@latest @angular/compiler@latest @angular/core@latest @angular/forms@latest @angular/platform-browser@latest @angular/platform-browser-dynamic@latest @angular/router@latest @angular/animations@latest @angular/compiler-cli@latest @angular/platform-server@latest @angular/cdk@latest --save", "latest-angular": "npm i @angular/common@latest @angular/compiler@latest @angular/core@latest @angular/forms@latest @angular/platform-browser@latest @angular/platform-browser-dynamic@latest @angular/router@latest @angular/animations@latest @angular/compiler-cli@latest @angular/platform-server@latest @angular/cdk@latest --save",
"update-fontawesome": "npm update @fortawesome/fontawesome-svg-core @fortawesome/free-brands-svg-icons @fortawesome/free-solid-svg-icons @fortawesome/angular-fontawesome --save" "update-fontawesome": "npm update @fortawesome/fontawesome-svg-core @fortawesome/free-brands-svg-icons @fortawesome/free-solid-svg-icons @fortawesome/angular-fontawesome --save"
}, },
"devDependencies": {}, "devDependencies": {
"webpack": "^5.105.4",
"webpack-cli": "^3.3.12"
},
"dependencies": { "dependencies": {
"@angular/animations": "^8.2.4", "@angular/animations": "^8.2.4",
"@angular/cdk": "^8.1.4", "@angular/cdk": "^8.1.4",
@@ -106,6 +109,7 @@
"ag-psd": "^6.2.0", "ag-psd": "^6.2.0",
"ag-sockets": "^4.7.0", "ag-sockets": "^4.7.0",
"angular2-template-loader": "^0.6.2", "angular2-template-loader": "^0.6.2",
"babel-loader": "^10.1.1",
"base64-js": "^1.3.1", "base64-js": "^1.3.1",
"bluebird": "^3.5.5", "bluebird": "^3.5.5",
"body-parser": "^1.19.0", "body-parser": "^1.19.0",
@@ -178,7 +182,7 @@
"pug": "^2.0.4", "pug": "^2.0.4",
"pug-html-loader": "^1.1.5", "pug-html-loader": "^1.1.5",
"pug-plugin-ng": "0.0.2", "pug-plugin-ng": "0.0.2",
"raw-loader": "^1.0.0", "raw-loader": "^4.0.2",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"remap-istanbul": "^0.13.0", "remap-istanbul": "^0.13.0",
"request": "^2.88.0", "request": "^2.88.0",
@@ -186,7 +190,7 @@
"rollbar": "^2.12.2", "rollbar": "^2.12.2",
"rxjs": "^6.5.2", "rxjs": "^6.5.2",
"sass": "^1.58.3", "sass": "^1.58.3",
"sass-loader": "^7.3.1", "sass-loader": "^13.3.3",
"serve-favicon": "^2.5.0", "serve-favicon": "^2.5.0",
"sinon": "^7.4.1", "sinon": "^7.4.1",
"source-list-map": "^2.0.1", "source-list-map": "^2.0.1",
@@ -204,9 +208,7 @@
"ua-parser-js": "^0.7.20", "ua-parser-js": "^0.7.20",
"uglifyjs-webpack-plugin": "^1.3.0", "uglifyjs-webpack-plugin": "^1.3.0",
"webgl-debug": "^2.0.1", "webgl-debug": "^2.0.1",
"webpack": "^4.39.3",
"webpack-bundle-analyzer": "^3.4.1", "webpack-bundle-analyzer": "^3.4.1",
"webpack-cli": "^3.3.7",
"webpack-dev-server": "3.7.2", "webpack-dev-server": "3.7.2",
"webpack-merge": "^4.2.2", "webpack-merge": "^4.2.2",
"workbox-cli": "^4.3.1", "workbox-cli": "^4.3.1",
@@ -7,7 +7,7 @@ $chat-log-tabs-height: 30px;
$chat-log-buttons-width: 40px; $chat-log-buttons-width: 40px;
$resizer-size: 12px; $resizer-size: 12px;
$resizer-offset: $resizer-size / 2; $resizer-offset: $resizer-size * 0.5;
.chat-log { .chat-log {
display: flex; display: flex;
@@ -5,11 +5,11 @@ $slider-fill: #eaeaea;
$bar-height: 8px; $bar-height: 8px;
$bar-control-size: 20px; $bar-control-size: 20px;
$bar-border-radius: $bar-height / 2; $bar-border-radius: $bar-height * 0.5;
:host { :host {
display: inline-block; display: inline-block;
padding: 2px ($bar-control-size - $bar-height + 10px) / 2; padding: 2px ($bar-control-size - $bar-height + 10px) * 0.5;
width: 100%; width: 100%;
&:focus { &:focus {
@@ -61,8 +61,8 @@ $bar-border-radius: $bar-height / 2;
.slider-bar-control { .slider-bar-control {
position: absolute; position: absolute;
left: -$bar-control-size / 2; left: -$bar-control-size * 0.5;
top: -($bar-control-size - $bar-height) / 2; top: -($bar-control-size - $bar-height) * 0.5;
width: $bar-control-size; width: $bar-control-size;
height: $bar-control-size; height: $bar-control-size;
border-radius: 50%; border-radius: 50%;
@@ -18,8 +18,8 @@ $time-size: 20px;
> div { > div {
position: absolute; position: absolute;
left: -$state-size / 2; left: -$state-size * 0.5;
top: -$state-size / 2; top: -$state-size * 0.5;
width: $state-size; width: $state-size;
height: $state-size; height: $state-size;
background: gray; background: gray;
@@ -43,8 +43,8 @@ $time-size: 20px;
> div { > div {
position: absolute; position: absolute;
left: -$time-size / 2; left: -$time-size * 0.5;
top: -$time-size / 2; top: -$time-size * 0.5;
width: $time-size; width: $time-size;
height: $time-size; height: $time-size;
background: gray; background: gray;
+42 -13
View File
@@ -1,5 +1,7 @@
const webpack = require('webpack'); const webpack = require('webpack');
const path = require('path'); const path = require('path');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
module.exports = { module.exports = {
context: path.join(__dirname, 'src'), context: path.join(__dirname, 'src'),
@@ -20,39 +22,66 @@ module.exports = {
}, },
{ {
test: /\.css$/, test: /\.css$/,
use: ['raw-loader'], use: [{
loader: 'raw-loader',
options: {
esModule: false,
},
},],
}, },
{ {
test: /\.html$/, test: /\.html$/,
use: ['raw-loader'], use: [{
loader: 'raw-loader',
options: {
esModule: false,
},
},],
}, },
{ {
test: /\.pug$/, test: /\.pug$/,
use: [ use: [
'raw-loader', {
loader: 'raw-loader',
options: {
esModule: false,
},
},
{ {
loader: 'pug-html-loader', loader: 'pug-html-loader',
query: { doctype: 'html', plugins: require('pug-plugin-ng') }, options: { doctype: 'html', plugins: require('pug-plugin-ng') },
}, },
], ],
}, },
{ {
test: /\.scss$/, test: /\.scss$/,
use: [ use: [
'raw-loader', {
loader: 'raw-loader',
options: {
esModule: false,
},
},
{ {
loader: 'postcss-loader', loader: 'postcss-loader',
options: { options: {
ident: 'postcss', postcssOptions: {
plugins: loader => [ ident: 'postcss',
require('autoprefixer')('last 2 versions'), plugins: [
require('cssnano')({ discardComments: { removeAll: true } }), autoprefixer('last 2 versions'),
], cssnano({ discardComments: { removeAll: true } }),
],
}
}, },
}, },
{ {
loader: 'sass-loader', loader: 'sass-loader',
options: { includePaths: ['src/styles'] }, options: {
sassOptions: {
includePaths: ['src/styles'],
},
},
}, },
], ],
}, },
@@ -60,13 +89,13 @@ module.exports = {
// Mark files inside `@angular/core` as using SystemJS style dynamic imports. // Mark files inside `@angular/core` as using SystemJS style dynamic imports.
// Removing this will cause deprecation warnings to appear. // Removing this will cause deprecation warnings to appear.
test: /[\/\\]@angular[\/\\]core[\/\\].+\.js$/, test: /[\/\\]@angular[\/\\]core[\/\\].+\.js$/,
parser: { system: true }, // enable SystemJS parser: { system: false }, // disable SystemJS
}, },
], ],
}, },
plugins: [ plugins: [
new webpack.ContextReplacementPlugin( new webpack.ContextReplacementPlugin(
/\@angular(\\|\/)core(\\|\/)fesm5/, /\@angular(\\|\/)core(\\|\/)/,
path.resolve(__dirname, 'src', 'ts'), path.resolve(__dirname, 'src', 'ts'),
{} {}
), ),
+22 -10
View File
@@ -4,7 +4,7 @@ const common = require('./webpack.common.js');
const compilerOptions = { const compilerOptions = {
...require('./tsconfig.json').compilerOptions, ...require('./tsconfig.json').compilerOptions,
target: 'es5', target: 'es6',
module: 'es2015', module: 'es2015',
}; };
@@ -15,16 +15,26 @@ module.exports = merge(common, {
'bootstrap-admin': './ts/bootstrap-admin', 'bootstrap-admin': './ts/bootstrap-admin',
'bootstrap-tools': './ts/bootstrap-tools', 'bootstrap-tools': './ts/bootstrap-tools',
}, },
devtool: 'cheap-eval-source-map', devtool: 'eval-cheap-source-map',
devServer: { devServer: {
host: '0.0.0.0', host: '0.0.0.0',
port: 8090, port: 8090,
hot: true, hot: true,
historyApiFallback: true, compress: false,
publicPath: '/assets/scripts/', allowedHosts: ['all'],
stats: 'minimal', headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET',
'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization'
}
},
stats: {
preset: 'normal',
reasons: true,
modules: true,
errorDetails: true,
moduleTrace: true
}, },
stats: 'minimal',
output: { output: {
pathinfo: false pathinfo: false
}, },
@@ -49,7 +59,8 @@ module.exports = merge(common, {
}, },
optimization: { optimization: {
removeAvailableModules: false, removeAvailableModules: false,
removeEmptyChunks: false, removeEmptyChunks: false, // replacement of NamedModulesPlugin(),
moduleIds: 'named',
splitChunks: { splitChunks: {
cacheGroups: { cacheGroups: {
commons: { commons: {
@@ -61,8 +72,9 @@ module.exports = merge(common, {
}, },
}, },
plugins: [ plugins: [
new webpack.HotModuleReplacementPlugin(), new webpack.DefinePlugin({
new webpack.NamedModulesPlugin(), DEVELOPMENT: true, TOOLS: true, SERVER: false,
new webpack.DefinePlugin({ DEVELOPMENT: true, TOOLS: true, SERVER: false, BETA: true, TIMING: true, TESTS: false }), BETA: true, TIMING: true, TESTS: false
}),
], ],
}); });
+85 -25
View File
@@ -1,12 +1,17 @@
const path = require('path'); const path = require('path');
const webpack = require('webpack'); const webpack = require('webpack');
const merge = require('webpack-merge'); const { merge } = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); const TerserPlugin = require('terser-webpack-plugin');
const WrapperPlugin = require('wrapper-webpack-plugin'); const WrapperPlugin = require('wrapper-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const { AngularCompilerPlugin } = require('@ngtools/webpack'); const { AngularWebpackPlugin } = require('@ngtools/webpack');
const linkerPlugin = require('@angular/compiler-cli/linker/babel');
const common = require('./webpack.common.js'); const common = require('./webpack.common.js');
const config = require('./config.json'); const fs = require('fs');
const r = p => JSON.parse(fs.readFileSync(p, 'utf8'));
const config = r('./config.json');
const analytics = config.analytics ? ` const analytics = config.analytics ? `
(function(i, s, o, g, r, a, m) {i['GoogleAnalyticsObject']=r; i[r]=i[r]||function() { (function(i, s, o, g, r, a, m) {i['GoogleAnalyticsObject']=r; i[r]=i[r]||function() {
@@ -17,18 +22,23 @@ const analytics = config.analytics ? `
ga('send', 'pageview'); ga('send', 'pageview');
` : ``; ` : ``;
const compilerOptions = require('./tsconfig-aot.json').compilerOptions; const compilerOptions = r('./tsconfig-aot.json').compilerOptions;
const compilerOptionsES = require('./tsconfig-aot-es.json').compilerOptions; //const compilerOptionsES = r('./tsconfig-aot-es.json').compilerOptions;
const scripts = [ const scripts = [
['bootstrap', 'app/app.module#AppModule', 'assets', compilerOptions, 'tsconfig-aot.json', 5, false], ['bootstrap', 'app/app.module#AppModule', 'assets', compilerOptions, 'tsconfig-aot.json', 5, false],
// ['bootstrap-es', 'app/app.module#AppModule', 'assets', compilerOptionsES, 'tsconfig-aot-es.json', 7, false], // ['bootstrap-es', 'app/app.module#AppModule', 'assets', compilerOptionsES, 'tsconfig-aot-es.json', 7, false],
['bootstrap-admin', 'admin/admin.module#AdminAppModule', 'assets-admin', compilerOptions, 'tsconfig-aot.json', 5, true], ['bootstrap-admin', 'admin/admin.module#AdminAppModule', 'assets-admin', compilerOptions, 'tsconfig-aot-admin.json', 5, true],
['bootstrap-tools', 'tools/tools.module#ToolsAppModule', 'assets', compilerOptions, 'tsconfig-aot.json', 5, true], ['bootstrap-tools', 'tools/tools.module#ToolsAppModule', 'assets', compilerOptions, 'tsconfig-aot-tools.json', 5, true],
]; ];
const toolsScrips = ['bootstrap-tools', 'tools/tools.module#ToolsAppModule', 'assets', compilerOptions, 'tsconfig-aot-tools.json', 5, true];
const max = Math.max(...([...scripts, toolsScrips].map(e => e[0].length)));
function getScripts(args) { function getScripts(args) {
const { analyze, main, admin } = args; const { analyze, main, admin, tools, beta } = args;
if (tools || beta) {
return [...scripts, toolsScrips];
}
if (analyze || main) { if (analyze || main) {
return [scripts[0]]; return [scripts[0]];
@@ -41,7 +51,7 @@ function getScripts(args) {
module.exports = (args = {}) => module.exports = (args = {}) =>
getScripts(args) getScripts(args)
.map(([script, entry, outDir, compilerOptions, tsConfigPath, ecma, TOOLS]) => merge(common, { .map(([script, entry, outDir, compilerOptions, tsconfig, _ecma, TOOLS]) => merge(common, {
mode: 'production', mode: 'production',
performance: { performance: {
maxEntrypointSize: 10000000, maxEntrypointSize: 10000000,
@@ -52,38 +62,88 @@ module.exports = (args = {}) =>
}, },
output: Object.assign({}, common.output, { output: Object.assign({}, common.output, {
filename: '[name]-[chunkhash:10].js', filename: '[name]-[chunkhash:10].js',
path: path.resolve(__dirname, 'build', outDir, 'scripts'), path: path.resolve(__dirname, 'dist', 'browser' , outDir, 'scripts'),
}), }),
devtool: script === 'bootstrap' ? 'source-map' : false, devtool: script === 'bootstrap' ? 'source-map' : false,
node: { Buffer: false },
module: { module: {
rules: [ rules: [
{ {
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/, test: /\.m?js$/,
use: [ use: {
{ loader: '@ngtools/webpack', options: { sourcemap: true, compilerOptions } }, loader: 'babel-loader',
], options: {
plugins: [linkerPlugin],
compact: false,
cacheDirectory: true,
}
}
},
{
test: /\.[jt]sx?$/,
use: [{
loader: '@ngtools/webpack', options: {
sourcemap: true,
compilerOptions,
}
}],
}, },
], ],
}, },
stats: {
preset: 'normal',
reasons: true,
modules: true,
errorDetails: true,
moduleTrace: true
},
optimization: { optimization: {
minimizer: [ minimizer: [
new UglifyJSPlugin({ new TerserPlugin({
sourceMap: true, extractComments: {
uglifyOptions: { condition: true,
ecma, banner: false,
mangle: !args.debug, },
terserOptions: {
sourceMap: true,
ecma: 5,
mangle: {
properties: {
regex: /^__(?!default$)/,
},
},
output: { comments: false }, output: { comments: false },
compress: ecma !== 5 ? { inline: 1 } : {},
}, },
}), }),
], ],
}, },
plugins: [ plugins: [
new AngularCompilerPlugin({ tsConfigPath, entryModule: `src/ts/components/${entry}` }), new AngularWebpackPlugin({
tsconfig,
compilerOptions: {
angularCompilerOptions: {
entryModule: `src/ts/components/${entry}`,
},
}
}),
(script === 'bootstrap' && !args.analyze) ? new WrapperPlugin({ test: /\.js$/, header: analytics }) : undefined, (script === 'bootstrap' && !args.analyze) ? new WrapperPlugin({ test: /\.js$/, header: analytics }) : undefined,
args.analyze ? new BundleAnalyzerPlugin({ analyzerMode: 'static' }) : undefined, args.analyze ? new BundleAnalyzerPlugin({ analyzerMode: 'static' }) : undefined,
new webpack.DefinePlugin({ DEVELOPMENT: false, TOOLS, SERVER: false, BETA: !!args.beta, TIMING: !!args.timing, TESTS: false }), new webpack.DefinePlugin({
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), DEVELOPMENT: false, TOOLS, SERVER: false, BETA: !!args.beta,
TIMING: !!args.timing, TESTS: false,
ngJitMode: false, // NOTE: Enable this if you need more detailed JIT compiler error
ngI18nClosureMode: false, // disables localization closure
ngDevMode: false, // Disable angular dev
}),
new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/ }),
new webpack.ProgressPlugin({
handler: (percentage, message, ...args) => {
const fullMsg = `${args.join(' ')} ${message}`.trim();
const p = Math.floor(percentage * 100).toString();
const emp = ' '.repeat(3 - p.length);
const l = script.length;
const emp2 = ' '.repeat(max - l);
console.log(`[${p}%]${emp}[${script}] ${emp2} | ${fullMsg}`);
},
}),
].filter(x => x), ].filter(x => x),
})); }));