entry: { index: path.join(srcPath, 'index.js'), other: path.join(srcPath, 'other.js') }, output: { filename: '[name].[contentHash:8].js', // [name] 表示 chunk 的名称,即上面的 index 和 other path: distPath },
第二,配置 html 插件
plugins: [ // 生成 index.html new HtmlWebpackPlugin({ template: path.join(srcPath, 'index.html'), filename: 'index.html', // chunks 表示该页面要引用哪些 chunk (即上面的 index 和 other),默认全部引用 chunks: ['index'] // 只引用 index.js }), // 生成 other.html new HtmlWebpackPlugin({ template: path.join(srcPath, 'other.html'), filename: 'other.html', chunks: ['other'] // 只引用 other.js }),
抽离公共代码
公共模块
多个页面或者入口,如果引用了同一段代码,如上文的多页面例子中,index.js 和 other.js 都引用了 import './common.js' ,则 common.js 应该被作为公共模块打包。webpack v4 开始弃用了 commonChunkPlugin 改用 splitChunks ,可修改 build/webpack.prod.js 中的配置
optimization: { // 分割代码块 splitChunks: { // 缓存分组 cacheGroups: { // 公共的模块 common: { chunks: 'initial', minSize: 0, // 公共模块的大小限制 minChunks: 2 // 公共模块最少复用过几次 } } } },
重新运行 npm run build ,即可看到有 common 模块被单独打包出来,就是 common.js 的内容。
第三方模块
同理,如果我们的代码中引用了 jquery lodash 等,也希望将第三方模块单独打包,和自己开发的业务代码分开。这样每次重新上线时,第三方模块的代码就可以借助浏览器缓存,提高用户访问网页的效率。修改配置文件,增加下面的 vendor: {...} 配置。
optimization: { // 分割代码块 splitChunks: { // 缓存分组 cacheGroups: { // 第三方模块 vendor: { priority: 1, // 权限更高,优先抽离,重要!!! test: /node_modules/, chunks: 'initial', minSize: 0, // 大小限制 minChunks: 1 // 最少复用过几次 }, // 公共的模块 common: { chunks: 'initial', minSize: 0, // 公共模块的大小限制 minChunks: 2 // 公共模块最少复用过几次 } } } },
重启 npm run build ,即可看到 vendor 模块被打包出来,里面是 jquery 或者 lodash 等第三方模块的内容。
懒加载
webpack 支持使用 import(...) 语法进行资源懒加载。安装 npm i @babel/plugin-syntax-dynamic-import -D 然后将插件配置到 .babelrc 中。
新建 src/dynamic-data.js 用于测试,内容是 export default { message: 'this is dynamic' } 。然后在 src/index.js 中加入
setTimeout(() => { import('./dynamic-data.js').then(res => { console.log(res.default.message) // 注意这里的 default }) }, 1500)
重新运行 npm run dev 刷新页面,可以看到 1.5s 之后打印出 this is dynamic 。而且,dynamic-data.js 也是 1.5s 之后被加载进浏览器的 —— 懒加载,虽然文件名变了。
重新运行 npm run build 也可以看到 dynamic-data.js 的内容被打包一个单独的文件中。
常见性能优化
tree shaking
使用 import 引入,在 production 环境下,webpack 会自动触发 tree shaking ,去掉无用代码。但是使用 require 引入时,则不会触发 tree shaking。这是因为 require 是动态引入,无法在编译时判断哪些功能被使用。而 import 是静态引入,编译时即可判断依赖关系。
noParse
不去解析某些 lib 其内部的依赖,即确定这些 lib 没有其他依赖,提高解析速度。可配置到 build/wepback.common.js 中
module: { noParse: /jquery|lodash/, // 不解析 jquery 和 lodash 的内部依赖
ignorePlugin
以常用的 moment 为例。安装 npm i moment -d 并且 import moment from 'moment' 之后,monent 默认将所有语言的 js 都加载进来,使得打包文件过大。可以通过 ignorePlugin 插件忽略 locale 下的语言文件,不打包进来。
plugins: [ new webpack.IgnorePlugin(/\.\/locale/, /moment/), // 忽略 moment 下的 /locale 目录
这样,使用时可以手动引入中文包,并设置语言
import moment from 'moment' import 'moment/locale/zh-cn' // 手动引入中文语言包 moment.locale('zh-cn') const r = moment().endOf('day').fromNow() console.log(r)
happyPack
多进程打包,参考 https://www.npmjs.com/package/happypack 。注意,小项目使用反而会变慢。只有项目较大,打包出现明显瓶颈时,才考虑使用 happypack 。
常用插件和配置
ProvidePlugin
如要给所有的 js 模块直接使用 $ ,不用每次都 import $ from 'jquery' ,可做如下配置
plugins: [ new webpack.ProvidePlugin({ $: 'jquery' }),
externals
如果 jquery 已经在 html 中通过 cdn 引用了,无需再打包,可做如下配置
externals: { jquery: 'jQuery' },
alias
设置 alias 别名在实际开发中比较常用,尤其是项目较大,目录较多时。可做如下配置
resolve: { alias: { Utilities: path.join(srcPath, 'utilities') } },