如今,有几种构建分布式前端应用程序的方法。对于建立分布式组件的环境以及管理依赖和协调可见组件的不同方式的人来说,还有许多框架可以使生活更轻松。
在本文中,我将使用Zack Jackson和其他 Core开发人员 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文件是动态生成不同版本的不同名称的?
对于所有这些情况和许多其他情况,Shell应用程序的webpack.config.js
文件将被更改并再次编译整个项目。即使您想在Shell应用程序中使用JavaScript,它并没有更改线路,但由于另一个项目的变化,必须再次编译该项目,然后再次进行生产。换句话说,可能有必要重新组建Shell应用程序确实是由于组件项目。
eis asolu㧣o
WebPack +模块联合会为我们提供API,以便可以动态注册组件。 ðÖ©ðü 所有这些记录都在执行时间发生后,因此我们可以做与WebPack一样的事情!
!猫猫
有权在其妈妈中注册远程妈妈,您可以从任何地方阅读远程妈妈列表,而不仅仅是静态记录。它可能来自其他地方的JSON,甚至来自API提供的一些注册(建议情况)。
妈妈在面团里
导入远程模块的语法非常简单,我们只需要命名组件,责任的名称和URL,就像我们在remotes
的配置上的示例中所看到的那样/p>
下面的脚本创建一个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
let promise = 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)
return promise
}
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
}
该代码的摘录必须在您的应用程序外壳中存在。
和实例化您的组件只需致电:
loadRemoteComponent({
moduleName: './AppContainer',
scopeName: 'RemoteComponent1',
url: 'http://https://host-of-component/remoteEntry.js'
});
您可能已经在其他地方注册了这些组件,而不是以webpack.confg.js
文件中的方式注册。因此,您请求此组件注册列表并记录下来。或者,您只有在某人向您的应用程序壳索取此组件时才可以按需注册。
比较
estária在webpack.config.js上注册
// ...
new ModuleFederationPlugin({
remotes: {
"AppContainer": "RemoteComponent1@https://host-of-component/remoteEntry.js"
}
})
// ...
带有LoadRemoteMoteComponent的动态记录
loadRemoteComponent({
moduleName: './AppContainer',
scopeName: 'RemoteComponent1',
url: 'http://https://host-of-component/remoteEntry.js'
});
你喜欢吗?你有生命吗?留下我回答的评论。