在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 問答/HTML/ 代碼分割與懶加載情況下(code-splitting+lazyload)如何抽離

代碼分割與懶加載情況下(code-splitting+lazyload)如何抽離公用模塊代碼?

問題背景

我知道,通過CommonsChunkPlugin 可以將 entry 的入口文件中引用多次的文件抽離打包成一個公用文件,從而減少代碼重復(fù)冗余

    entry: {
        main: './src/main.js',
        user: './src/user.js'
    },
    ......
    new webpack.optimize.CommonsChunkPlugin({
        name: "commons",
        filename: 'common.js',
        minChunks: 2,
    })
    
    // 打包生成一個文件common.js ,包含main.js 和 user.js 中引用兩次及以上的模塊代碼

那么當(dāng)我使用了 vue-router 代碼分割 懶加載的時候,每個路由對應(yīng)的.vue文件中,共同引用了多次的模塊,怎么自動抽離出來。

問題描述

懶加載路由文件

const
    Index = () => import(/* webpackChunkName: "index" */ "page/index/Index.vue"),
    User = () => import(/* webpackChunkName: "userIndex" */ "page/user/Index.vue"),
    UserDetail = () => import(/* webpackChunkName: "userDetail" */ "page/user/Detail.vue"),
    ...
// page/index/Index.vue 首頁路由文件
<template>首頁</template>
<script>
    import pub from 'script/public'
    ...
</script>

// 用戶頁
// page/index/Index.vue 用戶頁路由文件
<template>用戶頁</template>
<script>
    import pub from 'script/public'
    ...
</script>

上述使用了vue-router懶加載打包出來的 首頁路由文件index.js 和 用戶頁文件userIndex.js 都會包含一份 public.js的代碼,重復(fù)了。

我的問題就是,在代碼分割的代碼中,怎么自動抽離公共代碼? 就像CommonsChunkPlugin的效果一樣,或者說CommonsChunkPlugin怎么在 code-splitting 的場景上使用?

回答
編輯回答
夕顏

如問題所示,存在兩個使用了webpack code-splitting 和 懶加載的路由文件,路由文件都使用了公用的public.js模塊。
// page/index/Index.vue 首頁路由文件

<template>首頁</template>
<script>
    import pub from 'script/public'
    ...
</script>

// 用戶頁
// page/index/Index.vue 用戶頁路由文件

<template>用戶頁</template>
<script>
    import pub from 'script/public'
    ...
</script>

要將 public.js公用模塊抽離,有兩種解決方案

方案一,CommonsChunkPlugin 具名模塊

手動將所有共用的模塊抽離在一個文件。
創(chuàng)建文件commons.js

// commons.js
import pub from 'public'

webpack.config.jsCommonsChunkPlugin插件指定commons 的entry

// webpack.config.js
entry:{
    main: 'src/main.js',
    commons: 'src/commons.js'
},
...
    new webpack.optimize.CommonsChunkPlugin({
        name: "commons",   // 和 entry的commons對應(yīng),
        filename: 'common.bundle.js', // 抽離公共文件
        minChunks: Infinity,
    })

這樣,如果路由文件或其他模塊使用到了 commons.js中的模塊,都不會重復(fù)加載代碼,而是在common.bundle.js中獲取。

方案二,CommonsChunkPlugin 設(shè)置 children 屬性

官方文檔CommonsChunkPlugin 中 children屬性解釋

Move common modules into the parent chunk

With Code Splitting, multiple child chunks of an entry chunk can have common dependencies. To prevent duplication these can be moved into the parent. This reduces overall size, but does have a negative effect on the initial load time. If it is expected that users will need to download many sibling chunks, i.e. children of the entry chunk, then this should improve load time overall.

可知,設(shè)置 children 為 true 可以將code-splitting的模塊的依賴模塊抽離到父模塊,這樣做的后果就是,確實(shí)抽離公用模塊,降低了代碼重復(fù),減少了代碼體積。但是同時,抽離到父模塊,也意味著如果有一個懶加載的路由 ShopList.vue 沒有用到public.js 模塊,但是實(shí)際上引入了父模塊,也為這ShopList.vue也引入了public.js的代碼。

這就需要CommonsChunkPluginasync 屬性。

方案三(最佳實(shí)踐),childrenasync 雙管齊下

Extra async commons chunk

Similar to the above one, but instead of moving common modules into the parent (which increases initial load time) a new async-loaded additional commons chunk is used. This is automatically downloaded in parallel when the additional chunk is downloaded.

設(shè)置了async, 會將上述懶加載的路由文件公用的模塊代碼,抽離打包成一個單獨(dú)的文件,并且該文件是按需加載的,如果某個路由沒有使用到這些公用模塊,是不會加載進(jìn)來的。

舉個例子:
首頁路由模塊(訪問路徑/index),引用了 public模塊
用戶路由模塊(訪問路徑/user),引用了 public模塊
購物車模塊(訪問路徑/shop),沒有引用 public模塊

那么,打包生成的文件大概是

main.js - 根入口文件
index.js - 首頁路由文件
user.js - 用戶路由文件
shop.js - 購物車路由文件
0.js - 抽離路由的公用模塊文件

訪問url/index,加載的依賴文件是main.js + index.js + 0.js
訪問url/user,加載的依賴文件是main.js + user.js + 0.js
訪問url/shop,加載的依賴文件是main.js + shop.js
基本解決了 lazy load + code-splitting 情況下的公用模塊抽離。

以下附上簡單的webpack.config.js配置代碼

entry: {
    main: './src/main.js'
},
...
plugins: [
    ...
    new webpack.optimize.CommonsChunkPlugin({
        name: "main",
        minChunks: 2,
        children: true,
        // deepChildren: true,
        async: true,
    })
]

參考資料

commons-chunk-plugin
CommonChunkPlugin: Feature - Select statically imported modules from chunks that were created from a dynamic import (require.ensure / System.import / import(".."))

2017年9月13日 17:32
編輯回答
不討囍

標(biāo)準(zhǔn)的做法不敢說,但是有一個解決方法,就是把你的公共模塊當(dāng)成 vue 插件注進(jìn)去
假設(shè)注入成這樣

 Vue.prototype.$test= {test1: () => console.log(1), test2: () => console.log(2)}

然后你就可以在任意地方用 this.$test.test1() this.$test.test2() 使用

這樣最后每個單獨(dú)的文件不會包括上面的公用方法,公用方法會被扔到那個全局 app.js里面

補(bǔ)充疑問

假設(shè)入口文件如下

clipboard.png

clipboard.png

打包生成的文件

clipboard.png

這么做 vendor.**.js 一般是不會變的,如果按你后來的解決方案,懶加載路由使用的公用的文件是重新生成一個新文件還是補(bǔ)充到這個文件?如果是改變這個文件的話,我覺得不值得

因?yàn)樽约簩懙霉妙悗焓菚兊?每次都變動加話,代價太大

繼續(xù)補(bǔ)充

新文檔看到了 children 跟 async 一起用是生成新的文件是吧,有機(jī)會試下

2018年7月16日 03:09