提高首屏頁面加載速度,解決vue-cli打包后單個文件過大的問題


本教程是針對vue-cli3以上的版本,其實原理都大同小異,這個demo為vue-cli直接創建的項目,並在main.js中引入了echartelement-uilodash

首先看demo打包后生成的文件大小,這個demo里面什么業務都沒寫、僅僅引入了幾個包,chunk-vendors.js就達到了1.6M之多,如果是寫入了龐大的業務后沒做任何優化處理,那么這個文件可能會達到10M之多,這發生在我真實的項目經歷中

借助webpack-bundle-analyzer幫助分析

首先安裝webpack-bundle-analyzer

yarn add webpack-bundle-analyzer -D

然后在項目根目錄創建vue.config.js,然后在文件中寫入以下代碼

const WebpackBundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

module.exports = {
    configureWebpack: {
        plugins: [new WebpackBundleAnalyzerPlugin()]
    }
}

然后執行yarn build 在瀏覽器會自動打開我們的使用包分析文件,大致如下圖的樣子

我們可以看到生成的最大文件為chunk-vendors.js,這個文件主要又由echartselement-uilodashzrender組成,其中echartselement-uilodash為我們項目開發時必要引入的文件,所以我們如果把這寫文件分離出來那么文件自然就會小了很多

如何分離這些文件

我們可以借助wepack配置項里面的externals來達到目的,在vue.config.js里面加入如下代碼

module.exports = {

    // ... other code
    
    configureWebpack: {
    
    // ... other code
    
        externals: {
            "lodash": '_',
            "vue": 'Vue',
            "echarts": 'echarts',
            "element-ui": 'ELEMENT',
        },
        
        // ... other code
        
    }
    
    // ... other code
    
}

externals 配置選項提供了「從輸出的 bundle 中排除依賴」的方法。我們可以通過script標簽引入這些資源,具體關於externals的介紹請點擊這里
然后我們再對應的public -> index.html文件加入以下代碼,其中BASE_URL指的是public目錄,你需要從官網下載對應的資源放在對應的目錄下

<!DOCTYPE html>
<html lang="en">
  <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>optimize_vue</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but optimize_vue doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <script src="<%= BASE_URL %>js/pace.min.js"></script>
    <script src="<%= BASE_URL + (process.env.NODE_ENV === 'development' ? 'js/vue-2.6.0.js' : 'js/vue-2.6.0.min.js') %>"></script>
    <script src="<%= BASE_URL %>js/element-ui-2.11.1.js"></script>
    <script src="<%= BASE_URL %>js/lodash.min.js"></script>
    <script src="<%= BASE_URL %>js/echarts.min-4.4.0.js"></script>
  </body>
</html>

然后我們再看一下效果, lodash、echarts、elementui已經成功從webpack bundle分離出去了,打包后的chunk-vendors.js也只有24kb的大小

使用路由懶加載

路由懶加載會只加載當前頁面需要的資源,代碼如下

const Foo = () => Promise.resolve({ /* 組件定義對象 */ })
// or
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')

注意如果使用import方式的引入需要安裝@babel/plugin-syntax-dynamic-import,然后在babel.config.js中加入下面代碼即可

module.exports = {
    
  // ... other code
  
  "plugins": ["@babel/plugin-syntax-dynamic-import"]
  
  // ... other code
  
}

關於process.env.NODE_ENV

相信大家在開發的時候一定會有跟多個開發環境,比如development/feature/sandbox/production,因為這玩意我真是吃了大虧,剛開始沒看文檔, 直接在執行package.json的script命令的時候通過cross-env NODE_ENV=xxx 來修改環境變量,導致無法使用vue-cli工具為我們提供的代碼優化功能

注意: process.env_NODE_ENV的值只能為developmentproduction,不要修改為其他值,不然可能會出現其他問題,如果你真的想在不同的環境使用不同的接口地址或者、其他的內容我們可以用vue-cli為我們提供的--mode達到目的,比如

"scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "build:sanbox": "vue-cli-service build --mode sanbox",
    "build:feature": "vue-cli-service build --mode feature",
    "lint": "vue-cli-service lint",
    "precommit": "yarn lint"
}

這里vue-cli會讀取項目根目錄下的.env/.env./.env..local相關文件***指的是--mode的值,--mode會修改process.env.NODE_ENV的值,我們需要再對應的env里面把NODE_ENV改寫回來,比如一個.env.sanbox環境代碼如下

NODE_ENV=production
VUE_APP_ENV=sanbox

當我們執行yarn build:sanbox的時候就會加載這個文件,我們可以通過process.env.VUE_APP_ENV來訪問對應設置的值,注意只有VIE_APP_前綴的環境變量才會被webpack.DefinePlugin靜態嵌入到客戶端側的包中。

比如我們需要不同的構建命令構建不同的的publicPath的時候我們可以這樣做

const map = {
    production: '/',
    feature: '/feature',
    sanbox: '/sanbox',
    development: '/development',
}
const env = process.env.VUE_APP_ENV
const publicPath =  map[env]
const PATH = require('path')
const WebpackBundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

module.exports = {
    publicPath,
    configureWebpack: {
        externals: {
            "lodash": '_',
            "qiniu": 'qiniu',
            "vue": 'Vue',
            "echarts": 'echarts',
            "element-ui": 'ELEMENT',
        },
        resolve: {
            extensions: ['.js', '.vue', '.json', '.ts', '.tsx'],
            alias: {
                '$root': PATH.resolve(__dirname)
            }
        },
        plugins: [new WebpackBundleAnalyzerPlugin()]
    }
}

到這里就所有功能大功告成了,可以美滋滋的去喝一杯咖啡了。


免責聲明!

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



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