Webpack 4 教程 - 4. 使用SplitChunksPlugin插件進行代碼分割

Webpack 4給咱們帶來了一些改變。包括更快的打包速度,引入了SplitChunksPlugin插件來取代(以前版本里的)CommonsChunksPlugin插件。在這篇文章中,你將學習如何分割你的輸出代碼,從而提高咱們應用的性能。html

代碼分割的理念

首先搞明白: webpack裏的代碼分割是個什麼鬼? 它容許你將一個文件分割成多個文件。若是使用的好,它能大幅提高你的應用的性能。其緣由是基於瀏覽器會緩存你的代碼這一事實。每當你對某一文件作點改變,訪問你站點的人們就要從新下載它。然而依賴卻不多變更。若是你將(這些依賴)分離成單獨的文件,訪問者就無需屢次重複下載它們了。node

使用webpack生成一個或多個包含你源代碼最終版本的「打包好的文件」(bundles),(概念上咱們看成)它們由(一個一個的)chunks組成。webpack

入口(Entry)

入口定義了咱們的應用代碼開始執行的那個文件,webpack從這個文件開始打包。你能定義一個入口點(常見於單頁應用 - Single-Page Application), 或者多個入口點(常見於多頁應用 - Multiple-Page Application)。web

定義一個入口點就生成一個chunk。若是你只是用字符串的方式定義了一個入口點,其就被命名爲main。若是你用對象的方式定義多個入口點,其就被命名爲入口對象中的鍵值。下面兩個例子是等價的:瀏覽器

entry: './src/index.js'
entry: {
  main: './src/index.js'
}

輸出(Output)

輸出對象配置webpack如何輸出咱們的打包(bundles)和資源(assets),以及將它們放到哪裏。由於可能多於一個入口點,而只(能)指定一個輸出配置。事實上咱們就用chunks來給其一一命名。你能給打包輸出的文件定義一個肯定的名字,但既然咱們想要分割咱們的代碼,就不能這麼幹。你得使用[name]來建立輸出文件名的模板:緩存

output: {
  filename: '[name].[chunkhash].bundle.js',
  path: path.resolve(__dirname, 'dist')
}

這裏要注意的重要事情是 [chunkhash]: 它基於你文件的內容給每一個chunk生成了一個特有的hash。它只有在你的文件內容自己變化的時候才變化。事實上,(若是內容沒有變化)瀏覽器會緩存它。若是文件名改變了(譯註:這裏是指hash變化了,而hash是文件名的一部分,即意味着文件的內容變化了),瀏覽器就知道要從新下載了。chunkhash看起來長得就象這樣子: 0c553ebfd158e16da428異步

如此這般,咱們的main chunk就會被打包成名爲 main.[chunkhash].bundle.js的文件。性能

SplitChunksPlugin插件

正是有了SplitChunksPlugin插件,你能在你的應用中移出一部分到單獨的文件中。若是一個模塊被多個chunks使用,(分割出它以後)就能很容易的在這些chunks之間共享。這正是webpack的默認行爲。學習

// utilities/users.js

export default [
  { firstName: "Adam", age: 28 },
  { firstName: "Jane", age: 24 },
  { firstName: "Ben",  age: 31 },
  { firstName: "Lucy", age: 40 }
]
// a.js

import _ from 'lodash';
import users from './users';

const adam = _.find(users, { firstName: 'Adam' });
// b.js

import _ from 'lodash';
import users from './users';

const lucy = _.find(users, { firstName: 'Lucy' });
// webpack.config.js

module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  }
};

運行以後,你會看到webpack建立了二個文件: a.[chunkhash].bundle.js和b.[chunkhash].bundle.js,每個文件都包含了lodash庫的一份拷貝: 這不太好! 我以前說過webpack的默認行爲會給共享庫建立分離的文件,但這涉及到異步chunks,即咱們異步導入文件。咱們在討論懶加載的時候再來更多的覆蓋這一主題。爲了針對全部類型的chunks,咱們須要稍微改改咱們的webpack配置:ui

// webpack.config.js

module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  },
  optimization: {
    splitChunks: {
      chunks: "all"
    }
  },
};

如今咱們看到建立了一個附加的名叫vendors~a~b.[chunkhash].bundle.js的文件,其包含了Lodash庫。事實上這全靠了配置中自己默認固有一個cacheGroups的配置項:

splitChunks: {
    chunks: "all",
    cacheGroups: {
      vendors: {
        test: /[\\/]node_modules[\\/]/,
        priority: -10
      },
      default: {
        minChunks: 2,
        priority: -20,
        reuseExistingChunk: true
      }
    }
  }

首先,vendors這一項指明瞭包括來自node_modules目錄中的文件。其次default這一項表示默認的緩存組,包括其它共享模塊。這裏有一個小小的問題:發生了重複。a.[chunkhash].bundle.js和b.[chunkhash].bundle.js都包含了users.js的內容。這是由於,SplitChunksPlugin插件默認只分割超過30kb的文件。咱們能很容易的更改這點:

// webpack.config.js

module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  },
  optimization: {
    splitChunks: {
      chunks: "all",
      minSize: 0
    }
  }
};

默認的cache group配置使得會生成一個名爲a~b.[chunkhash].bundle.js的文件。由於咱們的users.js文件大大小於30kb,若是沒有修改minSize屬性的話,它就不會分割成一個單獨的文件。在真實情形下,這是合理的,由於(如分割)並不能帶來性能確實的提高,反而使得瀏覽器多了一次對utilities.js的請求,而這個utilities.js又是如此之小(不划算)。

咱們能更進一小步,只針對utilities目錄中的文件:

// webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  },
  optimization: {
    splitChunks: {
      chunks: "all",
      cacheGroups: {
        utilities: {
          test: /[\\/]src[\\/]utilities[\\/]/,
          minSize: 0
        }
      }
    }
  }
};

如今咱們打包出4個文件:a.[chunkhash].bundle.js, b.[chunkhash].bundle.js, vendors~a~b.[chunkhash].bundle.js 和 utilities~a~b.[chunkhash].bundle.js。即便咱們如今設置一個全局的minSize: 0(在splitChunks對象中),默認的cache group也不會建立。這是由於被咱們建立的utilities group覆蓋了。utilities group默認的優先級值是0, 高於default cache group的。你可能已經注意到,默認cache group的優先級設置成了-20。

還有其它一些默認參數的設置,你能查閱SplitChunksPlugin的文檔

小結

即便你只有一個入口點(見於大多數的單頁應用),分離依賴到單獨的文件中也是一個好主意。使用SplitChunksPlugin來達到這一目標實際上很簡單,由於這是Webpack 4的默認行爲,頗有可能你只需設置chunks: 「all」就足夠了。若是你想要我說說其它有關的東西,告訴我吧。很快咱們將學習如何應用懶加載來更好的提高性能, 敬請期待!

相關文章
相關標籤/搜索