vue-cli 項目可以做的優化


公司的一個管理后台項目是基於 vue-cli3 搭建的,這兩天我將它升級到了 vue-cli4,順手也做了一些優化,主要是從 webpack 方面入手,優化一下生產環境的代碼。

這里簡單提一下怎么升級腳手架版本的,首先將你電腦中的腳手架版本升級到 4,直接重新安裝就好,然后在你的項目中執行 vue upgrade 這個命令,根據提示一步一步地去升級即可。這里就不多描述細節了,網上能找到很多文章。

接下來主要聊聊 vue-cli 項目中可以配置的一些優化方案,下面提到的方案也並不是我都用上的,還是需要根據真實項目來決定用或不用。

刪除 console.log

在開發時,我還是喜歡用 console.log 來調試,但是部署到線上時,最好還是刪掉這部分代碼。別看代碼不多,當項目到了一定規模時,還是占用不少體積的。腳手架內部使用的是 TerserWebpackPlugin 這個插件來壓縮js代碼的,它自帶一個刪除 console.log 的功能,所以直接配置即可,在 configureWebpack 中配置,如下:

{
    // ...
    
    configureWebpack: config => {
        // 生產環境下生效
        if (process.env.NODE_ENV === 'production') {
          // 配置刪除 console.log
          config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true
        }
    }

    // ...
}

 

啟用 gzip 壓縮

使用 gzip 壓縮代碼,效果顯著。gzip 是需要服務端配置的,當開啟時會壓縮我們的線上代碼,但是如果我們前端已經使用 gzip 壓縮過,那么服務端就會直接使用已經壓縮好的代碼,就不需要花時間再去壓縮了。前端啟用 gzip 壓縮,使用到的插件是 

CompressionWebpackPlugin ,在 configureWebpack 中配置如下:
// 需要先安裝這個插件
// npm install compression-webpack-plugin

const CompressionWebpackPlugin = require('compression-webpack-plugin')

{
  // ...

  configureWebpack: config => {
    // 生產環境下生效
    if (process.env.NODE_ENV === 'production') {
      // 配置 gzip 壓縮
      config.plugins.push(
        new CompressionWebpackPlugin({
          test: /\.js$|\.html$|\.css$/,
          threshold: 4096 // 超過4kb壓縮
        })
      )
    }
  }

  // ...
}

 

當配置好 gzip 后,再去打包,會發現打包文件中有 .gz 結尾的文件,說明配置 gzip 壓縮成功了:

 

當然你可能還需要跟后端溝通一下,得讓服務端開啟這個功能。

 

代碼分割

對於 vue 項目,如果你留心過打包文件,會發現一個叫 chunk-vendors 的 js 文件,這個文件包含了業務代碼和一些引入的第三方庫代碼,所以一般體積比較大,瀏覽器加載時也耗時更多。

 

其實我們可以將這部分代碼做一個分割,分成多個文件,這樣瀏覽器加載時會並行加載,而且對於不變的代碼,會直接從緩存中讀取,速度得到提升。

webpack 提供了一個配置可以實現這樣的功能,從 webpack4 開始,可以在 optimization.splitChunks 中配置代碼分割功能,可以參考文檔 splitChunksPlugin 。直接看文檔可能有些懵,建議多搜些此類文章看看,我這里直接給出在 vue.config.js 中配置 splitChunks 的做法,我是在 chainWebpack 中配置的:

{
  // ...

  chainWebpack: config => {
    config
      .when(process.env.NODE_ENV === 'production', // 配置生產環境生效
        config => {
          config.optimization.splitChunks({
            chunks: 'all', // 將對什么類型的代碼進行分割,三種值:all: 全部 | async: 異步,按需加載的代碼 | initial: 入口代碼塊
            cacheGroups: { // 緩存組
              // 定義 libs 緩存組,分割從 node_modules 中引入的代碼
              libs: {
                name: 'chunk-libs', // 分割成的文件名
                test: /[\\/]node_modules[\\/]/, // 匹配 node_modules 中模塊
                priority: 10, // 優先級,當模塊同時命中多個緩存組的規則時,分配到優先級高的緩存組
                chunks: 'initial' // 這里覆蓋上面的 chunks: 'all',僅打包最初依賴的第三方庫
              },
              // 項目使用 iview 組件開發的,定義 iviewUI 緩存組,用於分割 iview 代碼
              iviewUI: {
                name: 'chunk-iviewUI',
                priority: 20, // 優先級 20,命中 iview 代碼時,優先分割到此組里
                test: /[\\/]node_modules[\\/]_?iview(.*)/ // 匹配 iview 代碼
              }
            }
          })
        }
      )
  }

  // ...
}

 

目前我只做了簡單的分割,對我的項目而言已經足夠了,splitChunks 的配置項有很多,建議多看看此方面的資料。打包后可以看到代碼已被分割:

 

 

配置 CDN

老實說,我不用這個功能的,線上使用 cdn 總讓我有一種不安全感,除非公司有自己的 cdn 庫,不過這確實也是一種優化方案,效果也還不錯。它的配置也很簡單,在 externals 中配置,例子:

{
  // ...

  configureWebpack: config => {
    if (process.env.NODE_ENV === 'production') {
      // 配置 cdn,這里將 vue,vue-router 和 axios 三個包配置成 cdn 引入
      // 其中 Vue,VueRouter 等名稱是該庫暴露在全局中的變量名
      config.externals = {
        vue: 'Vue',
        'vue-router': 'VueRouter',
        axios: 'axios'
      }
    }
  }

  // ...
}

