如今,有几种方法可以构建分布式前端应用程序。对于建立分布式组件的环境以及管理依赖和协调可见组件的不同方式的人来说,还有许多框架可以使生活更轻松。
在本文中,我将使用Zack Jackson和其他 Core Developers WebPack提出的“模块联合”。由于联邦模块是规范,因此在不同的模块串件(如汇总)中实现了实现。使用最高级API的移植MA是WebPack。因此,本文的示例是使用WebPack的ModuleFederation插件编写的。
对于联合模块架构的工作,有两个PAPS,即应用程序Shell 和远程组件。这些角色可以归因于同一项目或不同项目中的两个应用程序(最常见的是在不同的项目中构建它们)。
o 远程组件您必须通知国家/地区的哪些部分希望在其他应用程序中使用。例如,类,组件,功能等。 应用程序shell 需要注册导入的远程组件的位置。
webpack.config.js(远程组件)
module.exports = {
//...
plugins: [
new ModuleFederationPlugin({
name: 'RemoteComponent1', // nome do módulo remoto
filename: "remoteEntry.js",
exposes: {
"./AppContainer": "./src/App.js" // arquivos exportados, disponíveis para serem importados por outra aplicação
},
// ...
}),
],
};
如何使用 modulefederationplugin
导出组件的示例 webpack.config.js(应用程序shell )
module.exports = {
// ...
plugins: [
new ModuleFederationPlugin({
name: "container",
filename: "containerEntry.js",
remotes: {
"AppContainer": "RemoteComponent1@https://host-of-component/remoteEntry.js"
},
shared: {
// ...
}
})
]
};
如何在shell应用程序中设置插件的示例,以便可以远程找到组件
这就是问题
正如我们所看到的,远程组件的记录以插件配置中的remotes
属性的伸展方式发生。但是,如果我们想添加新组件怎么办?如果我们必须更新任何远程组件的HTTP地址怎么办?如果远程组件设计中有一个多功能控件,而remoteentry.js文件是动态生成不同版本的不同名称的?
对于所有这些情况和许多其他情况,webpack.config.js
文件将从Shell应用程序更改,并再次编译整个项目。即使您想在Shell应用程序中使用JavaScript,也没有更改行,因此必须再次编译该项目,因为另一个项目的更改,该项目也必须再次进行生产。换句话说,可能有必要重新组建应用程序外壳确实是由于组件项目。
eis asolu㧣o
WebPack +模块联合会提供不提供API,因此可以动态注册组件。 ðÖ©ðü 在执行所有这些记录之后,我们可以做与WebPack相同的事情!
!猫猫
有能力在妈妈中注册远程妈妈,您可以从任何地方阅读远程妈妈列表,而不仅仅是静态记录。它可能来自其他地方托管的JSON,甚至来自API提供的一些注册(建议情况)。
mass
导入远程模块的语法非常简单,我们只需要命名组件,责任和URL的名称和URL,就像我们在应用程序外壳中的remotes
配置中所看到的那样。
下面的脚本创建一个HTML Head脚本标签以导入远程脚本,在JS文件导入实例之后,模块
async function loadRemoteComponent({scopeName, moduleName, url} = params) {
const moduleExist = await window[scopeName]?.get(moduleName)
return await moduleExist ? loadRemoteModule(scopeName, moduleName) : importRemoteScope(scopeName, moduleName, url)
}
async function importRemoteScope(scope, moduleName, url) {
const element = document.createElement("script")
element.type = "text/javascript"
element.async = true
element.setAttribute('id', `scope_${scope}`) // id caso você queria remover o import depois por algum motivo
element.src = url
return new Promise((resolve, reject) => {
element.onload = async () => {
const mod = await loadRemoteModule(scope, moduleName)
resolve(mod)
}
element.onerror = async () => { reject('Não foi possivel carregar o modulo desejado') }
})
document.head.appendChild(element)
}
async function loadRemoteModule(scope, moduleName) {
await __webpack_init_sharing__("default")
const container = window[scope]
await container.init(__webpack_share_scopes__.default)
const factory = await window[scope].get(moduleName)
const module = factory()
return module.default
// se você não trabalha com export default faça: return module
}
该代码的摘录必须在您的Shell应用程序中存在。
和实例化您的组件只需致电:
loadRemoteComponent({
moduleName: './AppContainer',
scopeName: 'RemoteComponent1',
url: 'http://https://host-of-component/remoteEntry.js'
});
您可能已经在其他地方注册了这些组件,而不是以webpack.confg.js
文件中的方式注册。因此,您请求此组件注册列表并记录下来。或者,只有在有人向您的Shell应用程序索取此组件时,您才可以按需注册。
比较
estária在webpack.config.js上注册
// ...
new ModuleFederationPlugin({
remotes: {
"AppContainer": "RemoteComponent1@https://host-of-component/remoteEntry.js"
}
})
// ...
带有LoadRemoteComponent的动态记录
loadRemoteComponent({
moduleName: './AppContainer',
scopeName: 'RemoteComponent1',
url: 'http://https://host-of-component/remoteEntry.js'
});
你喜欢吗?你有生命吗?留下我回答的评论。