@jasw/galaxy-mf
v0.1.0
Published
Module Federation dependency resolution, Result helpers and bundle analysis utilities.
Maintainers
Readme
@jasw/galaxy-mf
@jasw/galaxy-mf 提供一组与 React 解耦、可复用于微前端运行时和构建流程的基础能力:
- 用
Result<T, E>表达可预期的失败,减少远程加载流程中的异常分支; - 按 semver 判断 Host 能否安全共享依赖,并为版本冲突提供明确的隔离信号;
- 在 Webpack 或 Vite/Rollup 构建结束后统计第三方依赖体积和重复情况。
该包不依赖 React,也不负责远程应用渲染;其职责是处理 Module Federation 接入过程中的版本协商、错误建模和构建统计。
维护者:jasw · 许可证:MIT
安装
pnpm add @jasw/galaxy-mf也可以使用 npm:
npm install @jasw/galaxy-mf包内置 TypeScript 类型声明,同时提供 ESM 和 CommonJS 产物。Node.js、Webpack 配置以及 Vite 项目都可以直接使用。
// ESM:从主入口按需导入
import { ok, resolveSharedDependency } from '@jasw/galaxy-mf';
// ESM:通过子路径明确导入某一组能力
import { mapResult, type Result } from '@jasw/galaxy-mf/result';
import { BuildAnalyzerPlugin } from '@jasw/galaxy-mf/build-analyzer';// CommonJS
const { BuildAnalyzerPlugin } = require('@jasw/galaxy-mf');目前公开的子路径如下:
| 子路径 | 内容 |
| ----------------------------------- | --------------------------------- |
| @jasw/galaxy-mf/result | Result 类型及组合函数 |
| @jasw/galaxy-mf/shared-dependency | 共享依赖的 semver 判断和错误类型 |
| @jasw/galaxy-mf/build-analyzer | Webpack、Vite/Rollup 构建分析能力 |
Result:显式处理可预期的失败
Result<T, E> 只有成功和失败两个分支。检查 ok 后,TypeScript 会自动收窄到 value 或 error,不需要类型断言。
import { err, mapResult, ok, type Result } from '@jasw/galaxy-mf/result';
class ParsePortError extends Error {
override readonly name = 'ParsePortError';
}
function parsePort(input: string): Result<number, ParsePortError> {
const port = Number(input);
return Number.isInteger(port) && port > 0
? ok(port)
: err(new ParsePortError(`端口无效:${input}`));
}
const endpoint = mapResult(parsePort('3000'), (port) => `http://localhost:${port}`);
if (endpoint.ok) {
console.log(endpoint.value);
} else {
console.error(endpoint.error.message);
}常用组合函数:
mapResult:转换成功值,失败分支原样向后传递;mapError:给底层错误补充业务上下文;andThen:成功后继续下一步返回Result的计算;isOk/isErr:在过滤、守卫或测试代码中收窄类型;fromThrowable:把同步异常转换成Result;fromPromise:把 Promise rejection 转换成Result。
异步取消仍由实际发起请求的一层负责。fromPromise 只封装结果,不负责创建或触发 AbortController:
import { fromPromise } from '@jasw/galaxy-mf/result';
const controller = new AbortController();
const response = await fromPromise(() =>
fetch('/remote-manifest.json', { signal: controller.signal }),
);
// 页面卸载或路由切换时调用
controller.abort();如果业务需要区分超时、取消和网络错误,建议给 fromPromise 传入错误转换函数,统一成自己的领域错误,而不是直接判断错误文案。
共享依赖版本判断
Module Federation 的 singleton 只能保证共享作用域里尽量只有一个实例,不能让互不兼容的版本变得兼容。尤其是 React,强行让旧版 Remote 使用新版 Host 的运行时,很容易出现 hooks 或 context 错误。
resolveSharedDependency 用完整 Host 版本和 Remote 要求的 semver 范围做判断:
import {
resolveSharedDependencyResult,
type SharedDependencyPolicy,
} from '@jasw/galaxy-mf/shared-dependency';
const policy: SharedDependencyPolicy = {
name: 'react',
hostVersion: '19.0.0',
requiredRange: '^18.0.0',
fallback: 'isolated',
};
const resolution = resolveSharedDependencyResult(policy);
if (!resolution.ok) {
// React 19 不满足 ^18.0.0,加载器应改用 Remote 自己的 React 运行时。
console.warn(resolution.error.code, resolution.error.message);
}这里提供了三种调用方式:
resolveSharedDependency:兼容时返回{ mode: 'shared' },配置非法或版本不匹配时抛出具体错误;resolveSharedDependencyResult:把上述错误包装为Result,适合放进远程加载流水线;resolveSharedDependencyWithFallback:版本不匹配时直接返回{ mode: 'isolated' },但配置非法时仍会抛错。
可识别的错误包括:
| 错误 | code | 含义 |
| ------------------------------------ | ------------------------------------ | ---------------------------------------- |
| InvalidSemverError | INVALID_SEMVER | Host 版本或 Remote 范围不是有效 semver |
| SharedDependencyVersionError | SHARED_DEPENDENCY_VERSION_MISMATCH | 版本合法,但 Host 版本不满足 Remote 范围 |
| InvalidSharedDependencyPolicyError | INVALID_SHARED_DEPENDENCY_POLICY | 依赖名为空或降级策略不受支持 |
判断内部使用 semver.valid、semver.validRange 和 semver.satisfies,时间复杂度约为版本与范围字符串总长度的 O(n)。建议使用完整版本号,例如 19.0.0,不要把 19 或 latest 当作 hostVersion。
BuildAnalyzerPlugin:查看依赖体积和重复打包
该插件用于分析第三方依赖在各个 chunk 中的分布。它不会修改分包策略,也不会因为统计信息不完整而阻断构建。
Webpack
const { BuildAnalyzerPlugin } = require('@jasw/galaxy-mf');
module.exports = {
plugins: [new BuildAnalyzerPlugin({ app: 'checkout-remote' })],
};插件通过 compiler.hooks.done 读取 Webpack stats,所以应放在普通 plugins 数组中,不需要额外调用。
Vite / Rollup
import { defineConfig } from 'vite';
import { BuildAnalyzerPlugin } from '@jasw/galaxy-mf/build-analyzer';
export default defineConfig({
plugins: [new BuildAnalyzerPlugin({ app: 'shared-utils' }).asRollupPlugin()],
});Vite/Rollup 需要使用 asRollupPlugin()。这个适配器只暴露 Rollup 所需的 hook,避免构建工具误处理 Webpack 专用的 apply 方法。
构建结束后会通过 console.table 输出:
| 字段 | 含义 |
| ------------ | -------------------------------------------------- |
| app | 创建插件时传入的应用名 |
| dependency | 从 node_modules 或 pnpm .pnpm 路径解析出的包名 |
| bytes | 该依赖在统计数据中的累计字节数 |
| percentage | 占当前应用全部第三方依赖体积的比例 |
| chunks | 依赖出现过的 chunk |
| duplicate | 同一依赖是否出现在多个 chunk 中 |
duplicate: true 是排查线索,不一定就是错误。动态路由、Remote 独立运行时或构建工具生成的公共 chunk 都可能让同一包出现在多个位置,仍需要结合实际加载链路判断。
聚合 M 个模块、P 个第三方包的复杂度为 O(M + P),输出前的稳定排序额外需要 O(P log P)。
在仓库中开发
源码和测试分别位于:
packages/shared-utils/src/
packages/shared-utils/tests/在仓库根目录执行:
# 构建 ESM、CJS 和类型声明
pnpm --filter @jasw/galaxy-mf build
# 运行测试并检查覆盖率
pnpm --filter @jasw/galaxy-mf test:coverage
# 查看实际会进入 npm 包的文件
pnpm --filter @jasw/galaxy-mf pack --dry-runpack 会先重新构建,并用 TypeScript 的 NodeNext 模式检查生成的声明文件,避免发布后才发现 ESM
相对导入不兼容。
改动公共 API 时,请同步检查根入口和对应子路径的导出,并补充测试。这个包刻意不绑定 React 或具体的 Federation 容器实现,新增能力也会优先维持这一边界。
维护
该包由 jasw 维护。完整的 React 19 Host、React 18/17 Remote、隔离挂载和预加载示例见项目仓库。维护者发布新版本时应遵循仓库中的 RELEASING.md。
