webpack 性能優(yōu)化

1. oneOf

對(duì)于某種類型的文件,webpack 會(huì)從上至下匹配所有的 loader,也就是,所有的 loader 都會(huì)去處理這種文件。但是,webpack 這種匹配方式在有些場(chǎng)景反而影響了效率。比如說,一個(gè) webpack 只有 babel-loader 處理了 js 文件,那么當(dāng)它匹配完了以后,完全沒有必要再匹配一些針對(duì) css 文件的 loader。所以,這就是為什么,我們使用 oneOf,匹配到了,立刻跳出循環(huán)。因此 oneOf 可以優(yōu)化構(gòu)建速度

    module: {
            rules: [
                {
                    oneOf: [
                        {
                            test: /\.(png|jpg|jpeg)$/,
                            use: ['file-loader'],
                            exclude: /(node_modules|bower_components|dist)/
                        }
                    ]
                }
           ]
      }
2. babel 緩存

babel 緩存的意思是,瀏覽器第一次拿資源文件的時(shí)候,會(huì)從服務(wù)器上走 http 拉取,但是當(dāng)刷新頁面再次請(qǐng)求的時(shí)候,瀏覽器會(huì)直接從緩存(可以是內(nèi)存,也可以是硬盤,自己配置)當(dāng)中拿同名文件,因此省去了發(fā)送 http 請(qǐng)求拿資源的時(shí)間。

3. 多進(jìn)程打包

業(yè)內(nèi)有兩種解決方案比較常用,一個(gè)是 thread-loader,一個(gè)是 happy-pack,但是 happy-pack 的維護(hù)者現(xiàn)在對(duì)這個(gè)庫不再維護(hù)了,因此,推薦使用 thread-loader(多進(jìn)程打包,不是線程)。

 {
                rules:
                    [
                        {
                            test: /\.(js|jsx)$/,
                            exclude: /(node_modules|bower_components|dist)/,
                            use: [
                                /**
                                 * 開啟多進(jìn)程打包,打開進(jìn)程一般 600 ms,
                                 * 通信也有開銷。
                                 */
                                {
                                     loader: "thread-loader",
                                     options: {
                                         workers: 3
                                     }
                                },
                                {
                                    loader: "babel-loader",
                                    options: {
                                        cacheDirectory: true
                                    }
                                }

                            ]
                        }
                   ]
              }

需要在 options 字段下配置 workers 也就是進(jìn)程的個(gè)數(shù)。注意 thread-loader 并不是開的進(jìn)程數(shù)越多就越好,假如你的 js 代碼量很少,開多核反而會(huì)降低性能,這是因?yàn)榇蜷_進(jìn)程有比較大的開銷(600 ms 左右),進(jìn)程間通信也有開銷。

4. tree shaking

tree shaking 的意思是你的項(xiàng)目里面有些代碼可能是從來沒被引入的,比方說你定義了一個(gè)函數(shù)但是你從來沒有引用到它。這個(gè)時(shí)候 tree shaking 可以在打包的時(shí)候幫你干掉這些代碼。

前提
使用 ES6 module
production 默認(rèn)開啟

需要配合 package.json 里面 sideEffects: ["*.css"] 一同使用,否則可能會(huì)干掉打包好的 css 文件。

5. code split

code split 直接從字面上理解即可,就是代碼分割技術(shù),因?yàn)?html 里面的靜態(tài)資源文件是并行加載的,即發(fā)送 http 請(qǐng)求并且把文件放到內(nèi)存里這個(gè)過程是并行的。所以適當(dāng)?shù)拇a分割技術(shù)可以讓我們的項(xiàng)目運(yùn)行性能更好。另外,代碼分割也可以幫助我們?cè)诙嗦酚傻膱?chǎng)景進(jìn)行性能優(yōu)化。
多入口

entry: {
  main: './src/js/index.js', // 入口1
  test: './src/js/test.js'  // 入口2
},
output: {
    // [name]是webpack命名規(guī)則,使用chunk的name作為輸出的文件名。
    // 什么是chunk?打包的資源就是chunk,輸出出去叫bundle。
    // chunk的name是啥呢? 比如: entry中xxx: "./src/xxx.js", name就是xxx。注意是前面的xxx,和文件名無關(guān)。
    // 為什么需要這樣命名呢?如果還是之前寫法main.js,那么打包生成兩個(gè)js文件都會(huì)叫做main.js會(huì)發(fā)生覆蓋。(實(shí)際上會(huì)直接報(bào)錯(cuò)的)
  filename: 'js/[name].[contenthash:10].js'
  path: resolve(__dirname, 'build')
}
// optimization 代碼分割配置
optimization: {
  splitChunks:{
    chunks: 'all' // 對(duì)所有模塊都進(jìn)行分割
// 以下是默認(rèn)值
      // minSize: 20000, // 分割代碼最小的大小
      // minRemainingSize: 0, // 類似于minSize,最后確保提取的文件大小不能為0
      // minChunks: 1, // 至少被引用的次數(shù),滿足條件才會(huì)代碼分割
      // maxAsyncRequests: 30, // 按需加載時(shí)并行加載的文件的最大數(shù)量
      // maxInitialRequests: 30, // 入口js文件最大并行請(qǐng)求數(shù)量
      // enforceSizeThreshold: 50000, // 超過50kb一定會(huì)單獨(dú)打包(此時(shí)會(huì)忽略minRemainingSize、maxAsyncRequests、maxInitialRequests)
      // cacheGroups: { // 組,哪些模塊要打包到一個(gè)組
      //   defaultVendors: { // 組名
      //     test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模塊
      //     priority: -10, // 權(quán)重(越大越高)
      //     reuseExistingChunk: true, // 如果當(dāng)前 chunk 包含已從主 bundle 中拆分出的模塊,則它將被重用,而不是生成新的模塊
      //   },
      //   default: { // 其他沒有寫的配置會(huì)使用上面的默認(rèn)值
      //     minChunks: 2, // 這里的minChunks權(quán)重更大
      //     priority: -20,
      //     reuseExistingChunk: true,
      //   },
      // },
      // 修改配置
      // cacheGroups: {
        // 組,哪些模塊要打包到一個(gè)組
        // defaultVendors: { // 組名
        //   test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模塊
        //   priority: -10, // 權(quán)重(越大越高)
        //   reuseExistingChunk: true, // 如果當(dāng)前 chunk 包含已從主 bundle 中拆分出的模塊,則它將被重用,而不是生成新的模塊
        // },

  }
}

上面這塊配置可以把你做兩件事:

node_modules 中代碼單獨(dú)打包成一個(gè) chunk
自動(dòng)分析多入口 chunk 中,有沒有公共文件,如果有會(huì)打包成一個(gè)單獨(dú) chunk

6. 懶加載和預(yù)加載

懶加載
使用 import 函數(shù),同上。回調(diào)函數(shù)中使用 import 函數(shù)。

document.getElementById('btn').onclick = () => {
  import('./test').then(({mul})=> {
    console.log(mul(4,5))
  })
)

預(yù)加載

 // eslint會(huì)對(duì)動(dòng)態(tài)導(dǎo)入語法報(bào)錯(cuò),需要修改eslint配置文件
  // webpackChunkName: "math":這是webpack動(dòng)態(tài)導(dǎo)入模塊命名的方式
  // "math"將來就會(huì)作為[name]的值顯示。
// webpackPrefetch 開啟預(yù)加載
document.getElementById('btn').onclick = () => {
  import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({mul})=> {
    console.log(mul(4,5))
  })
)
7. pwa

適用情景,我們希望在用戶離線時(shí)也可以訪問我們的頁面。對(duì)于 webpack 而言,我需要使用的是 workbox-webpack-plugin。配置成功以后,瀏覽器在離線后可以從 service-worker 里拉取靜態(tài)資源。

// webpack
plugins: [
  new WorkboxWebpackPlugin.GenerateSW({ 
    // 刪除舊的 serviceWorker 且快速啟動(dòng)
    clientsClaim: true,
    skipWaiting: true
  })
]

// js
if('serviceWorker' in navigator){
  window.addEventListenr('load', ()=>{
    navigator.serviceWorker.register.register('./service-worker.js')
    .then(()=>{
      console.log('sw 注冊(cè)成功了')
    })
    .catch(()=>{
      console.log('sw 注冊(cè)失敗')
    })
  })
}
8. CDN

CDN稱之為內(nèi)容分發(fā)網(wǎng)絡(luò)(Content Delivery Network或Content Distribution Network,縮寫:CDN), 它是指通過相互連接的網(wǎng)絡(luò)系統(tǒng),利用最靠近每個(gè)用戶的服務(wù)器; 更快、更可靠地將音樂、圖片、視頻、應(yīng)用程序及其他文件發(fā)送給用戶; 來提供高性能、可擴(kuò)展性及低成本的網(wǎng)絡(luò)內(nèi)容傳遞給用戶;

在開發(fā)中,我們使用CDN主要是兩種方式:
方式一:打包的所有靜態(tài)資源,放到CDN服務(wù)器, 用戶所有資源都是通過CDN服務(wù)器加載的;
方式二:一些第三方資源放到CDN服務(wù)器上

9. JS代碼壓縮

Terser

 optimization: {
     minimize: true, // 是否要啟用壓縮,默認(rèn)情況下,生產(chǎn)環(huán)境會(huì)自動(dòng)開啟
     minimizer: [
                // 壓縮時(shí)使用的插件,可以有多個(gè)
         new TerserPlugin(), // js壓縮插件
         new OptimizeCSSAssetsPlugin() // css壓縮插件
   ],
}
10. gizp

瀏覽器發(fā)送請(qǐng)求時(shí),會(huì)在請(qǐng)求頭中設(shè)置Accept-Encoding:gzip,deflate,br。表明瀏覽器支持gzip。服務(wù)器收到瀏覽器發(fā)送的請(qǐng)求之后,判斷瀏覽器是否支持gizp,如果支持gzip,則向?yàn)g覽器傳送壓縮過的內(nèi)容,不支持則向?yàn)g覽器發(fā)送未經(jīng)壓縮的內(nèi)容。一般情況下,瀏覽器和服務(wù)器都支持gzip,響應(yīng)頭返回包含content-encoding:gzip。瀏覽器接收到服務(wù)器的響應(yīng)之后判斷內(nèi)容是否被壓縮,如果被壓縮則解壓縮顯示頁面內(nèi)容
使用compression-webpack-plugin插件對(duì)打包結(jié)果進(jìn)行預(yù)壓縮,可以移除服務(wù)器的壓縮時(shí)間。

    const CmpressionWebpackPlugin = require("compression-webpack-plugin")
    module.exports = {
      plugins: [
        new CmpressionWebpackPlugin({
          // filename: "[file].gzip"
          test: /\.js/, //針對(duì)需要預(yù)壓縮的文件
          minRatio: 0.5 //壓縮比率
        })
      ]
    };

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 筆者最近在整理關(guān)于 webpack 相關(guān)的知識(shí)點(diǎn),一方面是因?yàn)樽约赫莆盏闹R(shí)點(diǎn)比較零碎、不夠系統(tǒng),有時(shí)候碰到...
    darrell閱讀 1,155評(píng)論 0 5
  • 性能分析 1. 統(tǒng)計(jì)基本信息 使用webpack內(nèi)置的stats 可以統(tǒng)計(jì)出構(gòu)建時(shí)間、構(gòu)建資源清單及資源大小等信息...
    刷題刷到手抽筋閱讀 1,498評(píng)論 0 1
  • Webpack是現(xiàn)在主流的功能強(qiáng)大的模塊化打包工具,在使用Webpack時(shí),如果不注意性能優(yōu)化,有非常大的可能會(huì)產(chǎn)...
    沫之閱讀 1,145評(píng)論 0 0
  • 性能優(yōu)化, 可以分為三個(gè)方面: 構(gòu)建性能主要指開發(fā)階段的構(gòu)建性能, 降低從打包開始到代碼呈現(xiàn)效果所經(jīng)過的時(shí)間 傳輸...
    風(fēng)雅歡樂閱讀 369評(píng)論 0 0
  • webpack項(xiàng)目?jī)?yōu)化主要分為兩個(gè)方面的優(yōu)化,生產(chǎn)環(huán)境的代碼優(yōu)化和開發(fā)環(huán)境的項(xiàng)目構(gòu)建優(yōu)化 生產(chǎn)環(huán)境的代碼優(yōu)化 第一...
    慕時(shí)_木雨凡閱讀 1,339評(píng)論 0 8

友情鏈接更多精彩內(nèi)容