默认angular配置:入口文件size高达7MB,DOMContentload和load分别为3.22s和3.43秒
1、安装 angular-builders
npm install @angular-builders/custom-webpack --save-dev
npm install @angular-devkit/build-angular --save-dev
2.修改angular.json中 build和server的配置
"architect": {
......
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./webpack.config.js"
}
}
},
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"customWebpackConfig": {
"path": "./webpack.config.js"
}
}
}
}
3.自定义webpack.config.js配置
const webpack = require('webpack');
const pkg = require('./package.json');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
optimization: {
splitChunks: {
chunks: 'all', // 共有三个值可选:initial(初始模块)、async(按需加载模块)和all(全部模块)
minSize: 30000, // 模块超过30k自动被抽离成公共模块
// minChunks: 1, // 模块被引用>=1次,便分割
maxAsyncRequests: 5, // 异步加载chunk的并发请求数量<=5
maxInitialRequests: 5, // 一个入口并发加载的chunk数量<=3
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
angular: {
name: 'angular',
test: /[\\/]node_modules[\\/]@angular[\\/]/,
priority: -8
},
monaco_editor: {
test: /[\\/]node_modules[\\/](monaco-editor)[\\/]/,
name: 'monaco-editor',
priority: -9
},
vendors: {
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
priority: -10
},
// 缓存组,会继承和覆盖splitChunks的配置
default: {
// 模块缓存规则,设置为false,默认缓存组将禁用
minChunks: 2, // 模块被引用>=2次,拆分至vendors公共模块
priority: -20, // 优先级
reuseExistingChunk: true // 默认使用已有的模块
}
}
}
},
plugins: [
new webpack.DefinePlugin({
APP_VERSION: JSON.stringify(pkg.version)
}),
// new BundleAnalyzerPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.join(__dirname, 'src/index.html'),
chunksSortMode: 'manual',
chunks: ['styles', 'runtime', 'polyfills', 'scripts', 'vendors', 'main'] // 限定顺序,main.js必须在最后
})
]
};
··这里说明下配置
(1).BundleAnalyzerPlugin
我注释掉了,因为不想编译时候自动启动,我选择npm加入script命令,有需要的时候执行命令生成stat.json并运行
"analyze": "webpack-bundle-analyzer dist/stats.json"
(2) DefinePlugin 测试webpack.config.js是否被引入。注:ng build模式或builder为custom-builder才生效
app.component.ts 里声明
declare var APP_VERSION: string;
@Component({
selector: 'root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.less']
})
ngOnInit(): void {
console.log('APP_VERSION:', APP_VERSION);
}
(3)最重要的是htmlwebpackplugin
splitChunks 把最主要的node_modules angular monaco-editor 三个包最主要的大型包都从主入口main.js抽出来了。
如果没有用htmlwebpackplugin,angular.json默认配置生成的html,不会引入我新抽出来的js,配置mergeRules,mergeStrategies都不好使。
"customWebpackConfig": {
··"path": "./webpack.config.js",
"mergeRules": {
"externals": "replace"
},
"mergeStrategies": {
"module.rules": "prepend"
},
"replaceDuplicatePlugins": true
}
最终用htmlwebpackplugin生成的html,并修改angular.json配置,把原html修改名字
"index": {
"input": "src/index.html",
"output": "index-old.html"
},
最后附上完整的angular.json
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"outputPath": "dist/onenote",
"index": {
"input": "src/index.html",
"output": "index-old.html"
},
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets",
{
"glob": "**/*",
"input": "./node_modules/mathjax",
"output": "/"
},
{
"glob": "**/*",
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
"output": "/assets/"
},
{
"glob": "**/*",
"input": "./WEB-INF",
"output": "/WEB-INF/"
}
],
"styles": [
"src/styles/theme/light/antd-light.less",
"src/styles.less",
"./node_modules/highlight.js/styles/github.css",
"./node_modules/monaco-editor/min/vs/editor/editor.main.css",
"./node_modules/github-markdown-css/github-markdown.css"
],
"stylePreprocessorOptions": {
"includePaths": [
"src/styles/theme",
"src/styles/theme/dark",
"src/styles/theme/light"
]
},
"scripts": [
"node_modules/mathjax/MathJax.js",
"node_modules/systemjs/dist/s.js",
"node_modules/systemjs/dist/extras/amd.js",
"node_modules/systemjs/dist/extras/named-register.js",
"node_modules/systemjs/dist/extras/use-default.js"
],
"customWebpackConfig": {
"path": "./webpack.config.js"
}
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": true,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
},
"analyzer": {
"optimization": true,
"outputHashing": "all",
"sourceMap": true,
"namedChunks": true,
"extractCss": true,
"extractLicenses": true,
"vendorChunk": true,
"buildOptimizer": true,
}
}
},
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"browserTarget": "onenote:build",
"customWebpackConfig": {
"path": "./webpack.config.js"
}
},
"configurations": {
"production": {
"browserTarget": "onenote:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "onenote:build"
}
},
"test": {
"builder": "ngx-build-plus:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"styles": [
"src/styles.less"
],
"scripts": [],
"assets": [
"src/favicon.ico",
"src/assets"
]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}