monorepo中如何共享bundle

monorepo中如何共享bundle

在monorepo中的多个app,由于它们的npm 包都是在最顶层的workspace 管理安装的,在编译各个子应用的时候,为了节省bundle的大小,如何才能将每个应用中公用的vendor bundle 抽出来。本篇就是基于此对webpack的一些探讨

借助optimization>splitChunks 来将某些包单独编译成vendor bundle

{
    optmization:{
        runtimeChunk:{
            name:'runtime',
        },
        splitChunks:{
            cacheGroups:{
                vendor:{
                    test: /[\\/]node_modules[\\/]/,
                    name:'vendor',
                    chunks:'all',
                    enforce:true,
                }
            }
        }
    }
}

如上所诉,将node_modules里面的包单独编译成vendor, 由于在monorepo 中每个子应用的依赖的包都是一样的,这个思路看似可行。但是有以下几个问题

  • 摇树的存在
    • 尽管子应用的依赖是一致的,但是子应用对于同样的包使用的程度是不一致的,所以在prod 编译的时候,摇树会将公用的包给摇掉,可能会造成其他的子应用炸掉
  • 一个子应用产生的vendor,它在window里面是通过子应用的名字来管理的,例如self['app1']={xxx}, 所以这个vendor bundle哪怕没有摇掉,也无法直接被其他应用直接引用
(self["appbunlde"]=self["appbundle"]||[]).push([['bundle'],{...modules}]);

既然一个子应用的vendor不能被其他的应用共享,那就创建一个commonapp,它的职责就是将公用的包困扎在一起,然后子应用直接用它不久行了。这么一些确实可行。

//inex.js
import * as ModuleA from 'moduleA';
import * as ModuleB from 'moduleA/sub';

// webpack.config.js
{
    output:{
        library:{
            name:'vendor',
            type:'umd',
        }
    }
}

// webpack 的输出里面有如下的片段

(function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory();
	else if(typeof define === 'function' && define.amd)
		define([], factory);
	else if(typeof exports === 'object')
		exports["vendor"] = factory();
	else
		root["vendor"] = factory();
})(self,()=>{
    /// xxxx 省略一大坨
    __webpack_require__.d(__webpack_exports__, {
    ModuleA: () => (),
    ModuleB: () => ()
    });

    return __webpack_exports__;
})
//############################################################其他应用####################################
// index.js 其他应用里
import some from 'moduleA';
import other from 'moduleA/sub';

// 在使用这个bundle 的应用里面的webpack 配置

{
    externals:{
        'moduleA':'vendor.ModuleA',
        'moduleA/sub':'vendor.ModuleB',
    }
}

// 这个是对应到bundle 里面的改动,它还可以有其他的配置,自己体会吧
{
    'moduleA':(module,exports,__webpack_require_)=>{
        exports = vendor.ModuleA;
    },
    'moduleA/sub':(module,exports,__webpack_require_)=>{
        exports = vendor.ModuleB;
    },
}



确实ModuleA,ModuleB 被困扎到一起了。那么问题来了,为啥需要困扎呢。如果ModuleA,ModuleB有CDN文件的化,直接copy/paste, 就可以将他们合成一个文件。何须用webpack.

感觉折腾了个寂寞

为什么我们需要webpack, 是为了在一个app 内部,将所需要的package 或者说 import/require 等语法中所引用的文件整合到一个大的文件中。然后再压缩。它本质上解决的是代码之间的捆绑,如果我们想把同样的代码先捆绑成bundle,然后再消费这个bundle,这个时候就不是webpack 的活了。因为webpack 这个时候只是留下了接口去兼容外面的bundle,并没有捆绑他们,所以。我们完全可以手动的将一些包裹文件整合一起。

posted @   kongshu  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示