引言
其实,相信很多只是从事快速应用开发的同学,对于 Webpack
打包优化方面可能是一知半解(我深有感触…)。但是,作为一名从事编程的人,我一直推崇的就是用编程高效、快速解决一些问题。因为,如果只是解决问题,我想这不是我想要的,就比如只会迭代不会递归,以及还停留在 console.log
调试代码等等。
当然,人总是从未知向知一点到知一些到构建完整的知识体系过渡,只要坚持,未知终将变为已知。那么,回到今天的正题,如何用Webpack
进行一些打包的优化?
在我们开始本篇文章之前,我们需要先安装两个 Plugin
用于分析 Wepack
打包的时间和打包后的各个模块的大小:
1.speed-measure-webpack-plugin
,它会分析每个 Loader
在打包过程中的耗时:
a. 首先安装依赖
npm install --save-dev speed-measure-webpack-plugin
b. 在 webpack.config.js
中使用
// 引入
const SpeedMeasurePlugin = require('speed-measure-plugin')
const speedMeasure = new SpeedMeasurePlugin
// 配置
const config = {
....
}
// 用 speed 插件包裹导出
module.exports = speedMeasure.wrap(config)
2.webpack-bundle-analyzer
,它会分析打包后的各个模块所占用的大小:
a. 安装依赖
npm install --save-dev webpack-bundle-analyzer
b. 配置 webpack.config.js
// 引入
const BundleAnalyzer = require('webpack-bundle-analyzer')
const config = {
...
plugin: [
...
new BundleAnalyzer()
]
}
c. 配置 package.js
中的 scripts
命令
{
...
'scripts`: {
"analyze": "cross-env NODE_ENV=production npm_config_report=true npm run build",
}
}
一、resolve 优化
resolve.modules
配置第三方模块对应的路径,即针对于代码中import from 'react'
之类的对应 from
后面的字符串,即不是绝对路径,又不是相对路径时命中的逻辑。
resolve: {
modules: [
resolve('node_modules') // 指定第三方模块去 node_modules 中查找
]
}
resolve.alias
针对特定的路径匹配(可以理解为指定)到对应已设好的目录,通常我们会用来指定自定义的组件文件夹。
resolve: {
alias: [
'component': resolve('src/component')
]
}
二、module 优化
noParse
忽略掉对一些文件的解析,例如 Jquery
之类的。
module: {
noParse: /Jquery/
}
loader优化
主要是用好一些 queryparams
以及精确地指定需要使用和不使用 loader
的地方,即 include
和 exclude
,例如对于 babel-loader
而言:
modulde: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader?cacheDirectory=true', // 缓存解析过的文件
include: resolve('src'),
exclude: /node_modules/
}
]
}
三、plugins 优化
webpack-parallel-uglify-plugin
主要是针对于代码压缩方面的优化,当然这是相对于Webpack.optimize.UglifyJsPlugin
而言,因为 Webpack
自带的 UglifyJsPlugin
只能同步压缩代码,而webpack-parallel-uglify-plugin
可以实现并行压缩代码的效果,这样一来就很好地利用了 CPU
,从而提高压缩速度。
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin')
new ParallelUglifyPlugin({
parallel: true, // 开启并行压缩 默认线程=cup-1
cache: path.resolve(__dirname, 'dist'),
uglifyOptions: {
output: {
comments: false
},
compress: {
drop_debugger: true,
drop_console: true
},
warnings: false
}
}),
hard-source-webpack-plugin
为模块提供中间缓存的作用,即在很大程度上会缩短第二次打包的时间。
const HardSourcePlugin = require('hard-source-webpack-plugin')
plugins: [
new HardSourcePlugin
]
happypack
在Webpack
压缩的过程中,很重要的一个过程就是babel
解析转化代码的过程,所以优化这个过程,在一定程度上也可以提高我们的打包速度。同样地,由于Webpack
整个打包地过程是同步进行的,而happypack
则可以实现多线程并行打包,它通常用于配合loader
一起使用,例如它和babel-loader
一起使用:
const HappyPack = require('happypack')
const os = require('os')
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length })
module: {
rules: [
{
test: /\.js$/,
loader: isProd ? 'happypack/loader?id=happybabel':'babel-loader' // 需要区分生产和开发环境
include: [resolve('src')],
exclude: /node_modules/,
}
]
},
plugins: isProd ? [
new HappyPack({
id: 'happyBabel',
loaders: [{
loader: 'babel-loader?cacheDirectory=true'
}],
threadPool: happyThreadPool,
verbose: true // 允许 HappyPack 输出日志
})
]:[]
四、其他优化
externals
对于一些文件我们可以预先放在 CDN
上,然后 index.html
中通过 script
标签引入,通过配置 externals
,我们仍然可以在代码中通过 import
导入。例如,拿 Jquery
举例:
在 index.html
中引入:
<script src="http://wjc.cdn.com/jquery.min.js"></script>
在 webpack
中配置 externals
:
{
externals: {
'jquery': 'jquery'
}
}
在项目中使用:
import $ from 'jquery'
总结
其实对于 webpack
的优化还有其他的途径,例如将第三方依赖分离出来直接放到 CDN
上,当然首先要保证这些依赖已经编译成 ES5
。又或者结合 DllPlugin
将第三方依赖(例如 Vue)之类的不会发生变化的单独打包成js
文件,然后在index.html
中通过script
标签引入等等。后续,时间充裕我会继续补上各种优化手段。