qiankun icon indicating copy to clipboard operation
qiankun copied to clipboard

[Feature Request] qiankun 如何复用公共依赖

Open gongshun opened this issue 4 years ago • 16 comments

Background

如果主项目和子项目都用到了同一个版本的 vue/vuex/vue-router 等,主项目加载一遍之后,子项目又加载一遍,就很浪费。

要想复用公共依赖,前提条件是子项目必须配置externals,这样依赖就不会打包进chunk-vendors.js,才能复用已有的公共依赖。

按需引入公共依赖,有两个层面:

  1. 没有使用到的依赖不加载
  2. 大插件只加载需要的部分,例如 elementUI 组件库的按需加载、echarts/lodash的按需加载。

Proposal

巨无霸应用的公共依赖和公共函数被太多的页面使用,导致升级和改动困难,使用微前端可以让各个子项目独立拥有自己的依赖,互不干扰。而我们想要复用公共依赖,这与微前端的理念是相悖的。

所以我的想法是:父项目提供公共依赖,子项目可以自由选择用或者不用。

这个也很好实现,父项目先加载好依赖,然后在注册子项目时,将vue/vuex/vue-router等通过 props 传过去,子项目可以选择用或者不用。

这样做不太可行,原因有两个:

  1. 子项目独立运行时,VueRouter/Vuex这些依赖从哪里来?子项目是只部署一份的,既可以独立运行,也可以被 qiankun 集成。
  2. 父项目只能传递它自己已经有的依赖,如何确定子项目需要哪些依赖?不满足按需引入的需求

要想实现按需引入依赖,配置webpackexternals 是必须的,而配置了这个之后,子项目独立运行时,这些依赖的来源有且仅有 index.html 中的外链 script 标签。

在这个前提下,能否做到,子项目和主项目的vue版本一致的情况下,使用同一份服务器文件。即使无法共享,也是可以做http缓存的。

那么 qiankun 能否做到,某个依赖加载了之后,不再加载,直接复用呢?比如说子项目A请求了服务器上的2.6版本vue,切换到子项目B,B项目也用了这个vue文件,能否不再次加载,直接复用呢?

其实是可以的,可以看到 qiankun 将子项目的外链 script 标签,内容请求到之后,会记录到一个全局变量中,下次再次使用,他会先从这个全局变量中取。这样就会实现内容的复用,只要保证两个链接的url一致即可。

所以只要子项目配置了webpackexternals,并在 index.html 中使用外链 script 引入这些公共依赖,只要这些公共依赖在同一台服务器上,便可以实现子项目的公共依赖的按需引入,一个项目使用了之后,另一个项目使用不再重复加载,可以直接复用这个文件。

Additional context

虽然 qiankun 不会重复请求相同 url 的公共依赖,但是这也仅比 http 缓存强了一丢丢。

有缺陷的地方在于:

  1. 主项目中的公共依赖没有记录到这个缓存中,也就不会被其他的项目复用
  2. 只是没有重复请求,还是需要重复执行一次。能否不执行,直接复用?js沙箱在子系统卸载时,会移除 window上新增的变量,而webpackexternals恰恰是将这些公共依赖挂载在 window上,能否看情况移除这些公共依赖?
  3. 相同版本的依赖会复用,版本不同但是使用无差别,能否做到也复用?(版本不同url也就不同,就不会复用)

gongshun avatar Jun 02 '20 06:06 gongshun

补充一点:如果子项目需要复用主项目的依赖,只需要给子项目 index.html 中公共依赖的 scriptlink 标签加上 ignore 属性(这是自定义的属性,非标准属性)。

有了这个属性,qiankun 便不会再去加载这个 js/css,而子项目独立运行,这些 js/css 仍能被加载,如此,便实现了“子项目复用主项目的依赖”。

<link ignore rel="stylesheet" href="//cnd.com/antd.css">
<script ignore src="//cnd.com/antd.js"></script>

需要注意的是,主项目中的公共依赖需要暴露出来(挂载到 window 上),且需要和子项目版本保持一致。

gongshun avatar Jun 29 '20 06:06 gongshun

补充一点:如果子项目需要复用主项目的依赖,只需要给子项目 index.html 中公共依赖的 scriptlink 标签加上 ignore 属性(这是自定义的属性,非标准属性)。

有了这个属性,qiankun 便不会再去加载这个 js/css,而子项目独立运行,这些 js/css 仍能被加载,如此,便实现了“子项目复用主项目的依赖”。

