1. 程式人生 > >在 Webpack 中執行程式碼分割

在 Webpack 中執行程式碼分割

有三種常用的程式碼分離方法:

  • 入口起點:使用 entry 配置手動地分離程式碼。
  • 動態匯入:通過模組的行內函數呼叫來分離程式碼。

1、入口起點

這是迄今為止最簡單、最直觀的分離程式碼的方式。不過,這種方式手動配置較多

webpack.config.js

const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: {
    index: './src/index.js',
    another: './src/another-module.js'
  },
  plugins: [
    new HTMLWebpackPlugin({
      title: 'Code Splitting'
    })
  ],
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};
這將生成如下構建結果
Hash: 309402710a14167f42a8
Version: webpack 2.6.1
Time: 570ms
            Asset    Size  Chunks                    Chunk Names
  index.bundle.js  544 kB       0  [emitted]  [big]  index
another.bundle.js  544 kB       1  [emitted]  [big]  another
   [0] ./~/lodash/lodash.js 540 kB {0} {1} [built]
   [1] (webpack)/buildin/global.js 509 bytes {0} {1} [built]
   [2] (webpack)/buildin/module.js 517 bytes {0} {1} [built]
   [3] ./src/another-module.js 87 bytes {1} [built]
   [4] ./src/index.js 216 bytes {0} [built]

正如前面提到的,這種方法存在一些問題:

  • 如果入口 chunks 之間包含重複的模組,那些重複模組都會被引入到各個 bundle 中。
  • 這種方法不夠靈活,並且不能將核心應用程式邏輯進行動態拆分程式碼。

2、防止重複

CommonsChunkPlugin 外掛可以將公共的依賴模組提取到已有的入口 chunk 中,或者提取到一個新生成的 chunk。讓我們使用這個外掛,將之前的示例中重複的 lodash 模組去除:

webpack.config.js

  const path = require('path');
+ const webpack = require('webpack');
  const HTMLWebpackPlugin = require('html-webpack-plugin');

  module.exports = {
    entry: {
      index: './src/index.js',
      another: './src/another-module.js'
    },
    plugins: [
      new HTMLWebpackPlugin({
        title: 'Code Splitting'
- })
+ }),
+ new webpack.optimize.CommonsChunkPlugin({
+ name: 'common' // 指定公共 bundle 的名稱。
+ })
    ],
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist')
    }
  };

這裡我們使用 CommonsChunkPlugin 之後,現在應該可以看出,index.bundle.js 中已經移除了重複的依賴模組。需要注意的是,CommonsChunkPlugin 外掛將 lodash 分離到單獨的 chunk,並且將其從 main bundle 中移除,減輕了大小。執行 npm run build 檢視效果:

Hash: 70a59f8d46ff12575481
Version: webpack 2.6.1
Time: 510ms
            Asset       Size  Chunks                    Chunk Names
  index.bundle.js  665 bytes       0  [emitted]         index
another.bundle.js  537 bytes       1  [emitted]         another
 common.bundle.js     547 kB       2  [emitted]  [big]  common
   [0] ./~/lodash/lodash.js 540 kB {2} [built]
   [1] (webpack)/buildin/global.js 509 bytes {2} [built]
   [2] (webpack)/buildin/module.js 517 bytes {2} [built]
   [3] ./src/another-module.js 87 bytes {1} [built]
   [4] ./src/index.js 216 bytes {0} [built]

以下是由社群提供的,一些對於程式碼分離很有幫助的外掛和 loaders:

  • bundle-loader: 用於分離程式碼和延遲載入生成的 bundle。
  • promise-loader: 類似於 bundle-loader ,但是使用的是 promises。

3、動態匯入

new Vue({ 

  el: '#app',
  components: {
    AsyncComponent: () => import('./AsyncComponent.vue')
  }
});

實施程式碼分割並不難,難在搞清楚在什麼時候、什麼地方進行。

Vue.js 單頁應用進行程式碼分割有三種思路:

  • 按頁面分割
  • 使用摺疊
  • 按條件分割

1. 按頁面

按頁面來進行程式碼分割,是最明顯的一種方式。

如果能確保每個單檔案元件代表一個頁面,如 Home.vueAbout.vue 以及 Contact.vue,那麼我們就可以使用 Webpack 的 "動態匯入" 函式 (import) 來將它們分割至單獨的構建檔案中。之後後,當用戶訪問一個新頁面的時候,Webpack 將非同步載入該請求的頁面檔案。

如果用到了 vue-router,由於頁面已經分割成了單獨的元件,實施起來會非常方便。

 const Home = () => import(/* webpackChunkName: "home" */ './Home.vue'); 
 const About = () => import(/* webpackChunkName: "about" */ './About.vue'); 
 const Contact = () => import(/* webpackChunkName: "contact" */ './Contact.vue'); 
 const routes = [ 
 { path: '/', name: 'home', component: Home }, 
 { path: '/about', name: 'about', component: About }, 
 { path: '/contact', name: 'contact', component: Contact } 
 ]; 

程式碼編譯完成後,通過檢視生成的統計資料得知:每個頁面都有自己單獨的檔案,同時有多出來一個名為 build_main.js 的打包檔案。裡面包含一些公共的程式碼以及邏輯,用來非同步載入其它檔案,因此它需要在使用者訪問路由之前載入完成。

2. 摺疊

“摺疊” 是指頁面初次載入時,檢視的不可見部分。使用者通常會花費 1~2 秒來瀏覽可視區域,特別是第一次訪問網站的時候(可能更久),之後才開始向下滑動頁面。
這個時候,可以非同步載入剩餘的內容。

3. 條件展示內容

程式碼分割另一種比較好的備選方式,是按條件展示。比如:模態框、標籤頁、下拉選單之類。

如果我們需要一個模態框,給模態框設定 v-if 屬性,綁定了 show 變數。一方面用來控制模態框是否顯示,同時也決定了是否應該渲染模態框元件。當頁面載入的時候,它的值為 false,模態框的程式碼只有當它顯示的時候才會被載入。如果使用者永遠不開啟這個模態框,這部分程式碼就永遠不會被下載。缺點是,可能會增加很小的使用者體驗成本:使用者點選按鈕後,需要等待程式碼檔案下載完成。