Webpack 5模块联合身份验证失败处理



所以我开始使用webpack 5模块联合,它在主机和微平台之间运行得很好。

但我注意到,如果microfrontend服务器关闭,那么在主机应用程序中,当它试图获取remoteEntry.js并失败时,主机应用程序ui将根本不会启动。

如果它是一个不可用的依赖项,这是可以理解的,但我认为更好的解决方案是有一个类似占位符的东西。。。而不是整个应用程序ui因为远程损坏而拒绝启动。

有什么解决办法吗?我认为webpack应该对远程进行检查,如果它失败了,它会优雅地处理它。

我认为,如果微金融的目的是分离关注点,那么远程资产可能会阻止应用程序完全运行,这是不好的。

更新:

实际上,有几种不同的方法来处理远程可用性:

  • 基于承诺的动态远程:您可以将承诺传递给模块联合插件配置,而不是远程的纯url。这个承诺和您的错误处理逻辑将在运行时得到解决。可以按照该示例执行:

module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
app1: `promise new Promise(resolve => {
const urlParams = new URLSearchParams(window.location.search)
const version = urlParams.get('app1VersionParam')
// This part depends on how you plan on hosting and versioning your federated modules
const remoteUrlWithVersion = 'http://localhost:3001/' + version + '/remoteEntry.js'
const script = document.createElement('script')
script.src = remoteUrlWithVersion
script.onload = () => {
// the injected script has loaded and is available on window
// we can now resolve this Promise
const proxy = {
get: (request) => window.app1.get(request),
init: (arg) => {
try {
return window.app1.init(arg)
} catch(e) {
console.log('remote container already initialized')
}
}
}
resolve(proxy)
}
// inject this script with the src set to the versioned remoteEntry.js
document.head.appendChild(script);
})
`,
},
// ...
}),
],
};

  • 动态远程容器:这是我在下面的回答中所描述的

我认为模块联合插件应该用作构建时依赖项,而不包括动态模块解决和故意故障。

因此,在构建时,很高兴知道您的应用程序中没有某些资产。

但是,如果您真的需要动态导入并在运行时使用MF处理端点的可用性,那么在模块联合示例repo 中就有一个很好的例子

或者它的简化版本:

const loadScope = (url, scope) => {
const element = document.createElement('script');
const promise = new Promise((resolve, reject) => {
element.src = url
element.type = 'text/javascript'
element.async = true
element.onload = () => resolve(window[scope])
element.onerror = reject
})`enter code here`
document.head.appendChild(element)
promise.finally(() => document.head.removeChild(element))
return promise
}
const loadModule = async (url, scope, module) => {
try {
const container = await loadScope(url, scope)
await __webpack_init_sharing__('default')
await container.init(__webpack_share_scopes__.default)
const factory = await container.get(module)
return factory()
} catch (error) {
console.error('Error loading module:', error)
throw error
}
}
const RemoteButton = React.lazy(() => loadModule(
'http://localhost:3002/remoteEntry.js',
'app2',
'./Button'
))

上面的答案以及链接的解决方案都存在第一个呈现的组件将覆盖第二个组件的问题。

对基于Promised的动态路由进行微小更改可以解决此问题。Webpack模块联合身份验证参考:https://webpack.js.org/concepts/module-federation/#promise-基于动态远程

  1. 向promise调用和script.onerror = reject添加拒绝
  2. 在模块联合插件配置中,在共享对象中,我们传递所需包的列表,如react、react dom。直接传递版本,而不是引用Host app package.json依赖项
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
app1: promise new Promise((resolve, reject) => {
const urlParams = new URLSearchParams(window.location.search)
const version = urlParams.get('app1VersionParam')
// This part depends on how you plan on hosting and versioning your federated modules
const remoteUrlWithVersion = 'http://localhost:3001/' + version + '/remoteEntry.js'
const script = document.createElement('script');
script.src = remoteUrlWithVersion
script.onerror = reject;
script.onload = () => {
// the injected script has loaded and is available on window
// we can now resolve this Promise
const proxy = {
get: (request) => window.app1.get(request),
init: (arg) => {
try {
return window.app1.init(arg)
} catch(e) {
console.log('remote container already initialized')
}
}
}
resolve(proxy)
}
// inject this script with the src set to the versioned remoteEntry.js
document.head.appendChild(script);
}
),
},
shared:{
"react": {
"singleton": true,
"requiredVersion": "17.0.1"
},
"react-dom": {
"singleton": true,
"requiredVersion": "17.0.1"
}
}
}),
],
};

相关内容

最新更新