@edynamix/mf-isolation

中文文档
0.0.43发布于 2026/11/04UNLICENSEDTypeScriptES Module近 30 天下载 2958

CSS和覆盖eDynamix微前端的隔离帮助器.

中文使用文档
文档目录14 节
  1. 安装
  2. 运行时边界
  3. 构建时间 CSS 隔离
  4. 根字体大小和雷姆
  5. 运行时主机模块样式
  6. 来自主机模块的文件查询
  7. 有维特的角
  8. 东道方合同
  9. 导航表
  10. 任意字母大小写中的角基础路径
  11. 角 CDK 覆盖
  12. 模块之间共享角
  13. 东道主拥有区.js
  14. 出口

@edynamix/mf-同位素

CSS隔离和Angular重叠辅助器用于微前端.

安装

bun add @edynamix/mf-isolation@latest

运行时边界

import { prepareMfBoundary } from '@edynamix/mf-isolation';

const disposeBoundary = prepareMfBoundary(element, {
  scopeId: 'portal',
});

// When the microfrontend unmounts:
disposeBoundary();

构建时间 CSS 隔离

全球和供应商支助:

import { scopeRemoteCss } from '@edynamix/mf-isolation/postcss';

export default {
  css: {
    postcss: {
      plugins: [scopeRemoteCss({ scopeId: 'portal' })],
    },
  },
};

主机和遥控器必须使用相同的 scopeId。两个 PostCSS 插件将普通全局和供应商选择器置于零特性下 :where([data-edyn-mf="<scope-id>"]) 边界。 原始文件的后人,如 html body#app button 或者说 html body button 保持根的重量,它们开始于: :where([data-edyn-mf="<scope-id>"]):not(<carrier>)时 :where() 无重和载体(例如: edyn-mf-root edyn-mf-root#edyn-mf-root 页:1 html body#app)具有与被替换的根相同的ID,类和类型计数,并且从未与范围元素相匹配. 因此,模块会像独立页上一样,在角材料上胜负.

模块页面有一个 <html> 和一个 <body>,所以一个需要第二个的选手 从来没有匹配: html body html body .x (一个全局部分在装入时会编译到什么) html body {}, (中文(简体) ), body .a body .b,或组合符后文档根(.x html, (中文(简体) ), .x :root) (中文(简体) ). 扫描会把这些根变成边界,使规则匹配成为主机,因此PostCSS插件都投放出这样的选择器,以及当没有选择器(0.036或更后)时的规则. 下方的运行时间反射器 留下了书面的, 里面也没有匹配.

根字体大小和雷姆

rem 总是与页面相对应 <html>甚至在阴影之根里 一个模块页面,其大小是自己的根(html, body { font-size: 12px })从这个大小绘制出每个雷姆长度;主机,相同的长度会使用主机页面的根. PostCSS 两种插件都因此记录了可解析 font-size 或者说 font 显示大小 html 或者说 :root (px,%,em,rem,绝对单位和大小关键字,与起首的16px相对) --edyn-mf-rem 在模块边界上,在设定它的规则之后 @media 条件和条件 !important 继续 大小 body (或 html body)单独放出rem,就像它在模块自己的页面上那样. 无法在构建时解决的大小( A)var(), (中文(简体) ), calc() 与 var(),取景器单元,系统字体)作为 PostCSS 警告报告;Rem 然后保留主机根大小. 从未大小的 CSS 和以前一样被排放出来 .

跑步时, provideMfOverlayRoot() 财务报告和审定财务报表 provideMfOverlayRootFromToken() 开始 followModuleRootFontSize(shadowRoot) 对于阴影根, 覆盖根坐入, 从环境初始化器( 在第一个组件完成之前) 直到注射器被摧毁。 一旦根中的样式表宣布 --edyn-mf-rem,每个雷姆长度变为 calc(<n> * var(--edyn-mf-rem, 1rem)): 在其样式表,包括组件样式中,Angular稍后添加,并内入 style 属性,包括由模板、绑定或代码后插入或更改的属性。 两者均通过CSSOM(rule.style 财务报告和审定财务报表 element.style),这样 @media, (中文(简体) ), @container 财务报告和审定财务报表 @supports 条件、字符串和 url() 保留他们的短信, !important 留下,重写是独有能力。 在单个属性测试中跳过没有未跟随回放长度(Matrial的波纹和上覆位置)的内置样式,一个其CSS从未大小其根的模块不支付任何报酬:没有启动内置观察者. 附加规则 insertRule() 至已重写的工作表,以及嵌入阴影根内的样式,不重写.

