升级优化Webpack4,使你的打包速度提升200%以上!
栏目: JavaScript · 发布时间: 5年前
内容简介:之前修改公司的运营系统,多年来积累下来的代码使得每次打包构建的时候时间异常漫长,非常难受,一气之下将项目的Webpack从2.x升级到了4.x,原来在Jenkins上一套需要6分钟的流程现在只需2分钟,顿时感到身心舒畅( ̄▽ ̄)/并且我顺便把项目划分成多入口项目,实现增量更新,这样就不用每次都打包这么多文件啦!先说一下我在升级中发现的可以优化的点,大家有什么建议和想法可以一并提出。
之前修改公司的运营系统,多年来积累下来的代码使得每次打包构建的时候时间异常漫长,非常难受,一气之下将项目的Webpack从2.x升级到了4.x,原来在Jenkins上一套需要6分钟的流程现在只需2分钟,顿时感到身心舒畅( ̄▽ ̄)/
并且我顺便把项目划分成多入口项目,实现增量更新,这样就不用每次都打包这么多文件啦!
ps:以下配置基于React,可以自行根据实际项目用到的框架和库修改
1. 配置中可优化的点
先说一下我在升级中发现的可以优化的点,大家有什么建议和想法可以一并提出。
1.1 优化第三方库
优化第三方库最简单粗暴并且及其有效的一个方式就是使用 webpac
k的 DllPlugin
。它可以将我们经常使用但是修改频率极低的第三方库与自己的代码完全分离开, 每次打包的时候会根据索引判断是否需要重新打包第三方库,大大提高了打包速度。用法我就不细说了,网上有很多教程,感兴趣的可以去了解下。
库的索引一般保存在一个 manifest.json
文件中。我们可以通过这个文件看到自己项目对第三方库的打包情况。
优化思路:
-
项目里安装的第三方库的需要评估必要性,如果很少使用到库的不要在
webpack
的vendor
入口指定打包进来。 -
同时可以升级某些第三方库,如
react v16
对比react v15
,加上react-dom
,体积上降低了30%,因此果断升级。 -
分析manifest.json文件后发现某些库体积特别大,例如使用很广泛的
moment.js
库。研究后发现webpack
把库下面所有的locale
文件打包了进来。这是一些支持多语言的文件。即我们可以通过ContextReplacementPlugin
插件来挑选我们需要的文件。
plugins: [ new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /zh-cn/), ] 复制代码
-
有时候通过依赖分析会发现项目里打包了两份第三方库,一份是
es module
版的,另一份则是umd
版的。如moment
通过import 'moment'导入的是es module
版的,locale
文件中却会用相对路径导入umd
版的。这时我们可以通过配置别名将库指向同一个版本。
resolve: { alias: { 'moment$': path.resolve('node_modules/moment/moment'), }, } 复制代码
-
有时候项目里并不需要某个库的全部功能,这时候可以考虑用更轻量的库来替代,或者使用定制阉割版(如Echarts, 官网上可定制),并且用
import()
语法和react-loadable
这个库将react组件包装成异步组件,在需要时才进行加载,这样webpack就会将异步组件抽取为异步加载的chunk,就不会多次加载。下面就说如何抽取。
1.2 抽取异步加载的chunk中的公共代码
在webpack4之前,我们使用 CommonsChunkPlugin
来抽取异步组件,但现在 CommonsChunkPlugin
已经被废弃了,取而代之的是 SplitChunksPlugin
使用方法有两种,一种是像Webpack3那样在 plugins
中配置,一种是在Webpack4中的 optimization
属性中的 splitChunks
配置
optimization: { splitChunks: { // 拆分代码规则(符合即单独拆分到一个chunk中) maxInitialRequests: 4, // 在初始化加载时,请求数量大于4 automaticNameDelimiter: '-', name: true, // 代码块的名字,设置为true则表示根据模块和缓存组秘钥自动生成, 实现固化 chunkId,保持缓存的能力 /* 缓存组,用于继续细分代码。 缓存组默认将node_modules中的模块拆分带一个叫做vendors的代码块, 将最少重复引用两次的模块放入default中。 或者自定义将符合规则的模块单独拆分进一个chunk中。*/ cacheGroups: { default: false, // 禁用默认规则 vendors: false, // 禁用默认规则 polyfill: { chunks: 'initial', test: 'polyfill', name: 'polyfill', }, vendor: { chunks: 'initial', test: 'vendor', name: 'vendor', }, // 对异步组件进行抽取 'async-vendor': { name: 'async-vendor', chunks: 'async', test: (module) => { // 缓存组的规则,表示符合条件的的放入当前缓存组 if (/[\\/]node_modules[\\/](echarts|zrender)/.test(module.context)) { return false; } return /[\\/]node_modules[\\/]/.test(module.context); }, }, 'async-biz': { name: 'async-biz', chunks: 'async', minChunks: 2, // 被引用次数大于2时进行拆分 }, // css文件单独打包进一个文件中 'styles': { name: 'styles', test: /\.css$/, chunks: 'async', enforce: true, }, }, }, }, 复制代码
当抽取异步加载组件时,我们需要在业务代码中使用下面的写法,webpack才能识别:
基于 react-loadable
库,简介:React Loadable 简介
import Loadable from 'react-loadable'; const loder1 = import(/* webpackChunkName: "chunkname2" */'path/to/module2') const Component = Loadable({ loader, loadingComponent, // loding时使用的组件 }) 复制代码
1.3 合理使用异步加载
若我们项目中的首屏也是使用异步加载的方法,并且用到了 async-vendor
里的组件,首屏加载时就会同时加载 async-vendor
并做缓存,这样之后的页面使用到了 async-vendor
里面的组件之后就无需再次加载新的代码。但是这样就会可能拖慢我们的的首屏速度。
解决办法一是拆分 async-vendor
的首屏部分;或是取消首屏页面的异步加载,将其打包到 main
中,这样就避免了加载 async-vendor
,大大减少了首屏体积。
1.4 分离出webpack runtime代码
webpack在客户端运行时会首先加载webpack相关的代码,例如require函数等,这部分代码会随着每次修改业务代码后发生变化,原因是这里面会包含chunk id等容易变化的信息。如果不抽取出来将会被打包在vendor当中,导致vendor每次都要被用户重新加载。抽离的配置写在 optimization
属性中的 runtimeChunk
配置中:
optimization: { runtimeChunk: { name: 'manifest', }, } 复制代码
1.5 webpack内部优化
HashedModuleIdsPlugin
和 ModuleConcatenationPlugin
默认情况下,webpack会为每个模块用数字做为ID,这样会导致同一个模块在添加删除其他模块后,ID会发生变化,不利于缓存。
为了解决这个问题,有两种选择: NamedModulesPlugin
和 HashedModuleIdsPlugin
,前者会用模块的文件路径作为模块名,后者会对路径进行md5处理。因为前者处理速度较快,而后者打包出来的文件体积较小,所以应该开发环境时选择前者,生产环境时选择后者。
ModuleConcatenationPlugin
主要是作用域提升,将所有模块放在同一个作用域当中,一方面能提高运行速度,另一方面也能降低文件体积。前提是你的代码是用es模块写的。
在 webpack4 中,只需要optimization的配置项中设置 moduleIds
为 hashed
或者 named
, 设置 mode
为 production
即可。
mode:'production', optimization : { moduleIds: 'hashed', } 复制代码
1.6 babel-polyfill优化
目前本人项目里用的方法是命名一个来源于babel-polyfill的polyfill的文件,但是注释掉了大部分的import,仅保留项目的基本需求,并在在项目入口文件中引入。
// webpack 中配置 entry: { polyfill: path.join(process.cwd(), 'path/to/your/polyfill'), }, 复制代码
参考下别人一些对polyfill优化的的优秀文章:
以上所述就是小编给大家介绍的《升级优化Webpack4,使你的打包速度提升200%以上!》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 提升效率——自动打包上传蒲公英
- 复习webpack4之提升Webpack打包速度的方法
- 【前端打包部署】谈一谈我在SPA项目打包=>部署的处理
- Maven多模块项目打包前的一些注意事项(打包失败)
- tar打包如何不打包某一个文件夹(排除某些文件夹)
- iOS新手用swift写一个macos打包工具 一键打包到指定位置
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
CSS 压缩/解压工具
在线压缩/解压 CSS 代码
HEX HSV 转换工具
HEX HSV 互换工具