项目技术栈是
dva+antd-mobile,由于是早期项目,项目里webpack版本用的是3.5.6,所以有些配置我会加上webpack 4.x版本的写法。有些plugin或者相关配置列出的较少或者讲解比较浅显,可以到webpack官网或者对应的plugin Github上查看详细的参数配置哟。有不足之处还请指正 🙏。
Roadhog 官方介绍:Roadhog 是一个包含 dev 、build 和 test 的命令行工具,他基于 react-dev-utils,和 create-react-app 的体验保持一致。你可以想象他为可配置版的 create-react-app。
Roadhog是有一些特定的参数去写相关的打包配置,具体可参考 Roadhog。
但是想要添加一些 Roadhog 给定参数没有的配置,比如打包分析 plugin webpack-bundle-analyzer,还是需要单独创建一个 webpack.config.js 文件去配置。(没有找到直接在 .webpackrc.js 文件中配置的方法,有解决方案的老兄还请告知呀 👀)
优化从下面几个方向进行:
- 首先添加打包分析 - analyzer
- 减小打包文件体积
- 提升打包速度
- 提升打包后的文件加载速度
- 针对一些较大模块的处理
- CDN 引入部分基础依赖
打包分析 - webpack-bundle-analyzer
这个插件是分析项目打包后各个模块文件的大小
npm i -D webpack-bundle-analyzer
具体参数可参考:配置详情及参数链接
/* webpack.config.js */
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
···
plugin: [
···
new BundleAnalyzerPlugin()
]
···
/* package.json */
···
"scripts": {
···
"analyz": "NODE_ENV=production npm_config_report=true npm run build"
},
···
运行:npm run analyz, 默认地址 http://127.0.0.1:8888/
总体的减小打包体积
UglifyJsPlugin
删除文件里的注释和 console,删除冗余代码,减小打包体积的目的。还可以删除 debugger,设置 cache 缓存等配置。
webpack 3.x 版本:通过 webpack.optimize.UglifyJsPlugin 设置
/* webpack.config.js */
···
plugins: [
···
new webpack.optimize.UglifyJsPlugin({
cache: true,
compress: {
warnings: false, // 是否在UglifyJS删除没有用到的代码时输出警告信息,默认为false
drop_debugger: true, //自动删除debugger
drop_console: true, //自动删除console.log
},
}),
···
]
webpack 4.x 版本:webpack 4.x 版本移除了 webpack.optimize.UglifyJsPlugin 的使用,通过配置 optimization.minimize 与 optimization.minimizer 来自定义压缩相关的操作。
npm i -D uglifyjs-webpack-plugin
/* webpack.config.js */
···
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new UglifyJsPlugin({
// 相关配置
})
],
},
};
提升打包速度
ParalleUglifyPlugin
提升编译打包时 js 压缩速度,还可设置打包时删除注释和 console 等代码,可以合并上文中的 UglifyJsPlugin
npm i -D webpack-parallel-uglify-plugin
/* webpack.config.js */
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
plugin: [
···
new ParallelUglifyPlugin({
cacheDir: '.cache/', // 用作缓存的可选绝对路径。如果未提供,则不使用缓存。
uglifyJS: {
output: {
comments: false, // 是否保留代码中的注释,默认为保留
},
warnings: false, // 是否在UglifyJS删除没有用到的代码时输出警告信息,默认为false
compress: {
drop_console: true, // 是否删除代码中所有的console语句,默认为false
collapse_vars: true, // 是否内嵌虽然已经定义了,但是只用到一次的变量, 默认值false
reduce_vars: true, // 是否提取出现了多次但是没有定义成变量去引用的静态值,默认为false
},
},
}),
···
]
happypack
开启多进程编辑,提升 loader 解析速度
npm i -D happypack
/* webpack.config.js */
const HappyPack = require('happypack');
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
const createHappyPlugin = (id, loaders) =>
new HappyPack({
id: id,
loaders: loaders,
threadPool: happyThreadPool,
verbose: process.env.HAPPY_VERBOSE === '1', // make happy more verbose with HAPPY_VERBOSE=1
});
plugin: [
···
createHappyPlugin('happy-babel', [
{
loader: 'babel-loader',
options: {
babelrc: true,
cacheDirectory: true, // 启用缓存
},
},
])
···
]
提升加载速度
压缩打包后的文件
减小文件体积,节省服务器的网络带宽,加速网站打开速度。经过服务器压缩,客户端浏览器快速加压的原理,可以很大的减少网站的流量。
压缩方式有两个:一种是 zip 压缩,一种是 gzip 压缩。
-
zip-webpack-plugin-zip压缩,会把所有的文件全部压缩到一个zip文件中npm i -D zip-webpack-plugin
/* webpack.config.js */
const ZipPlugin = require('zip-webpack-plugin');
···
new ZipPlugin({
filename: 'index.zip',
}),
···
-
compression-webpack-plugin-gzip压缩,单独压缩每个文件npm i -D compression-webpack-plugin
/* webpack.config.js */
const CompressionPlugin = require('compression-webpack-plugin');
···
new CompressionPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: /\.js$|\.css$/,
threshold: 10240,
minRatio: 0.8,
}),
···
CommonChunkPlugin - 代码分割打包
抽取入口文件依赖的类库打包到
vendor文件中,首次加载后存在缓存中,此后的加载会在浏览器缓存中读取,提高加载速度。
webpack 3.x 版本
/* webpack.config.js */
···
// 把所有的依赖的类库打包到 vendor 文件中
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(path.join(__dirname, './node_modules')) === 0
);
}
})
···
webpack 4.x 版本
/* webpack.config.js */
···
optimization: {
splitChunks: {
chunks: 'all', // async对异步代码做分割/all同步和异步都分割/initial对同步代码做分割
minSize: 30000, // import引入的组件或者文件大于300000字节=30kb,才会做代码分割
minChunks: 1, // 当一个模块被用了多少次后就进行代码分割
···
}
}
···
css 抽离 JS 文件,单独打包
npm i -D extract-text-webpack-plugin
/* webpack.config.js */
const ExtractTextPlugin = require('extract-text-webpack-plugin');
···
plugins: [
new ExtractTextPlugin('[name].[contenthash].css')
]
···
针对大文件的处理
从
analyz分析可以看出moment、core-js、crypto-js文件过大,以下针对这三个模块进行处理。
moment - 解决 moment 文件过大有两个方法
IgnorePlugin插件
/* webpack.config.js */
plugins: [
···
// 忽略 moment.js的所有本地文件
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
···
]
需要手动引入 locale 文件:
const moment = require('moment');
require('moment/locale/ja');
moment.locale('ja');
...
ContextReplacementPlugin插件
/* webpack.config.js */
plugin: [
···
// 只加载 `moment/locale/ja.js` 和 `moment/locale/it.js`
new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /ja|it/)
···
]
不需要手动引入 locale 文件
const moment = require('moment');
// 不需要
moment.locale('ja');
...
core-js
我在项目中并没有用到 core-js,搜索插件得知这个是 @babel-polyfill 用的库,打包的时候一并打包了进来。 把
babel-polyfill提取出来 CDN 引入 polyfill
/* webpack.config.js */
···
externals: {
'babel-polyfill': 'window',
}
···
/* index.html script引入 */
<script src="https://cdn.bootcss.com/babel-polyfill/6.22.0/polyfill.min.js"></script>
crypto-js
这个是加解密相关的库
之前的引用方式是直接引入 crypto-js 整个方法(大概有四十多个文件方法,具体有多少方法可自行查看 node_modules 下的 crypto-js 文件),这样会把很多无用的方法也加载进来,增加打包体积:
const CryptoJS = require('crypto-js');
// 方法调用
CryptoJS.HmacSHA256
CryptoJS.enc.Base64
CryptoJS.enc.Utf8
优化使用相关方法,使用哪个就直接引入 crypto-js 下的该方法的文件:
const CryptoJS_HmacSHA256 = require('crypto-js/hmac-sha256');
const CryptoJS_Base64 = require('crypto-js/enc-base64');
const CryptoJS_Utf8 = require('crypto-js/enc-utf8');
CDN 引入基础依赖
提取
React和ReactDom,CDN引入
/* webpack.config.js */
···
externals: {
'react': 'React',
'react-dom': 'ReactDOM',
}
···
/* index.html script引入 */
<script src="https://unpkg.com/react@16.5.2/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16.5.2/umd/react-dom.production.min.js"></script>
END
老项目优化实属不易,整理一下优化方法,记录一下。
其实 react-count-animation 这个模块文件也挺大的,但是没有找到优化的方案,有优化方法的兄弟们望告知呀 🙏 。