运行时主机模块样式

一个主机呼叫 adaptHostedModuleStyles(shadowRoot) 从 @edynamix/mf-isolation 在它创建的每个模块的阴影根上,以及它在卸载时返回的函数。 它适应一个模块在运行时给根带来的东西,没有模块重建:

  • rem 遵循模块本身的根字体大小, 如 followModuleRootFontSize() 执行以上;
  • 规则一个库在运行时对文档根进行注入,在阴影根内永远不匹配(Angular Matery's html { --mat-focus-indicator-display: block; } 左键盘焦点环关闭),所以它们会像PostCSS插件在构建时所做的那样移动到阴影主机上: html, (中文(简体) ), body, (中文(简体) ), :root 财务报告和审定财务报表 html body 变成 :host,以及 html .x, (中文(简体) ), body > .x 或者说 :root .x 变成 :host .x 财务报告和审定财务报表 :host > .x具有自身条件的根(html.dark, (中文(简体) ), body#app, (中文(简体) ), :root[dir=rtl])与任何已经命名的规则一样,是单独存在的 :host 或者说 data-edyn-mf。 。 。 . rescopeDocumentRootSelectors(selectorText) 是纯选取步骤,并报告它留下了多少个合格根;
  • 为遗留导航的上行栏杆所写的粘贴头被写到主机内容区的上行:旧页被滚动到49px栏下,故为粘贴 top 49px 或超过49px(top: 49px, (中文(简体) ), top: 50px)向上移动49px,在样式表规则和内置样式中从代码(位置-粘接指令')中调取模块集 position: sticky; top: 50px),其优先级保留,每分值一次,模块写出(0.034或以后)。 较小的顶部0, (中文(简体) ), 1px,用于已滚动到栏下方的页和面板, var(), (中文(简体) ), % 财务报告和审定财务报表 calc() 值,而非粘滞规则则单独存在.

在舱外安全 followModuleRootFontSize() 在同一根上(0.0.31或更后):样式表的修改会通过CSSOM,没有变异观察者看到,每个步骤都是一能的,已经遵循的内线样式从此不再看起来像工作,因此在对方的写作上也没有边行.

来自主机模块的文件查询

通过全球文件找到自身要素的模块(document.querySelector('.week-wrapper'), (中文(简体) ), this.document.getElementById('notes-tab-3') 通过角星 DOCUMENT)在自己的页面中找到它们;主机,它们生活在它的阴影根中,文档查询从不输入,所以相同的呼叫返回 null 或者什么都没有。 一个主机呼叫 scopeDocumentQueries(shadowRoot) 从 @edynamix/mf-isolation 旁边 adaptHostedModuleStyles() 在它创建的每个模块的阴影根上,以及它在卸载时返回的函数.

当一个根被注册, querySelector, (中文(简体) ), querySelectorAll, (中文(简体) ), getElementById 财务报告和审定财务报表 getElementsByClassName 在根的文档上,首先运行为正常运行,并在发现任何结果时保持其结果. 只有空结果会回落到已注册的根上,最新的第一(在模块中切换到的模块答案之前的出出模块),第一个有匹配答案的根. 要求任何其他文件,例如iframe的或来自 createHTMLDocument(){\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}没有动静 文档原型为任意数量的根被补丁一次,与页面上本套件的其他拷贝共享,并在上个根停止时恢复;一种方法是其他人在我们之后包裹的包装,我们的包被它通过.

权衡: querySelectorAll 财务报告和审定财务报表 getElementsByClassName 静态 NodeLists,不是活集,所以一个模块持有一个并期望它更新,必须再次查询. 一个文档匹配总是获胜,所以一个请求一个类或ID的模块主页也会像以前那样使用得到主机的元素. 依赖的页面上的代码 null 对于一个选中的模块,其中的一个模块匹配,现在获得模块的元素. getElementsByTagName 不被补丁: 标签查询几乎总是符合主机本身的元素, 因此一个倒计时会很少帮助并可以将模块的 <link> 或者说 <style> 来检查页面.

有维特的角

角化应用程序必须使用角化-感知插件,因此组件 CSS 仍然与 Emiled 视图封装相容 :

import { scopeAngularRemoteCss } from '@edynamix/mf-isolation/postcss';
import { defineConfig } from 'vite';

export default defineConfig({
  css: {
    postcss: {
      plugins: [scopeAngularRemoteCss({ scopeId: 'portal' })],
    },
  },
});

角意识插件离开外观 .component.css, (中文(简体) ), .component.scss, (中文(简体) ), .component.sass 财务报告和审定财务报表 .component.less 文件为已写入(仅包含) @keyframes 名称获得模块前缀),所以Angular完全编译了模块自己页面所编译的内容: 每个组件规则都保留其分量(mat-form-field[_ngcontent-x] 保留(0,1,1)并仍然输给一条全局规则(0,2,0)),在组件主机外的覆盖中提供模板内容保留其组件样式,以及顶级 ::ng-deep 规则保持全局到模块。 角质 _ngcontent 财务报告和审定财务报表 _nghost 属性将组件规则保存在它们的组件上,一个主机模块的组件样式活在自己的阴影根上,所以不需要边界. 组件声明 ViewEncapsulation.None 使用上面描述的全局选择器行为,因为Angular会将其 CSS 保留为全局.

在Angular AOT编译前通过 Vite/ PostCSS 运行此插件 。 别把它和 scopeRemoteCss 在同一 Vite 配置中.

东道方合同

主机通过一个 IMfShellContext 到模块的 mount 函数和预期 IMfModuleLifecycle 输出。 请检查主机版本 isSupportedMfHostContract: 它接受 MF_MINIMUM_HOST_CONTRACT_VERSION 以及以后的每一个版本,因此添加剂合同的更改不需要锁定步骤发布主机和所有模块.

import { type IMfShellContext, isSupportedMfHostContract, MF_MINIMUM_HOST_CONTRACT_VERSION } from '@edynamix/mf-isolation/host-contract';

export const mount = (element: HTMLElement, shellContext: IMfShellContext): void => {
  if (!isSupportedMfHostContract(shellContext)) {
    throw new Error(`This module requires host contract version ${MF_MINIMUM_HOST_CONTRACT_VERSION} or later.`);
  }
  // ...
};

导航表

宣布模块自主导航为有效数据并发射 navigation.json 从同一个 Vite 建筑 :

import {
  defineMfNavigation,
  MF_NAVIGATION_CONTRACT_VERSION,
} from '@edynamix/mf-isolation/navigation';
import { mfNavigationPlugin } from '@edynamix/mf-isolation/vite';
import { defineConfig } from 'vite';

const navigation = defineMfNavigation({
  applicationId: 22,
  contractVersion: MF_NAVIGATION_CONTRACT_VERSION,
  items: [
    {
      id: 'stockmaster.for-sale',
      label: 'For Sale',
      order: 1,
      path: 'usedstock/for-sale',
    },
  ],
  label: 'Stock Master',
  landingPath: 'usedstock',
  moduleId: 'stockmaster',
});

export default defineConfig({
  plugins: [mfNavigationPlugin({ navigation })],
});

路线是模块相对的,没有主斜线。 该插件验证整棵树,在建构过程中用 SHA-256 修订版发出决定性的 JSON, 并服务于相同的外观 Cache-Control: no-cache 在发展中.

对于独立开发,将运算表与主机拥有的导航浏览器条目和开发BFF合并:

import {
  MF_DEVELOPMENT_HOST_NAVIGATION_PATH,
  mfDevelopmentBffPlugin,
} from '@edynamix/mf-isolation/vite-development';

mfDevelopmentBffPlugin({
  hostNavigationUrl: 'https://host.example.test/host-navigation/index.js',
  moduleApiOrigin: 'https://module.example.test',
  moduleApiPath: '/stockmaster/api/',
  // The sign-in service and client the module's own server accepts (its Web.config).
  moduleSignIn: { issuer: 'https://login.example.test', clientId: 'module-local-client' },
});

const localHostNavigationUrl = new URL(
  MF_DEVELOPMENT_HOST_NAVIGATION_PATH,
  'https://localhost:4200',
).href;

hostNavigationUrl 选择主机环境。 装入浏览器条目 localHostNavigationUrl; BFF 通过安全的本地源为所选择的捆绑及其主机拥有的标志资产服务,避免在所选择的主机是HTTP本地主机实例时出现混合内容失败. 主机 API 调用到选中的主机源, 而模块 API 调用到明确 moduleApiOrigin. BFF 与 PKCE 执行 OIDC 授权代码,在开发过程中保留了令牌和模块 API cookie,并在没有暴露于模块 JavaScript的情况下转发认证的 API 请求. 主机的登录(发行者、客户端和范围) /api/auth/oidc-configuration names)授权发送到主机的一切:它的API,导航和它服务的出入口API. moduleSignIn 命名登录服务, 并客户端模块自己的服务器接受( nameissuer, (中文(简体) ), clientId,以及 scope,默认为 openid profile email offline_access);需要,插件拒绝在没有有效的情况下启动. 当它给主机的发行人和客户点名时,一个登录服务两者,就像以前一样. 否则 /api/dev-auth/login 将开发者先签入主机,再签入模块的签入服务,每个都带有自己的PKCE流和命名其步骤的状态,模块API请求携带模块的符号,而其他请求则携带主机. 每一次签入都会自动刷新,签出会同时取消两条并依次结束签入会话. 主机的刷新令牌也保存在 HttpOnly 中 __Host-edyn_dev_refresh 本地原产地的饼干, 一个单独的模块标志 -in' in __Host-edyn_dev_module_refresh,因此在 survived 服务器中签名可以重新启动,并在模块之间切换,直到一个符号过期;当模块单独签名时,重启需要两个 cookie. 登录服务接受每个刷新令牌一次,因此请求在重启的旋转饼干到达之前发送的浏览器会恢复其共享,而不是再次花出令牌并清理出新饼干. 主机API请求保留浏览器的导航选择头,由主机验证. 模块 API 请求代之以包含上次确认的主机的选择,从 /api/navigation 响应和导航流事件,通过 X-Edyn-Navigation-Group-Id, (中文(简体) ), X-Edyn-Navigation-Dealer-Ids 而对于一个庄客, X-Edyn-Navigation-Dealer-Id;模块后端在构建模块特定会话状态前仍必须授权这些值。 独立导航的门户菜单(/api/navigation/portal/...)去被选中的主机自己的门户网站 API(/portal/api/...)同样的方式,所以他们也从一个部署的宿主身上装入,这个宿主在下方没有任何转发 /api/navigation/portal。请求机构以固定长度(最多100 MB)发送,因为部署的模块前端拒绝块状机构。 在模块的第一个API调用 BFF 之前,BFF 请求主机进行当前选择,因为本地外壳在导航旁边而不是在导航之后启动模块. 一个模块的重定向到它的遗产 /login 页面在签名时引导开发签名;它显示模块 API 拒绝会话而不是在循环中重新装入模块。 当没有答案时 moduleApiOrigin,模块 API 调用答案 502 module_api_unreachable 与这个来源和原因, 终端说一次,直到模块服务器再次回答.

