模块联合会的未来
在过去的四年中,我在模块联合会中遇到了相当多的局限性。它完成了为完成的工作,从其他捆绑包中导入代码。但是随着时间的流逝,随着用例,规模和用户群的变化,有一些设计的监督真的很有帮助。
我从没想到联邦会像它一样流行,事后看来,有一些调整可以使其更加强大和有用。这也是Infra团队所看到的,他们最终摘下了插件,实施了浏览器DevTools并解决了许多Gotchas。
在下一个季度,我们将尝试将叉子中存在的内部耦合分开,而是将某些方面直接实施到模块联合会中。
要这样做,联邦需要以非打破的方式进行改变。
Module Federation Redesign · module-federation/universe · Discussion #1170
钩子
我们故意没有将钩子添加到插件中,因为最终用户不需要或不应该修补内部机制。我同意这一点,但我认为我们不认为我们应该提供一些框架API
如果需要修改联邦,我们必须更改Webpack或分叉整个插件,ouch。我们为将其与更好的管理系统和工具集成在一起而做的叉子。
在1.5版中,我们想引入钩子,以便增强联邦不需要完全分叉。
框架API
类似于钩子,通常在构建时间或运行时需要更多的中级API。当您处理复杂的应用程序时,标准{GET,INIT} API会感到有些限制。在运行时和编译时间的更多插头性将使框架作者更多地可以使用。
打字稿支持和远程类型
越来越强调合并强大的类型系统以增强代码安全性和可维护性。认识到这种需求,设置了模块联合会的下一个迭代,以引入**内置** typecript支持远程类型。
此功能旨在无缝整合远程类型的定义,从而使开发人员能够利用联合模块的打字稿的强大打字功能。
这样做可以增强互操作性,降低类型相关错误的风险并培养更连贯的开发体验。
这为创建更可靠和高效的分布式系统而进一步创新奠定了基础。
初始化阶段
主要的是中间件和启动代码的概念。
主机应该能够在消耗的遥控器上应用类似快递的中间件。这将有助于大量进行AB测试,动态环境切换,授权和权限,错误处理等。
但是,消费者端的中间件并不总是足够或适当。有时,我可能需要或想将一些启动代码作为遥控器的作者。可以在遥控器的初始化阶段执行的一些运行时代码。就像获取环境变量或确保所需的数据是否已准备就绪或存在,或将提供商注入应用程序。
遥控器需要一种方法来准备他们的消费环境,如果需要的话。
生命周期
与中间件相似且毗邻,我们可以从基本的生命周期中受益。像插件系统一样,可以为我们提供更多回调以应对发生的事情。
中间件实现提供了各种钩子,这些钩子提供了干预联合模块流程的机会:
-
ininit&init:准备初始环境和管理配置。
-
beforeloadremote&loadRemoteMatch:控制远程联合模块的加载。
-
loadRemote:对单个联合模块的加载过程的动态控制。
-
errorloadRemote:管理在远程加载过程中发生的错误。
-
beforeloadshare&LoadShare:控制共享模块及其行为。
-
preferproloadRemote:对预加载操作的优化和控制。
中间件:
一个人应该如何以集成方式与中间件流相互作用?
new ModuleFederationPlugin({
middleware: './src/federation-middleware.js'
})
//federation-middleware.js
module.exports = {
beforeInit,
beforeLoadingRemote,
loadRemoteMatch,
loadRemote,
errorLoadRemote,
beforeLoadShare,
beforePreloadRemote
}
在运行时:
hooks = new PluginSystem({
beforeInit: new SyncWaterfallHook<{
userOptions: UserOptions;
options: Options;
origin: VmokHost;
}>('beforeInit'),
init: new SyncHook<
[
{
options: Options;
origin: VmokHost;
},
],
void
>(),
beforeLoadRemote: new AsyncWaterfallHook<{
id: string;
options: Options;
origin: VmokHost;
}>('beforeLoadRemote'),
loadRemoteMatch: new AsyncWaterfallHook<{
id: string;
pkgNameOrAlias: string;
expose: string;
remote: RemoteInfo;
options: Options;
origin: VmokHost;
}>('loadRemoteMatch'),
loadRemote: new AsyncHook<
[
{
id: string;
expose: string;
pkgNameOrAlias: string;
remote: RemoteInfo;
options: ModuleOptions;
origin: VmokHost;
exposeModule: any;
moduleInstance: Module;
},
],
void
>('loadRemote'),
errorLoadRemote: new AsyncHook<
[
{
id: string;
error: unknown;
},
],
void
>('errorLoadRemote'),
beforeLoadShare: new AsyncWaterfallHook<{
pkgName: string;
shareInfo?: Shared;
shared: Options['shared'];
origin: VmokHost;
}>('beforeLoadShare'),
loadShare: new AsyncHook<[VmokHost, string, ShareInfos]>(),
beforePreloadRemote: new AsyncHook<{
preloadOps: Array<PreloadRemoteArgs>;
options: Options;
origin: VmokHost;
}>(),
});
启动
模块联合会中的启动代码代表遥控器具有自己的生命周期的建筑演化。这允许对联合模块的引导进行细微的控制,并与中间件同时进行,以启用复杂的谈判4向握手。
new ModuleFederationPlugin({
startup: './src/federation-startup.js'
})
示例和应用
启动阶段结合了可以根据特定需求量身定制的各种元素:
-
环境配置:设置不同联合模块的运行时环境。
-
状态管理:管理全球状态和州商店中的中间件。
-
实时通信:管理诸如WebSockets之类的实时频道。
-
关键资源预加载:预付资源可用于更顺畅的用户体验。
-
错误处理:使用自动恢复机制处理错误。
-
数据完整性:实现已加载模块的完整性检查。
-
访问控制:实现运行时访问控制。
-
主题和本地化:动态应用主题或本地化设置。
-
缓存管理:跨联合模块管理缓存。
-
与旧系统集成:通过适应界面与旧系统集成。
-
自定义UI组件加载:加载或卸载UI组件。
-
健康监测和报告:关键依赖性的嵌入健康检查。
-
合规性和安全执行:确保遵守法律或商业规则。
-
实验和A/B测试:支持动态A/B测试而不更改核心代码库。
-
插件的可扩展性:启用第三方开发人员扩展功能。
4向握手
在4向握手过程中,中间件和启动代码协同工作:
-
远程初始化(启动):执行规定的启动任务。
-
中间件执行:使主机能够执行动作并适应行为。
-
依赖关系链接:完成依赖关系图中的连接和链接。
-
应用程序执行:开始执行应用程序。
启动钩/生命周期
启动钩子专注于提供者/遥控器采取的初始化和准备操作。它们可能是中间件挂钩的镜像,重点是提供而不是消费。
startupHooks = new PluginSystem({
beforeStartup: new SyncWaterfallHook<{
moduleOptions: ModuleOptions;
environment: Environment;
provider: VmokProvider;
}>('beforeStartup'),
onStartup: new SyncHook<
[
{
provider: VmokProvider;
environment: Environment;
},
],
void
>('onStartup'),
beforeInitializeRemote: new AsyncWaterfallHook<{
id: string;
initializationOptions: InitializationOptions;
provider: VmokProvider;
}>('beforeInitializeRemote'),
initializeRemote: new AsyncHook<
[
{
id: string;
initializationOptions: InitializationOptions;
provider: VmokProvider;
remoteInstance: Remote;
},
],
void
>('initializeRemote'),
errorInitializeRemote: new AsyncHook<
[
{
id: string;
error: unknown;
},
],
void
>('errorInitializeRemote'),
beforePrepareEnvironment: new AsyncWaterfallHook<{
environment: Environment;
provider: VmokProvider;
}>('beforePrepareEnvironment'),
prepareEnvironment: new AsyncHook<
[
{
environment: Environment;
provider: VmokProvider;
},
],
void
>('prepareEnvironment'),
beforeFinalizeStartup: new AsyncWaterfallHook<{
finalizationOptions: FinalizationOptions;
provider: VmokProvider;
}>('beforeFinalizeStartup'),
finalizeStartup: new AsyncHook<
[
{
finalizationOptions: FinalizationOptions;
provider: VmokProvider;
},
],
void
>('finalizeStartup'),
});
启动钩的说明
-
besforestartup :允许初始配置。
-
onstartup :核心初始化逻辑。
-
initializeremote :初始化远程模块之前进行预处理。
-
initializeremote :远程模块的初始化。
-
错误initializeremote :在初始化过程中处理错误。
-
toferprepareEnvironment :环境配置之前的动作。
-
准备环境:实际环境设置。
-
frefinizestartup :在完成启动之前进行预处理。
-
finalizestartup :最终动作,包括清理或验证。
整体中间软件和启动
在模块联合会的体系结构中,中间件和启动代码的集成标志着处理联合模块的重大进步。他们提供了一种对称的设计,中间件专注于消费和主机的观点,而启动代码则针对配置和提供商的视图。
中间件
使用各种挂钩来控制和自定义联合模块加载和执行的不同阶段,中间件为消费者提供了量身定制的体验。它提供了对远程加载,错误管理,共享模块行为和预加载操作等方面的粒状控制水平。中间件允许与现代分布式系统的复杂需求进行复杂的一致性,从而提供灵活性,鲁棒性和有效的联合模块处理。
启动
另一方面,启动代码引入了一个细微的生命周期,以供远程使用,重点放在初始化和制备操作上。它强调了提供商的观点,允许诸如环境配置,错误处理,与旧系统集成,高速缓存管理等诸如诸如措施。启动挂钩提供了丰富的生命周期模型,该模型补充了面向消费的中间件挂钩。
综合效果
一起,中间件和启动形成了一个凝聚力和全面的协议,该协议符合联合模块操作的两侧。精心设计的钩子和生命周期阶段为开发人员提供了一个强大的工具包,以便从初始化到执行,可以对流程进行精细的控制。四向握手模型说明了这两个组件如何齐声工作以确保平稳有效的操作。
本质上,模块联合会中的中间件和启动的综合力量促进了更具适应性,弹性和可扩展的体系结构。它反映了一个周到的设计,该设计预测了现代开发环境的多方面需求,提供了以轻松而精确的方式创建复杂,分布式系统的工具和方法。无论是中间件提供的灵活自定义还是创业公司提供的强大初始化,这二人组成了一个智能系统的骨干,该智能系统有望彻底改变联合模块的处理和执行方式。
>运行时API / SDK
中间件,生命周期,这都是相关的,因此需要SDK和更好的运行时API。
运行时API应以某种方式暴露中间件原始图,例如可在React中使用的可引导生命周期。
另一方面,SDK的目的是将我们正在构建的东西带入WebPack运行时并将其内部旋转。
联邦v1.5尝试在其他构建工具中支持并支持联邦,联邦已经很棘手或不兼容。为了支持其他工具,我不知道他们的API是否值得付出努力 - 联邦使用了许多Webpacks API来实现它。
因此,与其保持WebPack已经可以做什么的复制品 - 如果我们运送空的WebPack Runtime,将其 webpack_require 在库中包裹起来,然后将其运送到它到NPM?
import {createContainer} from '@module-federation/sdk';
const federationConfig = {
name: 'app2',
exposes: {
"./Button": () => {
return import('./App').then(f => () => f)
}
},
shared: {
react: {
version: '18.2.0',
import: () => import('react').then(f => () => f),
weakRef: require.resolveWeak('react'),
},
'react-dom': {
version: '18.2.0',
import: () => import('react-dom').then(f => () => f),
weakRef: require.resolveWeak('react-dom'),
}
}
}
export default createContainer(federationConfig) // => {get,init}
插件钩
编译模块联合会的时间挂钩:
此方面尚未完全开发,但是以下方面应为方向提供一个窗口
初始化钩子
- beforecompileinit:在初始化编译过程之前调用。
beforeCompileInit: new SyncHook<[InitializationOptions]>('beforeCompileInit'),
文件系统挂钩
customizefilesystem:自定义用于加载块或更改汇编过程中文件系统定义的文件系统。
customizeFilesystem: new AsyncHook<[FilesystemOptions]>('customizeFilesystem'),
模板生成钩
beforetemplatemeneration:在生成联合模块的模板之前进行预处理。
beforeTemplateGeneration: new AsyncWaterfallHook<[TemplateOptions]>('beforeTemplateGeneration'),
generateTemplate:在编译时间内为联合模块的生成模板。
generateTemplate: new AsyncHook<[GenerateTemplateOptions]>('generateTemplate'),
API操纵钩
foreapialteration:在更改或扩展API接口之前调用。
beforeAPIAlteration: new SyncHook<[APIOptions]>('beforeAPIAlteration'),
Alterapi:更改或添加更多导出到主接口。
alterAPI: new AsyncHook<[AlterAPIOptions]>('alterAPI'),
使用(Web | Rs)包装运行时作为库?可能性
联邦的大部分价值都在于WebPack的运行时。这个想法是使用webpack运行时将动态导入注入到产生容器的工厂中。
这个概念类似于单SPA,其中可以从任何构建中导出任何作为远程条目或主机。运行时将启动该应用程序,而无需使用WebPack来构建它。
而不是复制WebPack的作用,而是使用其预构建的运行时,稍微修改它,并使用WebPack的实际运行时作为框架。父构建工具将处理脚本加载,因此SDK的职责将很小。
仅使用WebPack插件创建一个干净的SDK可能是不可能的,尽管这不是一件容易的事,但最好使用较小的构建API重新创建联邦。
作为与WebPack广泛合作的人,我非常感谢拥有Rspack。它允许使用插件的灵活性,从长远来看,尽管学习曲线长远。
。困难的建筑或业务问题变得更加易于管理甚至琐碎。使用Rspack,可以与WebPack保持兼容性,但是有增强的空间,其速度开辟了新的可能性。
速度和能力之间的平衡。如果RSPACK可以在4秒内构建18,000个文件代码库,而不是60个文件代码库,则可以在没有明显延迟的情况下引入新的强大功能。在JavaScript中执行其中一些任务可能是不可行的。
包装
模块联合的演变以更精致和专业的API的发展为标志。这些改进使开发人员能够应对框架级别的挑战,从而促进对分布式系统及其模块树的处理和形成的更细微的控制。
引入中间件,启动钩和编译时插件挂钩代表着向前迈出的重要一步。这些功能允许更大范围的自定义,丰富架构范围和实用程序。
这些进步的全部潜力只能在统一的元框架中实现,从而封装了现代发展的各种需求。这是ModernJS旨在在未来迭代中履行的角色。作为一个平台,它将这些新功能集成到一个连贯的整体中,为构建和管理分布式系统提供了一种实用,有效的方法。
通过在ModernJs内给模块联合会成为一个家庭,可以利用这些新功能来解决现实世界中的挑战,而不会失去潜在的技术复杂性。创新与实用性之间的这种一致性构成了在微额定和代码分布领域进一步增长和完善的基础。
Modern.js
*A Progressive React Framework for modern web development.*modernjs.dev