一、前言
閱讀完該文章大概需要2.5min。
讀完該篇文章你能學到
vue-cli默認做了哪些優(yōu)化?- 在cli的基礎上我們又能做哪些優(yōu)化?
vue.config.js中如何配置一些常用的plugin和loader
vue-cli的出現(xiàn),讓我們省掉了配置webpack的時間。也就是說,一個不懂webpack的人,也能直接上手開發(fā)。比如file-loader,url-loader會提前為我們配置好。性能方面,
vue-cli也默認盡可能多的幫我們做了優(yōu)化,比如cache-loader會在項目中預先做了配置。我們可以在控制臺輸入vue inspect > webpack.config.js,即可在webpack.config.js文件中查看cli預先定義好的基礎配置。我們今天就在vue-cli搭建好的項目基礎上聊一聊可優(yōu)化的點。
二、項目源碼
本文所用到的項目源碼
三、量化指標
1. build時間
speed-measure-webpack-plugin插件可以在build的時候看到webpack的loader和plugin所用的時間,配置非常簡單。如下:
// vue.config.js
module.exports = {
chainWebpack: config => {
config.plugin('speed')
.use(SpeedMeasureWebpackPlugin)
}
}
順便看一下效果
屏幕快照 2021-07-31 下午4.57.58.png
2.build后包的大小以及包的多少
webpack-bundle-analyzer插件可以幫我們可視化的展示build時的每個包的大小以及依賴。vue-cli也幫我們做了默認的配置,我只需要在build的后面加一個參數(shù)--report即可。
// package.json
{
"name": "dll-vue",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"report": "vue-cli-service build --report",
}
}
npm run report之后,dist目錄下就多了一個report.html文件,我們用瀏覽器打開這個文件看一下,右上角那個小藍塊是我們的vue代碼,接下來我們主要來優(yōu)化小藍塊之外的代碼
四、開始優(yōu)化
1. include/exclude
我們通常配置include和exclude,來達到使loader僅僅處理匹配到的文件,像這樣
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.js[x]?$/,
use: ['babel-loader'],
include: [path.resolve(__dirname, 'src')]
}
]
},
}
而vue的transpileDependencies屬性默認情況下 babel-loader 會忽略所有 node_modules 中的文件,其實已經(jīng)滿足了我們大部分需求。
2. resolve
resolve: 配置
webpack如何尋找模塊所對應的文件,比如import * from 'xxx',xxx模塊應該優(yōu)先從node_modules中找,我們通過vue inspect > webpack.config.js導出的文件中在modules字段中可以清晰的看到已經(jīng)將node_modules設置為優(yōu)先尋找的模塊
resolve: {
// ...
modules: [
'node_modules',
...
]
// ...
}
3. happypack-plugin/thread-loader
一般來說,我們可以通過happack-plugin或者thread-loader開啟多線程打包。vue-cli的
parallel屬性的含義是:是否為 Babel 或 TypeScript 使用thread-loader,默認值為cpu的內核數(shù),也就是說如果你系統(tǒng)是3核cpu,則build的時候,會自動在babel-loader和ts-loader執(zhí)行時候開啟3個線程。如果你想試著自己的配置一下,可以像下面這樣。(不過我試著自己配置了之后,似乎沒什么效果。也許是我配置的不對,歡迎大家來指正)
config.module.rule('vue')
.use('thread-loader')
.loader('thread-loader')
.before('vue-loader')
4. noParse
如果一些第三方模塊沒有AMD/CommonJS規(guī)范版本,可以使用
noParse來標識這個模塊,這樣Webpack會引入這些模塊,但是不進行轉化和解析,從而提升Webpack的構建性能 ,例如:jquery、lodash,vue.config.js中可以這樣配置:
// vue.config.js
module.exports = {
//...
configureWebpack:{
module: {
noParse: /^(lodash|moment)$/
}
}
//...
}
5. ContextReplacementPlugin
一些依賴,我們也許只是用到了一部分,沒必要全部解析,比如moment中的語言包,我們一般只用中文包就夠了,所以可以這樣配置:
// vue.config.js
module.exports = {
//...
configureWebpack:{
plugins: [
new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn/)
]
}
//...
}
我們通過一張圖片來體驗一下, 左邊為去掉語言包的效果
6. externals
一般來說像jQuery這些第三方的包,我們采用CDN的方式來引入,像這樣
<-- public/index.html -->
<script src="https://code.jquery.com/jquery-3.6.0.min.> js"></script>
在使用的時候,我們希望通過import的方式引入,像這樣
// App.vue\
import $ from 'jquery'
$('.today').text = 'today'
這就造成一個問題,build的時候就會將jquery再打包一次 我們可以配置
externals來達到build時忽略掉指定的依賴
// vue.config.js
module.exports = {
//...
configureWebpack:{
config.externals = {
jquery: 'jQuery'
}
}
//...
}
7. uglifyjs-webpack-plugin
在build的時候可以壓縮代碼的大小,有幾個常用的配置可以單獨提一下,比如去掉console.log,比如進行多進程壓縮??梢赃@樣:
// vue.config.js
module.exports = {
//...
configureWebpack:{
config.optimization.minimizer = [
new UglifyJsPlugin({
uglifyOptions: {
compress: {
drop_console: true, // 去掉console
}
parallel: true, //默認并發(fā)運行數(shù):os.cpus().length - 1
}
})
]
}
//...
}
8. compression-webpack-plugin
我們可以將代碼壓縮為.gz文件,瀏覽器也是可以識別的??梢赃@樣配置
//vue.config.js
module.exports = {
//...
configureWebpack:{
plugins: [
new CompressionWebpackPlugin()
]
}
//...
}
9. DllPlugin 和 DllReferencePlugin
- 對于變化幾率很小的一些第三方包,其實沒必要build的時候都要打包一次, 可以把這些第三方包單獨抽離出來,提前打包好。
- webpack本身是要體現(xiàn)出模塊間的依賴關系,當我們將一些包抽離出來后,維護之前的依賴關系就需要
manifest.json這個文件。讓我們從接下來的實戰(zhàn)中來學習它。
<1> 新建一個配置文件webpack.dll.config.js
// webpack.dll.config.js
module.exports = {
mode: 'production',
entry: {
vue_vendor: ['vue/dist/vue.runtime.esm.js', 'vuex', 'vue-router', 'element-ui'],
other_vendor: ['lodash', 'moment']
},
output: {
filename: '[name].dll.js',
path: path.resolve(__dirname, './public/dll'),
library: '[name]_[hash]'
},\
plugins: [
new webpack.DllPlugin({
name: '[name]_[hash]',
path: path.resolve(__dirname, '[name].manifest.json')
})
]
}
<2> 為了方便,我們將讀取該配置文件的命令寫到package.json文件中,像這樣。(需要安裝webpack-cli)
// package.json
{
.....
"scripts": {
.....
"dll": "webpack --config ./webpack.dll.config.js"
}
.....
}
<3> 執(zhí)行
npm run dll后可以看到生成兩個manifest文件,像這樣
<4> 修改vue.config.js,引入依賴文件,并自動將dll下的文件插入到index.html中(這里我們引入一個插件
add-asset-html-webpack-plugin)
module.exports = {
chainWebpack: config => {
// 多個manifest.json文件就需要寫多次
config.plugin('vendorDll1')
.use(webpack.DllReferencePlugin, [
{
context: __dirname,
manifest: require('./public/manifest/other_vendor.manifest.json')
}
])
config.plugin('vendorDll2')
.use(webpack.DllReferencePlugin, [
{
context: __dirname,
manifest: require('./public/manifest/vue_vendor.manifest.json')
}
])
// 將dll下的文件自動插入到index.html中
config.plugin('asset')
.use(AddAssetHtmlWebpackPlugin, [
[
{
filepath: path.resolve(__dirname, 'public/dll/vue_vendor.dll.js'),
outputPath: 'dll',
publicPath: '/dll'
},
{
filepath: path.resolve(__dirname, 'public/dll/other_vendor.dll.js'),
outputPath: 'dll',
publicPath: '/dll'
}
]
])
}
}
10. optimization.splitChunks
抽離公共代碼,通過配置splitChunks可抽離公共的代碼,防止重復,我沒有在自己的項目中用,
//vue.config.js
module.exports = {
//...
chainWebpack: config => {
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {}
})
}
//...
}
五、效果展示
六、補充幾個不需要配置的優(yōu)化點
1. extensions
當我們導入模塊時,假如沒有指定后綴,期望優(yōu)先匹配的文件格式,我們直接看vue-cli默認的配置
extensions: ['.mjs', '.js', '.jsx', '.vue', '.json', '.wasm']
2. tree-shaking
我們通過import方式引入,webpack會自動移除掉沒有用到的模塊代碼
3. Scope hosting
作用域提升:比如
let a = 1
let b = 2
let c = a + b
// webpack自動優(yōu)化為
c = 3
4. 路由懶加載
通過() => import('xxx')方式引入,可達到路由懶加載的效果
六、總結
該文章為最近優(yōu)化團隊項目的webpack打包速度,做的總結。
如果有不對的地方歡迎大家在討論區(qū)糾正
歡迎關注公眾號:
前端小卡如果覺得有用,歡迎點個贊啦