任意字母大小写中的角基础路径

IIS在其路径的任何字母大小写中服务一个模块,而旧的书签保留了旧的案例(/AutoPoint/...),但角质 Location 仅在精确匹配时将底线路径剥离。 安装模块 LocationStrategy 从此包中如此 /AutoPoint/... 财务报告和审定财务报表 /autopoint/... 打开模块,地址则保留它用(没有重定向)打开的大小写。 模块路径的早期名称可以作为别名相传:

import { NgModule } from '@angular/core';
import { provideCaseInsensitiveBasePath } from '@edynamix/mf-isolation/angular';

@NgModule({
  providers: [...provideCaseInsensitiveBasePath(['motcleanse'])],
})
export class AppModule {}

基础是模块的 APP_BASE_HREF (或文档的) <base>); 根基(/)是未触及的。 一个将模块路径的大小写变体重定向为小写的主机,一旦模块安装了这个策略,就可以停止这样做.

策略还传递了路由器,仅传递了模块底部和别名内的地址变化. 在主机中, 返回或转发到另一个模块, 在模块卸载前更改地址; 否则模块的路由器会为它自己的地址取取一个地址, 并同时日志 NG04002 (没有匹配)或者在模块的基底下回写(一个囊括或重定向),将页面留在错误的模块中.