然后在 public/index.html 模板文件中引入 cdn 地址:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
    <title></title>
    <!-- 引入 cdn 地址 -->
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.5.10/vue.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.0.1/vue-router.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.18.0/axios.min.js"></script>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

我這里使用的是 bootcdn 的地址,需要注意版本問題。也可以借助 HtmlWebpackPlugin 插件來方便插入 cdn 的引入。

使用 cdn 引入的方式雖然能極大改善網頁加載速度,但我還是不會用這個功能,項目還不需要非得這樣的優化,也怕 cdn 不穩定。覺得需要的還是可以上的。

 

圖片壓縮

圖片壓縮會影響圖片質量,這個根據個人需求來選擇。管理后台項目一般圖片不多,所以我自己沒有用上。試驗一下也未嘗不可,需要安裝 image-webpack-loader ,配置如下:

{
  // ...

  chainWebpack:config => {
    // 配置圖片壓縮
    config.module
      .rule('images')
      .use('image-webpack-loader')
      .loader('image-webpack-loader')
      .options({
        bypassOnDebug: true
      })
      .end()
  }

  // ...
}

可以看一下效果,配置前的某圖片:

配置圖片壓縮后:

效果還是顯著的,對圖片質量要求不高的可以配置上。

 

IgnorePlugin

webpack 中的 IgnorePlugin 插件,可以在打包第三方包時忽略一些文件內容,有效減小打包文件體積。一個典型的案例就是忽略 moment 插件的語言包,moment 自帶有很多語言包,即使你不用這些包,也會被一起打包了,這時候就可以使用 ignorePlugin 來忽略打包這部分文件,配置插件:

{
  // ...

  plugins:[
    new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/) // 忽略打包語言包
  ]

  // ...
}

在使用時,只需要引入自己需要的那個語言包即可:

import moment from 'moment'
// 引入中文
import 'moment/locale/zh-cn'
// 設置中文
moment.locale('zh-cn');
let momentStr = moment().subtract(10, 'days').calendar();

這里只是例舉 moment 這個例子,關於時間格式化,我還是喜歡自己去封裝,或者可以使用 dayjs 這個庫,更輕量化。

 

DllPlugin

這個適用於開發環境,每次構建都需要打包引入的第三方模塊,如果不打包這些模塊,那么構建速度將大大提升,這正是 DllPlugin 要做到的事。

說的明白點就是在構建項目之前,先把一些第三方包打包好,然后項目構建時直接引用這些打包好的第三方包,提升項目構建速度。

 

需要使用到兩個 webpack 內置的插件,分別是 DllPlugin 和 DllReferencePlugin。使用 DllPlugin 插件打包出 dll 文件,使用 DllReferencePlugin 插件使用 dll 文件。

 

我這里以打包 lodash 這個第三方模塊為例。首先要編寫一個 webpack 配置文件用以打包 lodash 模塊:

// webpack.dll.js

const webpack = require('webpack')
const path = require('path')
module.exports = {
    mode:'development',
    entry:{
        lodash:['lodash']
    },
    output:{
        // 輸出的動態鏈接庫的文件名稱,[name] 代表當前動態鏈接庫的名稱
        // 在這里 name 指的就是 lodash
        filename:'[name].dll.js',
        // 輸出的文件放到這個目錄下
        path:path.join(__dirname,'public'),
        // 存放動態鏈接庫的全局變量名稱。這里就是 _dll_lodash
        library:'_dll_[name]'
    },
    plugins:[
        new webpack.DllPlugin({
            // 該字段的值需要和 output.library 中保持一致
            // 該字段的值也就是輸出的 manifest.json 文件中的 name 字段的值
            name:'_dll_[name]',
            // 描述動態鏈接庫的 manifest.json 文件輸出時的文件名稱
            path:path.join(__dirname,'public/[name].manifest.json')
        })
    ]
}

然后可以在 package.json 的 scripts 中寫入一個命令:

scripts:{
    // ...
    "dll": "webpack --config webpack.dll.js"
}

此時執行 npm run dll 即可打包出 lodash 的 dll 文件。

 

接下來還有兩個重要步驟,一個是要在模板文件中手動引入剛打包出來的文件:

<body>
    <script src="../public//lodash.dll.js"></script>
</body>

在 vue.config.js 中使用 DllReferencePlugin 插件來引用映射文件:

{
  // ...

  configureWebpack: config => {
    if (process.env.NODE_ENV === 'development') {
      config.plugins.push(new webpack.DllReferencePlugin({
        manifest: require('./public/vendor/vendor.manifest.json')
      }))
    }
  }

  // ...
}

這樣一套配置下來后,項目構建時就不會每次都打包 lodash 這個包了。

 

結語

優化方案絕不止我上面提到的幾種,比如路由懶加載也算是一種優化,vue 項目中建議都用上路由懶加載,再比如考慮給 babel 加上緩存優化,甚至添加 mode: production 都能達到優化的目的,webpack 在生產模式下會自動開啟一些優化(Tree Shaking,Scope Histing 等),當然 vue-cli 項目里不需要我們手動添加模式。個人覺得優化方案選擇合適的就好,沒必要全上,可以把更多的心思花在業務代碼的優化上。

有錯處之處還望指出,謝謝。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM