Webpack 之經常使用配置(三)

做者:餘韻之

LazyLoading 懶加載 Chunk是什麼?

咱們可使用懶加載的方式引入模塊,好比說當觸發了某個條件,在經過import的方式引入模塊。這樣可使得項目的性能會更加的好。css

舉個例子html

當咱們點擊頁面的時候,纔會去引入lodash模塊,這裏 import()返回的是promise前端

async function getComponent() {
  const {default: _} = await import(/* webpackChunkName:"lodash" */'lodash')
  const element = document.createElement('div')
  element.innerHTML = _.join(['y', 'kk'], '-');
  return element;
}

document.addEventListener('click', () => {
  getComponent().then(element => {
    document.body.appendChild(element)
  })
})

一樣的路由懶加載的意思,表示當咱們監聽到路由變化了,纔會去引入對應的頁面模塊。node

所以能夠知道,Chunk是什麼?打包生成幾個JS文件,就是幾個Chunkjquery

Shimming

Shimming:在打包過程當中,有時候須要對代碼兼容。這種兼容不侷限於瀏覽器高低版本。webpack

舉個例子git

每一個文件都是一個模塊,每一個模塊都應該引入本身的依賴才能使用該依賴。github

import $ from 'jquery'
export function setBackground(){
  $('body').css('background','red')
}

可是這樣的話,每一個文件都要寫一遍web

import $ from 'jquery'

所以可使用墊片的方式來自動配置npm

plugins:[
    new webpack.ProvidePlugin({
      $:'jquery',
      _join:['lodash','join']
    })
]

當咱們配置了上述內容,那麼意味着當運行代碼的時候看到

  • $這個符號就會自動去node_modules裏引入jquery。他的原理就是自動幫咱們添加了import的步驟。
  • 看到_join就會自動找到 lodash裏join的方法

因而咱們能夠直接這些一個文件模塊使用

export function setBackground(){
  $('body').css('background', _join(['green'], ''))
}

webpack與瀏覽器緩存(caching)

當咱們打包生成了

index.html
main.js
vendors.js

客戶端從服務端拿到了兩個js文件,會保存在瀏覽器裏。客戶端刷新後瀏覽器會先從緩存裏獲取。
當開發修改了代碼,從新打包,生成了上述三個同名文件時,用戶刷新後仍然是原來的代碼並無更新。
這樣如何解決呢?

一、打包文件添加contentHash

開發環境由於是熱更新的,因此本地調試能夠不添加,
生產環境在output裏改成

output: {
    filename: '[name].[contentHash].js',
    chunkFilename: '[name].[contentHash].js'
}

contentHash 表示只要不改變源代碼的內容,那麼contentHash所產生的hash值是不會變的。若是代碼是分割成不一樣的chunk,某個chunk沒有修改,該chunk的文件名contentHash也不會修改

同時作了代碼分割的參數最好也配置一下

optimization.splitChunks.cacheGroup.vendors.filename = 'vendors.[contentHash].js'

二、對老版本的兼容

可能老的版本即便不改內容,contentHash值也會改變,這個時候能夠配置

optimization: {
    runtimeChunk:{
      name:'runtime'
    }
}

新版本添加這個runtimeChunk也是沒有問題的,此時打包會多出一個runtime.xxxxxxx.js文件

這是怎麼回事呢?

由於在舊的webpack版本里main.js(業務邏輯) 和 vendors.js(第三方庫) 之間是存在關聯的,這部分的處理代碼放在mainfest,雖然沒有改變代碼,但在舊版本的webpack裏 mainfest 包和包之間的關係每次打包可能會變化,當咱們配置了runtimeChunk的時候就把mainfest這塊關係相關的代碼抽離出來了放在runtime.js裏

所以這樣就解決了這個兼容老版本的問題。

對CSS代碼分割

正常打包的話,會把CSS文件一塊兒打包的main.js文件,如何進行CSS代碼分割呢?

一、使用一個插件:mini-css-extract-plugin

但這個插件有一個缺點,目前不支持熱更新,因此適合線上環境作打包

配置方式安裝依賴

yarn add mini-css-extract-plugin

在生產環境的webpack.config.js配置

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

  module:{
    rules:[
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              importLoaders: 2
            }
          },
          'sass-loader',
          'postcss-loader'
        ]
      }, {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader'
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "[name].css", //index.html直接引入的文件
      chunkFilename: "id.css" // 間接引用的文件
    })
  ]

注意 若是此時使用了tree shaking 看看 package.json 裏 sideEffects 配置。若是爲false那麼css代碼是沒有分割的。須要把css tree shaking排除在外。修改以下:

"sideEffects": [
    "*.css"
  ],

二、接下來對合並的CSS代碼壓縮

安裝依賴

yarn add optimize-css-assets-webpack-plugin -D

生產環境

const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')

optimization:{
    minimizer:[new OptimizeCSSAssetsPlugin({})]
}

打包分析

生成webpack打包分析json

webpack --profile --json > stats.json --config ./build/webpack.dev.js

而後把生成的stats.json放入相關的分析網站就能夠看到可視化的數據。固然也能夠配置analyzer

安裝依賴

npm install webpack-bundle-analyzer --save-dev

在webpack.config.js配置

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
 
module.exports = {
  ...
  configureWebpack: {
    plugins: [
        new BundleAnalyzerPlugin({
                    //  能夠是`server`,`static`或`disabled`。
                    //  在`server`模式下,分析器將啓動HTTP服務器來顯示軟件包報告。
                    //  在「靜態」模式下,會生成帶有報告的單個HTML文件。
                    //  在`disabled`模式下,你可使用這個插件來將`generateStatsFile`設置爲`true`來生成Webpack Stats JSON文件。
                    analyzerMode: 'server',
                    //  將在「服務器」模式下使用的主機啓動HTTP服務器。
                    analyzerHost: '127.0.0.1',
                    //  將在「服務器」模式下使用的端口啓動HTTP服務器。
                    analyzerPort: 8888, 
                    //  路徑捆綁,將在`static`模式下生成的報告文件。
                    //  相對於捆綁輸出目錄。
                    reportFilename: 'report.html',
                    //  模塊大小默認顯示在報告中。
                    //  應該是`stat`,`parsed`或者`gzip`中的一個。
                    //  有關更多信息,請參見「定義」一節。
                    defaultSizes: 'parsed',
                    //  在默認瀏覽器中自動打開報告
                    openAnalyzer: true,
                    //  若是爲true,則Webpack Stats JSON文件將在bundle輸出目錄中生成
                    generateStatsFile: false, 
                    //  若是`generateStatsFile`爲`true`,將會生成Webpack Stats JSON文件的名字。
                    //  相對於捆綁輸出目錄。
                    statsFilename: 'stats.json',
                    //  stats.toJson()方法的選項。
                    //  例如,您可使用`source:false`選項排除統計文件中模塊的來源。
                    //  在這裏查看更多選項:https:  //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
                    statsOptions: null,
                    logLevel: 'info' // 日誌級別。能夠是'信息','警告','錯誤'或'沉默'。
        })
    ]
  }, 
  ...
};

使用方式 在打包或者啓動的時候加 --report

npm run serve --report
npm run build --report

prefetching && preloading

關注代碼使用率:一開始不會執行的代碼不要加載出來,而是當交互了再去加載。

webpack但願儘量使用異步加載模快在第一次加載提升性能,而同步是第二次加載了增長緩存對性能的提高是有限的。

document.addEventListener('click', () => {
  import('./click.js').then(({default:func}) => {
    func()
  })
})

注意 但這樣會存在一個問題,就是當用戶點擊交互了才下載代碼可能會有一點小小的延遲,如何解決這個問題?

解決方案就是 : prefetching/preloading

  • prefetching 會等到核心先展現的代碼加載完畢了,等寬帶空閒再繼續下載。

只須要在代碼添加以下內容便可:

document.addEventListener('click', () => {
  import(/* webpackPrefetch:true */'./click.js').then(({default:func}) => {
    func()
  })
})

當用戶點擊了,仍然會下載click.js文件,可是使用的時間會很是短,由於以前已經下載過了有了緩存了。

  • preloading 會和主的代碼同時下載。
document.addEventListener('click', () => {
  import(/* webpackPreload:true */'./click.js').then(({default:func}) => {
    func()
  })
})

所以性能優化最好去考慮代碼的使用率更高。


對 Electron 感興趣?請關注咱們的開源項目 Electron Playground,帶你極速上手 Electron。

咱們每週五會精選一些有意思的文章和消息和你們分享,來掘金關注咱們的 曉前端週刊


咱們是好將來 · 曉黑板前端技術團隊。
咱們會常常與你們分享最新最酷的行業技術知識。
歡迎來 知乎掘金SegmentfaultCSDN簡書開源中國博客園 關注咱們。
相關文章
相關標籤/搜索