角 CDK 覆盖

角融合以角/CDK 19.x为对象. 在一个主机应用程序中,安装完整的提供方阵列,这样全局和连接的覆盖共享模块边界的视图和协调系统:

import { provideMfOverlayRoot } from '@edynamix/mf-isolation/angular';

const providers = provideMfOverlayRoot(overlayRoot);

全部通过 providers 通过应用的靴子。 通话 provideMfOverlayRoot() 没有元素保存了 CDK 的普通文档-视图端口行为.

通过注入符接收根的后遗症 NgModule 应用程序必须同时通过发号施令的帮助器安装两个提供者:

import { InjectionToken, NgModule } from '@angular/core';
import { provideMfOverlayRootFromToken } from '@edynamix/mf-isolation/angular';

export const MF_OVERLAY_ROOT = new InjectionToken<HTMLElement>('MF_OVERLAY_ROOT');

@NgModule({
  providers: [...provideMfOverlayRootFromToken(MF_OVERLAY_ROOT)],
})
export class AppModule {}

提供运行时间 MF_OVERLAY_ROOT 通过现有平台/宝藏注入器的值。 不只提取第一个提供者 provideMfOverlayRoot(); 安装容器但省略了边界感知连接的定位.

角切入点需要 @angular/core, (中文(简体) ), @angular/common,以及 @angular/cdk 19.x (中文(简体) ).

