module federation,monorepo分不清楚?

一代版本一代神,现代的前端已经不是会用一个react就能混过去的了,虽然正式工作上还是打螺丝,调包侠+切图仔,但是有些时候,新知识不可不学。 有两个概念近些年很火,一个是module federation一个是monorepo,光看名字可能觉得有点像,但是其实是两个东西。

模块联邦module federation

这是webpack在v5被投入生产,并作为v5的核心特性之一。它的出现解决了一些问题,或者说它适用于以下场景:

  1. 微前端架构:实现独立部署的子应用动态集成(如电商平台的首页、商品页拆分)。
  2. 大型应用拆分:逐步重构单体应用,降低维护成本。
  3. 跨团队代码共享:避免重复发布 npm 包,直接运行时复用模块。

基本上可以说他是微前端的方式。当然市面上肯定大部分工具也会跟上webpack,比如vite就通过rollup钩子实现了(vite-plugin-federation),又比如@module-federation/rollup插件,next-mf插件,Rspack(基于webpack)。 接下来看下他的主要配置

主应用webpack.config.js:

css 复制代码
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = {
  ...
  plugins: [
    new ModuleFederationPlugin({
      name: 'host',
      remotes: {
        app1: 'remote@http://localhost:3001/app1Entry.js', // 子应用地址
      },
      shared: { 
        react: { singleton: true }, 'react-dom': { singleton: true }                 },
    }),
  ],
};

这里看到了一个shared配置singleton,指明了哪些模块应该作为单例共享,也就是单例模式,true的话父子应用共用一个实例,避免重复加载,但是当插件需要完全隔离的依赖如react环境时,可以设置成false;

remotes字段指定了远程微应用的名称和其远程入口文件URL。 当主应用需要用到子应用的玩意时,如下:

javascript 复制代码
// 动态加载子应用的Button组件 
const RemoteButton = React.lazy(() => import('app1/Button'));

子应用webpack配置

less 复制代码
const { ModuleFederationPlugin } = require('webpack').container; module.exports = { 
    entry: './src/moduleOutput.js', // 必须通过moduleOutput.js间接引入 
    plugins: [ 
        new ModuleFederationPlugin({ 
            name: 'app1', // 子应用名称(全局唯一) 
            filename: 'app1Entry.js', // 入口文件名(默认),模块清单名
            exposes: { 
                './Button': './src/Button.js', // 暴露组件路径 
            }, 
            shared: { 
                react: { singleton: true }, 'react-dom': { singleton: true } 
            },             
        }), 
    ], 
};
go 复制代码
// moduleOutput.js
import('./index'); // 延迟加载业务代码

注意,这里我们看到entry不是我们平时项目脚手架自带的index.js/ts,而是通过其他文件moduleOutput.js,这个文件的存在是为了正确执行模块联邦的动态加载机制和代码执行顺序,而主要导致这样的原因是:

  1. 主应用加载子应用时,会先下载app1Entry.js模块清单文件,然后在按需加载子模块,比如exposes中的Button,如果子应用直接以index.js作为entry,可能会在子应用的子模块模块被主应用加载时,子应用的依赖(如react)未准备就绪,毕竟子应用也是配置了按需加载,这就会导致运行错误
  2. app1Entry.js这文件的作用就是延迟执行,通过动态导入(import())将子应用的业务代码(如 index.js)的加载推迟到 所有共享依赖(如 React)已就绪后 。 当然,如果父子应用没有共享的模块,那么这个文件也就没必要了,另外shared的依赖中,有一个requiredVersion字段,可以让父子协商是否共享模块。

monorepo

这其实不是具体工具,而是一种思想:强关联性,同一业务线的项目,可以将项目放在同一个版本管理工具中(比如git),这么做的好处有很多,比如

  1. 代码共享与复用,一些公共的ts定义,和api接口层,组件能直接引用,并且所有项目共用顶层node_modules,减少重复依赖安装(通过workspaces功能)
  2. 统一工程化配置,比如eslint,pritter,jest和webpack等构建工具等,这会让维护成本降低。
  3. 统一版本管理,通过changesets等工具自动化版本号和changeLog管理
  4. 版本提交的完整性,当修改底层库时,可同时更新依赖他的所有应用,这保证了提交的完整性
  5. 依赖关系可视化,可用preune等命令工具生成关系图,便于框架优化
  6. 统一CI配置,所有项目共用一套CI/CD流程 当然也不是所有业务线都要这么做,这适用于部分场景:
  7. 微前端架构
  8. 全栈项目(对我来说当然是js的全栈)
  9. 多应用平台,比如pc,mobile共用业务逻辑
  10. 大型团队协作,减少代码碎片化
  11. 替代npm的频繁更替 常用来实现monorepo的工具有pnpm,lerna,turborepo,我一般使用pnpm

总结

这么一盘,好像两者也不是毫无联系,这都和微前端扯到了关系,但是两者场景并不是非常一致,且手段不同。最共同的点是,他们都是要学的东西。

相关推荐
Jinuss4 小时前
源码分析之React中createFiberRoot方法创建Fiber根节点
前端·javascript·react.js
liux35285 小时前
MySQL集群架构:MySQL InnoDB Cluster (MIC)详解(十一)
数据库·mysql·架构
Jinuss5 小时前
源码分析之React中ReactDOMRoot实现
前端·javascript·react.js
无心水5 小时前
微服务架构下Dubbo线程池选择与配置指南:提升系统性能与稳定性
java·开发语言·微服务·云原生·架构·java-ee·dubbo
web守墓人5 小时前
【前端】vue3的指令
前端
Warren2Lynch5 小时前
AI赋能企业架构:TOGAF智能建模新时代
人工智能·架构
想起你的日子6 小时前
EFCore之Code First
前端·.netcore
框架图6 小时前
Html语法
前端·html
深耕AI6 小时前
【wordpress系列教程】07 网站迁移与备份
运维·服务器·前端·数据库
猎人everest6 小时前
Spring Cloud Alibaba 微服务架构拆分api和server的必要性
运维·微服务·架构