Webpack的Code Splitting實現按需載入

zhaiyy發表於2019-03-03

一. 什麼是Code Splitting?

在最開始使用Webpack的時候, 都是將所有的js檔案全部打包到一個build.js檔案中(檔名取決與在webpack.config.js檔案中output.filename), 但是在大型專案中, build.js可能過大, 導致頁面載入時間過長. 這個時候就需要code splitting, code splitting就是將檔案分割成塊(chunk), 我們可以定義一些分割點(split point), 根據這些分割點對檔案進行分塊, 並實現按需載入.

二. Code Splitting的作用?

  1. 第三方類庫單獨打包:
    由於第三方類庫的內容基本不會改變, 可以將其與業務程式碼分離出來, 這樣就可以最大化的利用瀏覽器的快取機制, 減少請求.
  2. 按需載入:
    Webpack支援定義分割點, 通過require.ensure進行按需載入.

三. 如何進行Code Splitting?

下面的程式碼是基於vue-cliwebpack-simple模板生成的演示文件

//cmd
vue init webpack-simple code_spliting_demo
複製程式碼

(一) 第三方類庫單獨打包

我們假設專案中引入了jquery.jsrespond.js, 那麼我們可以在webpack.config.js中配置多入口來進行將這兩個第三方類庫單獨打包.

  • webpack.config.js進行配置

    //webpack.config.js
    
    //在entry中新增相應第三方類庫
    entry: {
        bundle: './src/main.js',
        vendor: ['./src/lib/jquery-1.10.2.min.js', './src/lib/respond.min.js']
    }
      
     //在plugins中新增CommonChunkPlugin
    plugins:[
        new webpack.optimize.CommonsChunkPlugin({ 
            name: 'vendor',  
            filename: 'vendor.bundle.js'  
        })
    ]
    複製程式碼
  • 執行npm run build, 此時dist目錄下生成了兩個檔案, 分別是build.jsvendor.bundle.js

    npm run build後的生成檔案
    npm run build後的生成檔案
  • index.html中引入, 注意: vendor.bundle.js優先於build.js引入

    //index.html
    
    <script src="/dist/vendor.bundle.js"></script>
    <script src="/dist/build.js"></script>
    複製程式碼

(二) 按需載入

我們可以在router中進行配置, 實現元件的按需載入, 在一些單個元件檔案較大的時候, 採用按需載入能夠減少build.js的體積, 優化載入速度(如果元件的體積較小, 那麼採用按需載入會增加額外的http請求, 反倒增加了載入時間)

  • 這裡, 我們增加3個元件,分別是A.vue, B.vue, C.vue

    //A.vue
    <template>
        <h1>這裡是A.vue元件</h1>
    </template>
    
    //B.vue
    <template>
        <h1>這裡是B.vue元件</h1>
    </template>
    
    //C.vue
    <template>
        <h1>這裡是C.vue元件</h1>
    </template>
    複製程式碼
  • 在路由中進行配置 (注意:這裡是為了方便, 是在app.js中新增的路由, 在實際的專案中, 路由應該單獨抽取出來)

    //app.js
    
    import Vue from 'vue'
    import App from './App.vue'
    import VueRouter from 'vue-router'
    Vue.use(VueRouter)
    
    //AMD規範的非同步載入
    const ComA = resolve => require(['./components/A.vue' ], resolve);
    const ComB = resolve => require(['./components/B.vue' ], resolve);
    const ComC = resolve => require(['./components/C.vue' ], resolve);
    
    const router = new VueRouter({
      routes: [
        {
          name: 'component-A',
          path: '/a',
          component: ComA
        },
        {
          name: 'component-B',
          path: '/b',
          component: ComB
        },
        {
          name: 'component-C',
          path: '/c',
          component: ComC
        }
      ]
    })
    
    new Vue({
      el: '#app',
      router: router,
      render: h => h(App)
    })
    複製程式碼
  • webpack.config.js中進行配置output.chunkFilename,

//webpack.config.js

output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    filename: 'build.js',
    //新增chundkFilename
    chunkFilename: '[name].[chunkhash:5].chunk.js'
}
複製程式碼
  • 執行npm run build, 此時dist目錄下生成了5個檔案, 多出的3個檔案,就是對應的A.vue, B.vue, C.vue這三個元件

    npm run build後生成的檔案
    npm run build後生成的檔案
CMD規範的非同步載入

剛才在路由引入的時候, 使用的是AMD規範的非同步載入. webpack提供了require.ensure()這個方法實現CMD規範的非同步載入. 這同樣也是webpack推薦的載入方式.想深入瞭解ensure, 請點選《webpack程式碼分離 ensure 看了還不懂,你打我》

  • 下面的程式碼是使用require.ensure()方法對路由進行配置
//app.js

import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)

//AMD風格的非同步載入
// const ComA = resolve => require(['./components/A.vue' ], resolve);
// const ComB = resolve => require(['./components/B.vue' ], resolve);
// const ComC = resolve => require(['./components/C.vue' ], resolve);

//CMD風格的非同步載入
const ComA = resolve => require.ensure([], () => resolve(require('./components/A.vue')));
const ComB = resolve => require.ensure([], () => resolve(require('./components/B.vue')));
const ComC = resolve => require.ensure([], () => resolve(require('./components/C.vue')));

const router = new VueRouter({
  routes: [
    {
      name: 'component-A',
      path: '/a',
      component: ComA
    },
    {
      name: 'component-B',
      path: '/b',
      component: ComB
    },
    {
      name: 'component-C',
      path: '/c',
      component: ComC
    }
  ]
})

new Vue({
  el: '#app',
  router: router,
  render: h => h(App)
})
複製程式碼
  • 執行npm run build後, dist目錄下同樣生成5個檔案
    npm run build後生成的檔案
    npm run build後生成的檔案
  • 按需載入效果演示:
    按需載入效果演示
    按需載入效果演示
Lee_tanghui 釋出在 https://www.jianshu.com/p/b3b8fb8a2336


相關文章