模块之间共享角

不分享,每个主机舱会飞船,并开始自己的Angular副本. 与 createMfAngularShared() 从 @edynamix/mf-isolation/vite,同一版本的模块每页装入Angular、CDK、材料和RxJS一次:

import { federation } from '@module-federation/vite';
import { createMfAngularShared } from '@edynamix/mf-isolation/vite';
import packageJson from './package.json' with { type: 'json' };

federation({
  name: 'autopoint',
  filename: 'remoteEntry.js',
  exposes: { './lifecycle': './src/lifecycle.ts' },
  shared: createMfAngularShared(packageJson.dependencies),
});

它共享模块的每个脚本入口 @angular/* 依赖性(从每个已安装的软件包读取) exports),加 (中文(简体) ) rxjs 财务报告和审定财务报表 rxjs/operators,在模块自己的版本。 样式表也解决的条目点被忽略: @angular/material 财务报告和审定财务报表 @angular/cdk 根响应 @use '@angular/material',模块联盟将用脚本来回答样式表. @angular/compiler 财务报告和审定财务报表 @angular/platform-browser-dynamic 不共享:只有及时编译需要它们,共享它们就能将编译器放入每个模块的构建中. 版本必须准确(19.2.25没有 ^19.2.25) (中文(简体) ). 一个不同版本的模块保留了自己的副本,而不是将两个Angular版本混合在一个页面上. 过 { root } 当 Vite 配置不从模块的软件包目录运行时.

一个模块首先在页面上加载自己在启动时的每个共享切入点的副本,在批次中,联邦插件命令它们输入,一个切入点通过一个仅被加载后才被加载的根来读取另一个切入点. 因此,一个在加载时读取另一个的切入点(一个类扩展,一个静态字段,一个在模块上方的调用)需要该切入点在更早的批次中加载,插件只通过共享的包根命令它们的切入点. createMfAngularShared() 读取每个输入点的源头,并删除那些以未定义约束开头的源头(@angular/material-moment-adapter 扩展 @angular/material/core是因为 DateAdapter,但取决于未分摊 @angular/material 树根; @angular/cdk/listbox 提供 @angular/forms' NG_VALUE_ACCESSOR,而CDK并不依赖),加上每个导入它们的共享切入点,所以一个模块从不持有一个切入点的两份副本. 模块像分享之前一样,将自己的拷贝捆绑起来. mfAssetManifestPlugin() 以同样方式检查已建的输出, 如果共享的切入点仍然读取到另一个切入点, 则会失败 .

共享角是每页一个角平台. 装有 createApplication() 重新使用那个平台。 用于拖带NgModule 替换的模块 platformBrowserDynamic(providers) 与 createHostedAngularPlatform(providers)数字 :

import { createHostedAngularPlatform } from '@edynamix/mf-isolation/angular-platform';

const platform = createHostedAngularPlatform([{ provide: APP_BASE_HREF, useValue: baseHref }]);
const moduleRef = await platform.bootstrapModule(AppModule);
// on unmount
platform.destroy();

它的提供者只接触到模块本身的NgModules,以及 destroy() 只销毁它们;共享平台和其他模块继续运行。 通话 platformBrowserDynamic(providers) 而不是把模块交给另一个模块的平台 没有其供应商,及其 destroy() 将停止页面上的每一个模块。 进入点需要 @angular/platform-browser-dynamic 19.x (中文(简体) ).

东道主拥有区.js

独立的 Angular 应用程序装入自己的 Zone.js 运行时照常:

import 'zone.js';

当应用程序作为主机生命周期运行时,主机拥有单个Zone.js运行时间. 在动态导入任意角代码前检查运行时间 :

import { assertHostZoneRuntime } from '@edynamix/mf-isolation/angular-runtime';
import type { IShellContext } from './shell-context';

export const mount = async (host: HTMLElement, context: IShellContext): Promise<void> => {
  assertHostZoneRuntime();

  const lifecycle = await import('./lifecycle-impl');
  return lifecycle.mount(host, context);
};

angular-runtime 无框架。 它证明 globalThis.Zone 是函数;它不装入或修改Zone.js.

出口

  • @edynamix/mf-isolation
  • @edynamix/mf-isolation/angular
  • @edynamix/mf-isolation/angular-runtime
  • @edynamix/mf-isolation/angular-platform
  • @edynamix/mf-isolation/host-contract
  • @edynamix/mf-isolation/postcss

版本与发布记录

@edynamix/mf-isolation 共发布 43 个版本,首次发布于 2026/08/03;过去 12 个月发布了 43 个版本。

版本发布日期距今
0.0.43latest2026/11/049 天前
0.0.422026/10/3014 天前
0.0.412026/10/3014 天前
0.0.402026/10/3014 天前
0.0.392026/10/3014 天前
0.0.382026/10/3014 天前

关于 @edynamix/mf-isolation 的常见问题

@edynamix/mf-isolation 是什么?

CSS和覆盖eDynamix微前端的隔离帮助器.

如何安装 @edynamix/mf-isolation?

在项目目录运行 npm install @edynamix/mf-isolation,或使用 pnpm add / yarn add / bun add。

@edynamix/mf-isolation 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@edynamix/mf-isolation 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@edynamix/mf-isolation 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@edynamix/mf-isolation 可以商用吗?

@edynamix/mf-isolation 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@edynamix/mf-isolation 的下载量有多少?

根据 npm 官方下载统计,@edynamix/mf-isolation 在 2026/10/13 – 2026/11/11 这 30 天内被下载 2,958 次,日均约 99 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@edynamix/mf-isolation 还在维护吗?

最新版本 0.0.43 发布于 2026/11/04(9 天前);至今共发布 43 个版本,其中过去 12 个月发布了 43 个;首次发布于 2026/08/03。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。