webpack優化,首屏渲染從9s到1s

1.生產環境關閉productionSourceMapcss sourceMap

眾所周知,SourceMap就是當頁面出現某些錯誤,能夠定位到具體的某一行代碼,SourceMap就是幫你建立這個映射關系的,方便代碼調試。在生產環境中我們完全沒必要開啟這個功能(誰在生產環境調試代碼?不會是你吧
如下配置:

const isProduction = process.env.NODE_ENV === 'production' 
// 判斷是否是生產環境 
module.exports = {     
  productionSourceMap: !isProduction, //關閉生產環境下的SourceMap映射文件 
  css: {         
    sourceMap: !isProduction, // css sourceMap 配置 
    loaderOptions: {             
    ...其它代碼         
   }     
  },     
  ...其它代碼 
}

此時再npm run build 打包,就會發現速度快了很多,體積瞬間只有幾兆了!

2.分析大文件,找出內鬼

安裝 npm install webpack-bundle-analyzer -D 插件,打包后會生產一個本地服務,清楚的展示打包文件的包含關系和大小。

vue.config.js 配置:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin  
module.exports = {     
   ...其它     
   configureWebpack: [         
   plugins: [             
      new BundleAnalyzerPlugin() // 分析打包大小使用默認配置 
   ]    
  },  
 ...其它 
}

自動彈出一個服務,清晰的展示打包后js的文件大小:

  1. element-ui和ant-design占了近1/4的大小:1.53MB

  2. exceljs也是個大東西有:1.3MB

  3. echarts.js文件也接近1MB

  4. moment.js也有700KB

打包后js文件一共就5MB,這五個哥們就占了4M左右。不分析好還,一分析嚇得夠嗆~
不要虛!找到刺了,一個一個來拔掉就好了。相信我拔掉的過程是很爽的。

一個一個解決,拔刺

把必須要用的第三方js通過cdn的方式引用
分析發現,elementui、echarts是必須使用的,打包又耗時且頁面加載也較慢得很。可以通過cdn直接引入,方便且速度快。
element-ui是我們項目用的主要框架,所以這個肯定是少不了,但是項目里面ant-design為什么會存在呢,原來是發現有個頁面使用了antd的進度條組件,因為elementui的進度條不太好看。但是沒想到這樣把整個antd都導進來了。
方案:

  1. 舍棄antd組件,自己去找一個類似的vue插件或者干脆自己實現一個。(這個方法短時間無法完成,且不想去動以前代碼,暫不考慮)

  2. 使用antd部分加載。只加載想要的進度條組件,可以減少文件體積(這個方法簡單粗暴,就是犧牲一些文件大小)。

我們使用方案2,根據antd官方的文檔配置部分組件的引入。

安裝 npm install babel-plugin-import -D

  1. main.js導入需要的組件 Step
import { Steps } from 'ant-design-vue'; 
Vue.component(Steps.name, Steps); 
Vue.component(Steps.Step.name, Steps.Step);
  1. babel.config.js 加上配置:
module.exports = {  
    presets: [  '@vue/cli-plugin-babel/preset'   ],   
    //以下是按需加載的配置++++ 
    plugins: [     
     [       
      "import",       
      {         
          libraryName: "ant-design-vue",        
          libraryDirectory: "es",         
          style: true       
      }     
     ]   
    ] 
}

此時再分析,antd已經小了很多。

2.使用cdn加載第三方js。

我們項目里面第三方js很多,有些打包下來會很大,而且加載速度較慢。我們把這些js分離出來,通過cdn的方式在html中的script標簽中直接使用,一方面減少打包體積,一方面提高了加載速度。

這里推薦一個免費的cdn: BootCDN。也可以使用自己購買的付費cdn服務,我們到網站搜索自己項目需要的js。例如:vue

[圖片上傳失敗...(image-152539-1650424840084)]

注意,一定要選擇自己項目對應的版本,否則會出現各種奇怪的問題

我的項目使用的是 "vue": "^2.6.12", (package.json)

[圖片上傳失敗...(image-df5b4-1650424840084)]
第一步:配置vue.config.js,讓webpack不打包這些js,而是通過script標簽加入。

const isProduction = process.env.NODE_ENV === 'production' // 判斷是否是生產環境
//正式環境不打包公共js
let externals = {}
//儲存cdn的文件
let cdn = {
    css: [
        'https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.0/theme-chalk/index.min.css' // element-ui css 樣式表
    ],
    js: []
}
//正式環境才需要
if (isProduction) {
    externals = { //排除打包的js
        vue: 'Vue',
        'element-ui': 'ELEMENT',
        echarts: 'echarts',
    }
    cdn.js = [
        'https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js', // vuejs
        'https://cdn.bootcdn.net/ajax/libs/element-ui/2.6.0/index.js', // element-ui js
        'https://cdn.bootcdn.net/ajax/libs/element-ui/2.6.0/locale/zh-CN.min.js',
        'https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.min.js',
    ]
}
module.exports = {
//...其它配置
configureWebpack: {
        //常用的公共js 排除掉,不打包 而是在index添加cdn,
        externals, 
        //...其它配置
    },
chainWebpack: config => {
        //...其它配置  
        // 注入cdn變量 (打包時會執行)
        config.plugin('html').tap(args => {
            args[0].cdn = cdn // 配置cdn給插件
            return args
        })
    }
//...其它配置     
}

第二步:html模板中加入定義好的cdn變量使用的代碼

<!DOCTYPE html>
<html lang="">

<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">
    <title>web</title>
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <!-- 引入樣式 -->
    <% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
       <link rel="stylesheet" href="<%=css%>" >
    <% } %>

    <!-- 引入JS -->
    <% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
       <script src="<%=js%>"></script>
    <% } %>
