<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【Vite】1790- Vite打包性能優(yōu)化以及填坑

          共 13749字,需瀏覽 28分鐘

           ·

          2023-08-31 18:17

          a225e418c9c275b7408a00c75dfee94b.webp

          前言

          最近在使用 Vite4.0 構(gòu)建一個(gè)中型前端項(xiàng)目的過程中,遇到了一些坑,也做了一些項(xiàng)目在構(gòu)建生產(chǎn)環(huán)境時(shí)的優(yōu)化,在這里做一個(gè)記錄,以便后期查閱。(完整配置在后面)

          項(xiàng)目優(yōu)化前

          4eab1221bb8fec613a7ce46683732d3f.webpimage.png

          上面是dist文件夾的截圖,里面的內(nèi)容已經(jīng)有30mb了,是時(shí)候該做點(diǎn)什么了。

          分析

          想要實(shí)現(xiàn)優(yōu)化,首先我得先知道,是什么占了這么大的空間。是圖片?是庫?還是其他靜態(tài)資源?

          1. 將文件分門別類,js,css這些資源目錄分別打包到對(duì)應(yīng)的文件夾下

                        
                        js
            復(fù)制代碼build: {
                rollupOptions: {
                  output: {
                    chunkFileNames'js/[name]-[hash].js'// 引入文件名的名稱
                    entryFileNames'js/[name]-[hash].js'// 包的入口文件名稱
                    assetFileNames'[ext]/[name]-[hash].[ext]'// 資源文件像 字體,圖片等
                  }
                }
            }
          2. 查看項(xiàng)目的依賴,找出大塊頭

          rollup-plugin-visualizer是一個(gè)打包體積分析插件,對(duì)應(yīng)webpack中的webpack-bundle-analyzer。配置好后運(yùn)行構(gòu)建命令會(huì)生成一個(gè)stats.html

                
                bash
          復(fù)制代碼npm i rollup-plugin-visualizer -D
          js
          復(fù)制代碼import { visualizer } from 'rollup-plugin-visualizer'
          js
          復(fù)制代碼plugins: [
              visualizer({open: true})
          ]
          arduino
          復(fù)制代碼npm run build // 打包結(jié)束后會(huì)出現(xiàn)下圖
          73ad33213367e2389e2c5bbc094890b7.webpimage.png

          從體積能看到,這里已經(jīng)達(dá)到了7MB大小了,是時(shí)候該做點(diǎn)什么了。

          優(yōu)化

          拆分包

          這里有一個(gè)自己的個(gè)人見解:如果不同模塊使用的插件基本相同那就盡可能打包在同一個(gè)文件中,減少http請(qǐng)求,如果不同模塊使用不同插件明顯,那就分成不同模塊打包。這是一個(gè)矛盾體。這里使用的是最小化拆分包。如果是前者可以直接選擇返回'vendor'。

                
                scss
          復(fù)制代碼rollupOptions: {
          output: {
          manualChunks(id) {
          if (id.includes("node_modules")) {
          // 讓每個(gè)插件都打包成獨(dú)立的文件
          return id .toString() .split("node_modules/")[1] .split("/")[0] .toString();
          }
          }
          }
          }

          去除debugger

                
                bash
          復(fù)制代碼npm i terser -D
          js
          復(fù)制代碼terserOptions: {
            compress: {
              drop_console: true,
              drop_debugger: true
            }
          }

          CDN 加速

          內(nèi)容分發(fā)網(wǎng)絡(luò)(Content Delivery Network,簡稱 CDN)就是讓用戶從最近的服務(wù)器請(qǐng)求資源,提升網(wǎng)絡(luò)請(qǐng)求的響應(yīng)速度。同時(shí)減少應(yīng)用打包出來的包體積,利用瀏覽器緩存,不會(huì)變動(dòng)的文件長期緩存。(不建議使用第三方cdn,這里做學(xué)習(xí)討論使用)

                
                bash
          復(fù)制代碼npm i rollup-plugin-external-globals -D
          npm i vite-plugin-html -D
          html
          復(fù)制代碼<head>
              <%- vuescript %>
          </head>
          css
          復(fù)制代碼import { createHtmlPlugin } from 'vite-plugin-html'

          rollupOptions: {
            // 告訴打包工具 在external配置的 都是外部依賴項(xiàng)  不需要打包
            external: ['vue'],
            plugins: [
              externalGlobals({
                // "在項(xiàng)目中引入的變量名稱""CDN包導(dǎo)出的名稱,一般在CDN包中都是可見的"
                vue: 'Vue'
              })
            ]
          }

          plugins: [
              createHtmlPlugin({
                minify: true,
                inject: {
                  data: {
                    vuescript: '<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>'
                  }
                }
              })
          ]
          2d05ca1ed954d56ac4c6645a32ddedcb.webpimage.png

          按需導(dǎo)入

          仔細(xì)看上面那張圖右下部分的模塊,不知道你會(huì)不會(huì)感覺到奇怪,明明是同一個(gè)包,為什么既出現(xiàn)了lodash又出現(xiàn)了lodash-es。其實(shí)lodash-es 是 lodash 的 es modules 版本 ,是著具備 ES6 模塊化的版本,體積小,而lodash是common.js版本。lodash最大的缺陷就是無法按需導(dǎo)入。

                
                js
          復(fù)制代碼import _ from 'lodash-es'// 你將會(huì)把整個(gè)lodash的庫引入到項(xiàng)目
          import { cloneDeep } from 'lodash-es'// 你將會(huì)把引入cloneDeep引入到項(xiàng)目

          項(xiàng)目中用到lodash的地方也不多,經(jīng)過手動(dòng)修改一下,看現(xiàn)在已經(jīng)看不到lodash的庫了。

          31aaa257824c28b510b5aa27f3228bad.webpimage.png

          文件壓縮

                
                復(fù)制代碼npm install vite-plugin-compression -D
          js
          復(fù)制代碼// build.rollupOptions.plugins[]
          viteCompression({
            verbose: true, // 是否在控制臺(tái)中輸出壓縮結(jié)果
            disablefalse,
            threshold: 10240, // 如果體積大于閾值,將被壓縮,單位為b,體積過小時(shí)請(qǐng)不要壓縮,以免適得其反
            algorithm: 'gzip', // 壓縮算法,可選['gzip'' brotliccompress ''deflate ''deflateRaw']
            ext: '.gz',
            deleteOriginFile: true // 源文件壓縮后是否刪除(我為了看壓縮后的效果,先選擇了true)
          })

          當(dāng)請(qǐng)求靜態(tài)資源時(shí),服務(wù)端發(fā)現(xiàn)請(qǐng)求資源為gzip的格式時(shí),應(yīng)該設(shè)置響應(yīng)頭 content-encoding: gzip 。因?yàn)闉g覽器解壓也需要時(shí)間,所以代碼體積不是很大的話不建議使用 gzip 壓縮。

          圖片壓縮

                
                bash
          復(fù)制代碼yarn add vite-plugin-imagemin -D

          or

                
                bash
          復(fù)制代碼npm i vite-plugin-imagemin -D
          js
          復(fù)制代碼import viteImagemin from 'vite-plugin-imagemin'

          plugin: [
              viteImagemin({
                gifsicle: {
                  optimizationLevel: 7,
                  interlaced: false
                },
                optipng: {
                  optimizationLevel: 7
                },
                mozjpeg: {
                  quality: 20
                },
                pngquant: {
                  quality: [0.8, 0.9],
                  speed: 4
                },
                svgo: {
                  plugins: [
                    {
                      name: 'removeViewBox'
                    },
                    {
                      name: 'removeEmptyAttrs',
                      active: false
                    }
                  ]
                }
              })
          ]

          viteImagemin在國內(nèi)比較難安裝,容易出現(xiàn)報(bào)錯(cuò),可以嘗試一下下面幾種解決方案。

          viteImagemin報(bào)錯(cuò)

          1. 使用 yarn 在 package.json 內(nèi)配置(推薦) "resolutions": { "bin-wrapper": "npm:bin-wrapper-china" }
          2. 使用 npm,在電腦 host 文件加上如下配置即可 199.232.4.133 raw.githubusercontent.com
          3. 使用 cnpm 安裝(不推薦)

          填坑

          坑1

          在優(yōu)化過程中發(fā)現(xiàn)有什么rollupOption不生效,請(qǐng)檢查vite版本。上述配置在vite4.0版本生效,如需升級(jí),請(qǐng)前往官方遷移文檔。

          坑2

          Uncaught TypeError: Failed to resolve module specifier "Vue". Relative references must start with either "/", "./", or "../".get

          這里有可能是 vue-demi 引入了 vue,然而 rollup-plugin-external-globals 插件配置全局變量時(shí)不會(huì)處理 node_modules 下的依賴項(xiàng),導(dǎo)致 vue-demi 還是通過 import 的方式與 node_modules 下的 vue 進(jìn)行關(guān)聯(lián),而沒有使用全局變量下的 vue,打包后 vue 已變成外部依賴項(xiàng),vue-demi 自然無法找到 vue,所以就報(bào)錯(cuò)了。

          vue-demi是哪里來的呢,我的項(xiàng)目是由于element-plus引用了vue-demi,所以此時(shí)解決方案就是將vue-demi也用cdn引入。

          總結(jié)

          到了這一步,整個(gè)文件夾已經(jīng)完全瘦身了。從一開始的30MB到現(xiàn)在的11.8MB了。我們?cè)陧?xiàng)目里面放置了許多json數(shù)據(jù)(因?yàn)闃I(yè)務(wù)原因不能上傳到服務(wù)器),json數(shù)據(jù)已經(jīng)占了差不多5、6mb的原因,所以是一個(gè)單純的項(xiàng)目并沒有這么大。

          ebb493b9d0e948a4b152a778fd0de066.webpimage.png

          配置

                
                js
          復(fù)制代碼// vite.config.js
          import { defineConfig } from 'vite'
          import { createHtmlPlugin } from 'vite-plugin-html'
          import viteImagemin from 'vite-plugin-imagemin'
          import externalGlobals from 'rollup-plugin-external-globals'
          import { visualizer } from 'rollup-plugin-visualizer'
          import viteCompression from 'vite-plugin-compression'
          // https://vitejs.dev/config/
          export default defineConfig({
            plugins: [
              visualizer({ opentrue }),
              // 將下面的添加到plugin下
              createHtmlPlugin({
                minifytrue,
                inject: {
                  data: {
                    vuescript'<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>',
                    demiScript'<script src="http://cdn.jsdelivr.net/npm/[email protected]"></script>',
                    elementPlusScript`
                      <link ></script>
                    `
          ,
                    echartsSciprt'<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js"></script>'
                  }
                }
              }),
              viteImagemin({
                gifsicle: {
                  optimizationLevel7,
                  interlacedfalse
                },
                optipng: {
                  optimizationLevel7
                },
                mozjpeg: {
                  quality20
                },
                pngquant: {
                  quality: [0.80.9],
                  speed4
                },
                svgo: {
                  plugins: [
                    {
                      name'removeViewBox'
                    },
                    {
                      name'removeEmptyAttrs',
                      activefalse
                    }
                  ]
                }
              })
            ],
            build: {
              target'es2020',
              minify'terser',
              // rollup 配置
              rollupOptions: {
                output: {
                  chunkFileNames'js/[name]-[hash].js'// 引入文件名的名稱
                  entryFileNames'js/[name]-[hash].js'// 包的入口文件名稱
                  assetFileNames'[ext]/[name]-[hash].[ext]'// 資源文件像 字體,圖片等
                  manualChunks(id) {
                    if (id.includes('node_modules')) {
                      return 'vendor'
                    }
                  }
                },
                //  告訴打包工具 在external配置的 都是外部依賴項(xiàng)  不需要打包
                external: ['vue''element-plus''echarts'],
                plugins: [
                  externalGlobals({
                    vue'Vue',
                    'element-plus''ElementPlus',
                    echarts'echarts',
                    'vue-demi''VueDemi'
                  }),
                  viteCompression({
                    verbosetrue// 是否在控制臺(tái)中輸出壓縮結(jié)果
                    disablefalse,
                    threshold10240// 如果體積大于閾值,將被壓縮,單位為b,體積過小時(shí)請(qǐng)不要壓縮,以免適得其反
                    algorithm'gzip'// 壓縮算法,可選['gzip',' brotliccompress ','deflate ','deflateRaw']
                    ext'.gz',
                    deleteOriginFilefalse // 源文件壓縮后是否刪除
                  })
                ]
              },
              terserOptions: {
                compress: {
                  // 生產(chǎn)環(huán)境時(shí)移除console
                  drop_consoletrue,
                  drop_debuggertrue
                }
              }
            }
          })

          相關(guān)文章

          你還在憑感覺來優(yōu)化性能?

          從零開始搭建vite4.0-vue3.0項(xiàng)目

          作者:simple_lau

          鏈接:https://juejin.cn/post/7232688124416458789

          瀏覽 199
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  操逼操逼操逼操逼操逼操逼 | 午夜无码中文字幕 | 夜天干天干啦天干天天爽 | 爱弓凉免费无码一区二区 | 成人影久久久 |