5-打造属于你的组件库-【模块联邦】

1. 前言

模块联邦Webpack5 的新功能,实现了跨应用的共享模块,在之前我们一般会使用 NPM 的方式去共享模块。

NPM 组件库
 - 优势:
    比较常用的方式,也便于版本管理,TS支持友好
 - 不足:
     模块升级,使用了该模块的项目,也需要一起升级才能使用最新的模块

使用 NPM 包方式,就意味着如果 NPM 包升级,那么项目里的使用的包也需要升级重新构建,而模块联邦可以让模块在项目之间利用 CDN 共享,从此便不需要在项目中本地安装,构建,发布了

那么模块联邦又和传统的 CDN 方式引入有何区别?

CDN/UMD 全局引入
 - 优势:
    运行时加载,简单规划一下,也可以做到版本控制
 - 不足:
    TS类型支持不友好
    一般是直接引入 script 标签,会一次性加载模块的所有资源
    需要考虑依赖加载顺序

这两者在我看来,有些类似,都是从远程加载资源共享,但 模块联邦 可以标识出需要 exposes(导出) 的模块,可以根据你的需求去引入。可以在项目页面中需要的地方再去加载,相比 CDN/UMD 来说更灵活。

2. 个人感受

先简述下结论,真正使用的话,需要考虑

  • 模块的 TS 类型共享问题(听说有解决方法,日后在瞅瞅)

  • 虽然做到了项目共享,但有些项目需要低版本的模块,这边可能需要开发者做中间层去处理版本问题

  • 随意升级模块,如果模块有个没测试出来的隐藏 BUG,有可能导致使用模块的项目炸裂。

3. 模块联邦的使用

模块联邦两个概念: Host(消费者)Remote(被消费),同时,每个项目即可以是 Host 也可以是 Remote。其本身只是一个 Webpack 的插件 ModuleFederationPlugin

  • 属性

    • name : 该模块的名字
    • filename : 模块编译后生成的入口文件名,如果没设置,会根据 name 生成
    • remotes : 当模块为 Host 时使用,用来设置可以被导入的模块
    • exposes : 当模块为 Remote 时使用,用来设置模块中的哪些部分可以被导出给 Host 使用
    • shared : 强制远程 Remote 模块使用主模块 Host 的依赖项,当主模块没有该依赖项时,会直接使用远程模块自身的依赖
  • 使用时遇到的坑

  1. 使用 HtmlWebpackPlugin 自动导入的 js 没有加上 type='module' 导致浏览器启动时,ES6 模块导出报错

    // `HtmlWebpackPlugin` 添加 `chunks` 选项
    new HtmlWebpackPlugin({
    template: './src/index.html',
    filename: 'index.html',
    chunks: ['main.js', 'remote.js'],
    })
    
    //   html模板 那添加自己设置的 `script` 标签解决
    <% for (var chunk in htmlWebpackPlugin.options.chunks) { %>
    <script type="module" type="text/javascript" src="<%=htmlWebpackPlugin.options.chunks[chunk] %>"></script>
    <% } %>
    
  2. 引入远程模块,跨域问题

    // webpack.config.js
    devServer: {
       port: 4001,
       headers: {
         // 利用CORS解决跨域
         'Access-Control-Allow-Origin': 'http://localhost:4000',
       },
     }
    
  3. host_appremote_app 测试失败,没分析出具体原因,测了好多回

    网上查了很多解决方法,有说 splitChunk 的,也有说 runtime 的,一个一个试了都没用,QAQ
    暂时放弃 webpack + js 的方式去测试,转实 vite 的模块联邦


Vite 的模块联邦

1. vite-plugin-federation

Vite 模块联邦 Github 支持模块联邦 的 Vite/Rollup 插件,可以与 Webpack Module Federation 兼容。

# 安装
yarn add @originjs/vite-plugin-federation --dev

2. 使用

配置基本和 Webpack 模块联邦类似, remotes 略微不同,在 vite 里,无需添加 name@ 的前缀

export default defineConfig({
  plugins: [
    // ...otherConfig
    federation({
      remotes: {
        // 这里的 value 不同于 webpack, 没有 name@ 的前缀
        remote_vite: 'http://localhost:3333/assets/remoteEntry.js'
      }
    })
  ],
  build: {
    target: 'esnext'
  }
})

3. 注意事项

由于 Vite按需编译的,所以你在本地测试的时候,开启两个开发环境是没有用的Host可以在本地启动,但 Remote 需要先部署在线上。

可为了测试一个项目,就部署,太麻烦了,所以这里可以使用 vite preview 的方式去模拟 Remote 的部署

// preview 是基于 build 之后的文件的,所以在此之前需要先 build 一次
// 由于是测试项目,我就直接在 script 里增加了 yarn build 的代码。然后用 preview 模拟 3333 端口
"preview": "yarn build & vite preview --port 3333"

完成上述操作,即可打开 Host(可以开发环境开启) 查看效果。。。

为什么 Vite 开启两个开发环境会失效呢?

因为 Vite 按需编译的特性,在开发模式下使用的是 esbuildno-bundle 的特性,在启动时,只需要预编译依赖,随后项目启动,进入 index.html ,随即发起 http 请求获取当前所需的资源。

所以你无法在开发环境下找到 remoteEntry.js 的资源。。个人感觉这个可以优化,期待插件后续更新。

而,当你 build 打包之后,在你的项目下就会有 remoteEntry.js 资源了,那么便可以直接访问 http://localhost:3333/assets/remoteEntry.js

原文链接:https://juejin.cn/post/7237531176587313212 作者:pnm学编程

(0)
上一篇 2023年5月28日 上午10:46
下一篇 2023年5月28日 上午10:56

相关推荐

发表回复

登录后才能评论