</head>
<body style="font-size:14px">
    <section id="app"></section>
</body>
</html>

可以發現cdn.js中,我把vue、echarts、element-ui這三個大頭加入了。在externals對象中左側是npm包的名稱,右側是在代碼中暴露的全局變量。注意element-ui對應的是 ELEMENT

沒有ant-design-vue是因為我們上面使用了部分加載的方式,如果使用cdn這種方式是加載全部的代碼,有點浪費。

沒有使用exclejs,是因為exceljs在我的業務代碼中不是直接引用的,而是一個叫table2excel間接依賴的。所以就算我通過上面的方法排除掉它,在打包的時候還是會通過table2excel的依賴找到它并打包。
那這種不可避免的情況,該如何優化,讓加載速度不受影響呢?

答案是通過懶加載的方式:

  • 1.script標簽中注釋掉 import Table2Excel from "table2excel.js";

  • 2.下載的方法中:download(){

1.script標簽中注釋掉 import Table2Excel from "table2excel.js";

2.下載的方法中:
download(){
    //使用import().then()方式
    import("table2excel.js").then((Table2Excel) => {
        new Table2Excel.default("#table").export('filename') //多了一層default 
    })
}

這樣在進入系統時,不會加載Table2Excelexceljs,當需要時才會去加載,第一次會慢一點,后面就不需要加載了,會變快。

  • 3 moment.js的優化

我們發現monentjs在項目中有使用來對時間格式化,但是使用頻率并不高,完全可以自己實現一個format方法,或者使用只有6kbday.js.

但這里我們暫不替換,把moment變得瘦小一些即可,刪除掉除中文以外的語言包
第一步:**vue.config.js**

...其它配置
 chainWebpack: config => {
     config.plugin('ignore')
        //忽略/moment/locale下的所有文件
     .use(new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/))
 }
...其它配置

第二步:main.js

import moment from 'moment' //手動引入所需要的語言包 
import 'moment/locale/zh-cn'; // 指定使用的語言 
moment.locale('zh-cn');` 

這次我們看看moment打包后多大:

[圖片上傳失敗...(image-238672-1650424840084)]

只有174kb了。不過,有一說一還是day.js香~
做完上面這些動作我們的js文件總大小:3.04MB ,其中包含 1.3MB的懶加載js,剩下的1.7MB左右的js基本上不會對頁面造成很大的卡頓。

[圖片上傳失敗...(image-a20f81-1650424840084)]

還有進步空間?
1.通過 compression-webpack-plugin 插件把代碼壓縮為gzip。但是!需要服務器支持
webpackvue.config.js配置如下:

//打包壓縮靜態文件插件
const CompressionPlugin = require("compression-webpack-plugin")

//...其它配置
module.exports = {
    //...其它配置
    chainWebpack: config => {
        //生產環境開啟js\css壓縮
        if (isProduction) {
            config.plugin('compressionPlugin').use(new CompressionPlugin({
                test: /\.(js)$/, // 匹配文件名
                threshold: 10240, // 對超過10k的數據壓縮
                minRatio: 0.8,
                deleteOriginalAssets: true // 刪除源文件
            }))
        }
    }
    //...其它配置
}

打包大小由3MB860KB,感覺起飛了~
[圖片上傳失敗...(image-e79200-1650424840084)]

服務器端配置這里就不詳細說明了可以谷百:nginx開啟靜態壓縮 找到答案。
最后貼上優化前后的無緩存下的首屏加載時間對比(chrome瀏覽器),絕對包真:
優化前項目網站首屏加載數據:9.17s

[圖片上傳失敗...(image-7b5f48-1650424840084)]

優化后項目網站首屏加載數據:1.24s

[圖片上傳失敗...(image-4b0505-1650424840084)]

這些都是在工作之余,自己抽時間去查閱各位大佬的帖子,雖然都是些耍爛了的技術,但是真的要在自己項目中實施還是需要一些時間和精力,大多數都是為了完成功能快速迭代而忽略掉了做程序原本的目的,就是要讓用戶有一個良好的使用體驗。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容