vue或webpack如何使得lib包內(nèi)部的component支持懶加載

首先場(chǎng)景如下:

  1. 構(gòu)建一個(gè)lib包,內(nèi)含多個(gè)vue組件,父工程通過Vue.use方式進(jìn)行全局引入
  2. 由于組件可能會(huì)很多很大,所以想實(shí)現(xiàn)這個(gè)lib包里面的組件實(shí)現(xiàn)懶加載
  3. 初步設(shè)想的是采用動(dòng)態(tài)導(dǎo)入(dynamic imports)實(shí)現(xiàn)懶加載
  4. (element-ui的按需加載方式好像是通過babel-component-plugin將未使用的component標(biāo)記后,通過tree shaking優(yōu)化掉的,所以不適合這里的懶加載)

lib包代碼:

function install (Vue, options) {
  Vue.component('d2p-file-uploader', () =>import('./lib/file-uploader'))
  Vue.component('d2p-images-format', () =>import('./lib/images-format'))
}

打包出來是這個(gè)樣子:

看上去還不錯(cuò),成功按照懶加載的方式打成多個(gè)chunk了


image.png

但是,引用這個(gè)lib之后,報(bào)如下錯(cuò)誤:

Uncaught SyntaxError: Unexpected token <
vue.runtime.esm.js:619 [Vue warn]: Failed to resolve async component: function(){return t.e(3).then(t.bind(null,"50bf"))}
Reason: ChunkLoadError: Loading chunk 3 failed.
(missing: http://localhost:8080/d2p-extends.umd.min.3.js)

為啥會(huì)報(bào)這個(gè)錯(cuò)呢:

仔細(xì)看上面的錯(cuò)誤是懶加載50bf這段chunk的時(shí)候,d2p-extends.umd.min.3.js這個(gè)文件找不到
其實(shí)因?yàn)閐2p-extends.umd.min.3.js這段js是在lib里面的,而引用它的父工程打包出來的js是這樣的


image.png

lib包里面懶加載分離出來的chunk并沒有按照原來的名字復(fù)制到父工程的dist/js目錄下面
所以這種lib的打包方式并不能實(shí)現(xiàn)lib里面的component懶加載

然后baidu、google、Stack Overflow、github一通查:

最后在webpack的issue上查到了一些對(duì)于這個(gè)問題的討論

https://github.com/webpack/webpack/issues/2471

該問題被標(biāo)記為困難,16年問題就提出來了,18年1月關(guān)閉時(shí)候都沒有解決,看來這個(gè)需求實(shí)現(xiàn)還是真的挺麻煩的


image.png

然后18年9月又被人打開了,至今未解決
https://github.com/webpack/webpack/issues/6818

image.png

所以結(jié)論是目前為止webpack暫時(shí)不支持lib里的動(dòng)態(tài)導(dǎo)入方式的懶加載

但是Stack Overflow上提到了一個(gè)解決方案

https://stackoverflow.com/questions/54149892/webpack-cannot-resolve-node-modules-lazy-assets

image.png

簡(jiǎn)單來說,就是通過源碼方式導(dǎo)入,而不是dist/xxx.umd.js導(dǎo)入。
這樣就相當(dāng)于把lib包放到父工程里面去重新打包,就跟你把lib包里面的源代碼復(fù)制到你的父工程里面一樣。(只是這樣就要求父工程與lib的eslint配置要一致,可以通過設(shè)置忽略來解決)

所以拋棄dist通過src方式引入即可獲得懶加載功能

1、方式一:lib包里面的package.json的main改成 'src/index'

{
"main": "src/index"
}

2、方式二:父工程import src目錄

 import componentName from 'subLibName/src'

懶加載效果

項(xiàng)目地址:https://github.com/greper/d2-crud-plus
示例地址:http://qiniu.veryreader.com/D2CrudPlusExample/index.html#/form/uploader

lazyloading3.gif

最后幾個(gè)附加題

1. 如果這個(gè)lib還想提供給那些不追求懶加載的人通過dist方式引用呢?

因?yàn)槲覀兤鋵?shí)并沒有解決dist引入時(shí)發(fā)生的ChunkLoadError: Loading chunk 3 failed錯(cuò)誤
要解決這個(gè)問題,就是不讓他打包成多個(gè)chunk
翻遍了vue-cli的文檔,發(fā)現(xiàn)沒有什么簡(jiǎn)單的方法關(guān)閉它。
然后去webpack去找,最后找到一個(gè)插件“LimitChunkCountPlugin”,它本是一個(gè)用來優(yōu)化合并小chunk的插件,但是它有一個(gè)maxChunks參數(shù),可以限制最大chunk數(shù)量,把它設(shè)置為1就可以實(shí)現(xiàn)不打包成多個(gè)chunk的目的了。

vue.config.js 中配置如下插件即可

const webpack = require('webpack')
const plugins = [new webpack.optimize.LimitChunkCountPlugin({
  maxChunks: 1,
  minChunkSize: 1000
})]
module.exports = {
  configureWebpack: {
    plugins: plugins
  }
}

2. 既然報(bào)的錯(cuò)誤是懶加載的chunk下載不到,寫個(gè)插件從lib里面把相關(guān)的chunk復(fù)制出來是不是也可以?

理論上確實(shí)可以,我試過手動(dòng)從lib里面把chunk復(fù)制出來放到父工程打包后的/js/目錄下,部署執(zhí)行完全沒有問題。
這個(gè)方式可以解決源碼導(dǎo)入的缺陷(父工程與lib之間eslint配置要求一致的問題)
這樣的插件寫起來應(yīng)該蠻簡(jiǎn)單。
但這樣一來就要求父工程一定要配置這個(gè)自定義的復(fù)制插件,使得這個(gè)lib的應(yīng)用受到一定的限制。

3. 更好的辦法

更好的辦法是將lib根據(jù)第1點(diǎn)打包成單個(gè)chunk,然后寫個(gè)插件,父工程在build的時(shí)候通過這個(gè)插件將lib拆分,把懶加載的模塊提取出來,寫到新的chunk里面。
這種方式即不破壞lib的通用性,又實(shí)現(xiàn)了lib組件的懶加載。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容