观测插件

观测插件用于让 Module Federation 加载过程可观测。它会记录运行时加载事件,整理最终加载结果,并在加载失败时打印稳定的 traceId。构建侧信息由构建观测插件单独写出。

该插件面向 Module Federation 2.5.0 及以上版本。如果项目还在更早的 MF 版本,仍然可以先用运行时错误码做基础排查;但更完整的报告和加载观测链路需要升级到 2.5.0+ 并启用这个插件。

它适合回答这些问题:

  • 这个 remote 是否真的加载成功?
  • 失败发生在 manifest、remoteEntry、init、expose、factory 还是 shared?
  • 这次加载是否通过 retry 或 fallback 恢复了?
  • 这次命中了哪个 shared provider 和版本?
  • 应该把哪份报告交给人或 AI coding agent 排查?

安装

npm install @module-federation/observability-plugin

Browser

浏览器运行时使用默认入口。开发环境和生产环境的接入方式一样,区别只在于传给 ObservabilityPlugin 的参数。

Build Plugin(使用构建插件)
Pure Runtime(未使用构建插件)

如果应用已经通过构建插件注册 Module Federation,推荐用 runtimePlugins 注入观测插件。

先创建一个运行时插件文件:

mf-observability-runtime-plugin.ts
import { ObservabilityPlugin } from '@module-federation/observability-plugin';
import type {
  ObservabilityPluginOptions,
  ObservabilityController,
} from '@module-federation/observability-plugin';

let observability: ObservabilityController | undefined;

export function getObservability() {
  return observability;
}

export default function mfObservabilityRuntimePlugin(
  options: ObservabilityPluginOptions = {},
) {
  observability = ObservabilityPlugin(options);

  return observability.plugin;
}

然后在 Module Federation 构建配置中注入它:

module-federation.config.ts
import path from 'node:path';

export default {
  name: 'runtime_host',
  remotes: {
    remote1: 'remote1@https://example.com/mf-manifest.json',
  },
  runtimePlugins: [
    [
      path.resolve(__dirname, './mf-observability-runtime-plugin.ts'),
      {
        level: 'verbose',
        browser: {
          enabled: true,
          scope: 'runtime_host',
        },
      },
    ],
  ],
};

如果业务代码需要主动标记组件加载成功,可以从同一个插件文件导入 getObservability()

import { getObservability } from './mf-observability-runtime-plugin';

getObservability()?.markComponentLoaded({
  requestId: 'remote1/Button',
  componentName: 'Button',
});

开发和生产参数

当 Module Federation 加载失败时,插件会打印一条简短的 console.error

[Module Federation] Observability report generated
traceId: mf-...
phase: manifest
errorCode: RUNTIME-003
read: window.__FEDERATION__.__OBSERVABILITY__["runtime_host"].getReport("mf-...")

在浏览器控制台执行 read: 后面的命令,就能拿到完整报告。

也可以直接读取:

window.__FEDERATION__.__OBSERVABILITY__.runtime_host.getLatestReport();
window.__FEDERATION__.__OBSERVABILITY__.runtime_host.getReport('mf-...');
window.__FEDERATION__.__OBSERVABILITY__.runtime_host.getReports({ limit: 5 });
window.__FEDERATION__.__OBSERVABILITY__.runtime_host.findReports({
  remote: 'remote1',
});
window.__FEDERATION__.__OBSERVABILITY__.runtime_host.exportReport('mf-...');

开发环境通常打开浏览器读取入口,方便人或 AI coding agent 直接读取报告:

mf-runtime.ts
import { ObservabilityPlugin } from '@module-federation/observability-plugin';

export const observability = ObservabilityPlugin({
  level: 'verbose',
  browser: {
    enabled: true,
    scope: 'runtime_host',
  },
});

生产环境仍然使用同一个插件,只是参数更保守:console 只保留 traceId 和已知 errorCode,完整报告通过业务自己的系统上报。

mf-runtime.ts
import { ObservabilityPlugin } from '@module-federation/observability-plugin';

export const observability = ObservabilityPlugin({
  level: 'summary',
  browser: {
    enabled: true,
    scope: 'runtime_host',
    mode: 'production',
  },
  onReport(report) {
    if (report.status === 'error' || report.summary.outcome === 'recovered') {
      navigator.sendBeacon(
        '/api/mf-observability',
        JSON.stringify({
          traceId: report.traceId,
          status: report.status,
          diagnosis: report.diagnosis,
          summary: report.summary,
          remote: report.remote,
          shared: report.shared,
          moduleInfo: report.moduleInfo,
        }),
      );
    }
  },
});

生产环境浏览器模式下,console 只包含 traceId 和已知 errorCode。完整报告应通过 onReportexportReport() 或业务自己的上报系统获取。

Browser 参数

ObservabilityPlugin(options) 支持以下参数:

参数类型默认值说明
enabledbooleantrue是否启用观测插件。关闭后不记录事件、不生成报告。
level'summary' | 'verbose''summary'报告详细程度。summary 保留摘要和关键事件,verbose 保留完整事件时间线。
maxEventsnumber内置上限单个插件实例最多保留的事件数量,避免长时间运行时无限增长。
consolebooleantrue加载失败时是否打印 console.error 提示。
printRawStackbooleanfalse是否把原始错误栈打印到 console。默认关闭,避免生产环境输出过多细节。
stackTrace.enabledbooleantrue是否在报告中保存裁剪后的错误栈。
stackTrace.maxLinesnumber内置上限错误栈最多保留多少行。
stackTrace.maxLengthnumber内置上限错误栈最多保留多少字符。
browser.enabledbooleanfalse是否把读取入口挂到 window.__FEDERATION__.__OBSERVABILITY__
browser.scopestringhost 名称浏览器读取入口的命名空间,例如 runtime_host
browser.mode'development' | 'production''development'浏览器输出模式。生产模式下 console 只输出最小提示。
onEvent(event, report, context) => voidundefined每次记录观测事件时触发,适合接入自定义日志系统。
onReport(report, context) => voidundefined报告更新时触发,生产环境常用它上传失败或恢复报告。
onRawError(error, context) => voidundefined捕获原始错误对象时触发,适合接入业务自己的错误系统。

生产环境推荐至少设置:

ObservabilityPlugin({
  level: 'summary',
  browser: {
    mode: 'production',
  },
  onReport(report) {
    // 上传到业务自己的系统
  },
});

Node 或 SSR 运行时

需要本地观测文件时,使用 Node 专用入口。

mf-node-runtime.ts
import { createInstance } from '@module-federation/runtime';
import { ObservabilityPlugin } from '@module-federation/observability-plugin/node';

const observability = ObservabilityPlugin({
  level: 'verbose',
  fileOutput: true,
  directory: '.mf/observability',
});

createInstance({
  name: 'node_host',
  remotes: [],
  plugins: [observability.plugin],
});

Node 入口会写:

  • .mf/observability/latest.json:最近一次完整报告
  • .mf/observability/events.jsonl:多次 trace 的事件流水

优先读 latest.json。只有需要查看事件顺序或多条 trace 时,再读 events.jsonl

Node 入口继承运行时参数,并额外支持:

参数类型默认值说明
fileOutputbooleanfalse是否写出本地观测文件。
directorystring'.mf/observability'观测文件输出目录。
latestFilestring'latest.json'最近一次完整报告的文件名。
eventsFilestring'events.jsonl'事件流水文件名。

构建观测

如果希望保留构建侧证据,把构建观测插件放到 Module Federation 构建插件旁边。

webpack.config.js
const {
  ModuleFederationPlugin,
} = require('@module-federation/enhanced/webpack');
const {
  ObservabilityBuildPlugin,
} = require('@module-federation/observability-plugin/build');

const moduleFederationOptions = {
  name: 'runtime_host',
  remotes: {
    remote1: 'remote1@https://example.com/mf-manifest.json',
  },
  exposes: {
    './Button': './src/Button',
  },
  shared: {
    react: { singleton: true, requiredVersion: '^18.0.0' },
  },
};

module.exports = {
  plugins: [
    new ModuleFederationPlugin(moduleFederationOptions),
    new ObservabilityBuildPlugin({
      moduleFederation: moduleFederationOptions,
    }),
  ],
};

构建观测可以写出:

  • .mf/observability/build-info.json
  • .mf/observability/build-report.json

运行时报告不会内嵌这两个文件。排查时如果需要构建侧证据,单独读取构建文件,再和运行时报告对照。

ObservabilityBuildPlugin(options) 支持以下参数:

参数类型默认值说明
enabledbooleantrue是否启用构建观测插件。
outputFilestring'.mf/observability/build-info.json'成功构建时写出的构建信息文件。
errorReportfalse | object{}构建失败时是否写出构建错误观测报告。设为 false 可关闭。
errorReport.outputFilestring'.mf/observability/build-report.json'构建错误观测报告文件路径。
cwdstring编译上下文输出文件的相对目录基准。
bundlerstring自动识别手动指定 bundler 名称。
bundlerVersionstring自动识别手动指定 bundler 版本。
pluginVersionstring自动识别手动指定 Module Federation 构建插件版本。
moduleFederationunknown自动读取显式传入 Module Federation 配置,便于构建观测采集 remotes、exposes、shared 等信息。

标记业务组件成功

Module Federation 能知道 remote module 是否加载完成,但不一定能知道业务组件自己的渲染、请求或初始化是否完成。业务认为组件可用时,可以主动标记。

observability.markComponentLoaded({
  requestId: 'remote1/Button',
  componentName: 'Button',
  metadata: {
    route: '/dashboard',
  },
});

报告里会出现 component:business-loaded,并且 summary.outcome 会变成 "component-loaded"

配合 mf Skill 使用

安装 skill:

npx skills add module-federation/core --skill mf -y

当控制台打印观测提示时,把这段交给 Agent:

/mf observability
我看到了这条 Module Federation console error:

[Module Federation] Observability report generated
traceId: mf-...
read: window.__FEDERATION__.__OBSERVABILITY__["runtime_host"].getReport("mf-...")

请读取报告并帮我修复问题。

如果是 Node 或 SSR,把文件路径交给 Agent:

/mf observability
请读取 .mf/observability/latest.json,告诉我可能是谁的问题,以及应该怎么修。

如果生产环境已经把报告上传到自己的系统,把上传后的报告或 traceId 交给 Agent:

/mf observability
这是 traceId mf-... 对应的上传报告。
帮我判断这是 host、remote、shared、network 还是 build 的问题。

AI 优先读什么

skill 会按这个顺序读报告:

  1. diagnosis
  2. summary
  3. moduleInfo
  4. events

如果需要构建侧证据,再单独读取 .mf/observability/build-info.json.mf/observability/build-report.json

报告会省略 undefined 字段。字段不存在时,表示这次没有观察到,或者这次加载不相关。