<link ignore rel="stylesheet" href="//cnd.com/antd.css">
<script ignore src="//cnd.com/antd.js"></script>

需要注意的是,主项目中的公共依赖需要暴露出来(挂载到 window 上),且需要和子项目版本保持一致。

image 这是我目前提取的公共依赖,公共的都好说,就是自己的pk-view是自己封装的组件,但无法将其挂载在window上,vuecli的--target lib和--target wc好像无法实现,楼主方便解惑吗

cpa0701 avatar Aug 13 '20 05:08 cpa0701

是我目前提取的公共依赖,公共的都好说,就是自己的pk-view是自己封装的组件,但无法将其挂载在window上,vuecli的--target lib和--target wc好像无法实现,楼主方便解

pk-view 是只有一个组件吗,还是很多个组件。配一个环境变量,可以单独对他进行一次打包,入口文件就是这个组件,很多个组件就单独写一个 index.js ,导出这些组件,然后 --target lib 就可以了

gongshun avatar Aug 13 '20 06:08 gongshun

是我目前提取的公共依赖,公共的都好说,就是自己的pk-view是自己封装的组件,但无法将其挂载在window上,vuecli的--target lib和--target wc好像无法实现,楼主方便解

pk-view 是只有一个组件吗,还是很多个组件。配一个环境变量,可以单独对他进行一次打包,入口文件就是这个组件,很多个组件就单独写一个 index.js ,导出这些组件,然后 --target lib 就可以了

组件库,我可能问的问题不对,不过还是谢谢啦

cpa0701 avatar Aug 13 '20 07:08 cpa0701

求一个复用公共依赖的demo

WhisperYq avatar Dec 15 '20 13:12 WhisperYq

建议参考systemjs + webpack externals

uWydnA avatar Dec 21 '20 05:12 uWydnA

请问楼主

  1. 上面说的props传递的方式,不可行的原因1没太理解,子应用为啥会有单独运行的场景呢,是因为业务特色嘛
  2. 最终楼主有解决方案嘛,求分享~

humorHan avatar Jul 21 '21 07:07 humorHan

公共的组件,是否也可以跟公共依赖一样呢?封装成npm包后,通过script的方式引入并设置ignore?

xiejiaxin007 avatar Sep 12 '21 13:09 xiejiaxin007

公共的组件,是否也可以跟公共依赖一样呢?封装成npm包后,通过script的方式引入并设置ignore?

可以的

gongshun avatar Sep 13 '21 01:09 gongshun

公共的组件,是否也可以跟公共依赖一样呢?封装成npm包后,通过script的方式引入并设置ignore?

可以的

那比如一些不方便封装成npm包的业务组件,比如依赖了axios、moment等第三方包的组件,我该怎么处理呢?是单独放子应用进行解耦?还是主应用传递给子应用?

xiejiaxin007 avatar Sep 13 '21 01:09 xiejiaxin007

那比如一些不方便封装成npm包的业务组件,比如依赖了axios、moment等第三方包的组件,我该怎么处理呢?是单独放子应用进行解耦?还是主应用传递给子应用?

这些组件,主应用直接挂 window 上,子应用能读取到,至于这些组件的依赖(axios、moment等),可以由组件引入

gongshun avatar Sep 13 '21 02:09 gongshun

那比如一些不方便封装成npm包的业务组件,比如依赖了axios、moment等第三方包的组件,我该怎么处理呢?是单独放子应用进行解耦?还是主应用传递给子应用?

这些组件,主应用直接挂 window 上,子应用能读取到,至于这些组件的依赖(axios、moment等),可以由组件引入

主应用挂window上,那是不是子应用独立开发的时候,需要把主应用也运行起来

xiejiaxin007 avatar Sep 13 '21 02:09 xiejiaxin007

search 到这个 问题,想要讨论一下 公共依赖的版本是如何管理的,要如何控制公共依赖的升降级呢?

wangcheng007 avatar Aug 22 '22 07:08 wangcheng007

DllReferencePlugin+libDll.js

Feahter avatar Jan 07 '24 14:01 Feahter

请问下楼主是否有了最终的解决方案,可以分享一下么

hujingyuki avatar Mar 13 '24 12:03 hujingyuki

请问下楼主是否有了最终的解决方案,可以分享一下么

就主应用下发不是挺好的吗? 静态资源就cdn

humorHan avatar Mar 13 '24 13:03 humorHan