1

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

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

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

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

如果微前端的目标是关注点分离,我认为远程资产可以阻止应用程序完全运行是很糟糕的。

4

1 回答 1

1

更新:

实际上有几种不同的方法来处理遥控器的可用性:

  • 基于 Promise 的动态遥控器:您可以将 Promise 传递给 Module Federation 插件配置,而不是遥控器的普通 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 处理端点的可用性,那么在module-federation-examples 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'
))
于 2021-07-16T12:56:25.433 回答