如何使用 Webpack 创建与容器应用程序共享库的微前端包?

IT技术 reactjs webpack architecture microservices micro-frontend
2021-05-14 19:02:33

我有一个任务。

拥有带有单spa框架的微前端。

  1. 门户/主应用程序(通过 url 加载所有其他 js 代码)
  2. 微前端 1(基于react)
  3. 微前端 2(基于react)

所以我的问题只有一个:我不想复制像 react、react-dom(任何其他)这样的供应商库。我想让它们在其他微前端(与 webpack 捆绑在一起)之间共享

我知道拥有一些全局内容是什么不好的做法(这违反了与 webpack 捆绑的整个想法)。但是如何解决厂商库重复的问题呢?

我发现一个解决方案只是使用 SystemJs 加载规范,例如 html 中的分隔标签,但我只是想知道也许还有另一种解决方案。

谢谢你。

SystemJs 根据需求加载依赖项但从 CDN 加载依赖项的方法,我只想做同样的事情,但是从带有 react 和其他东西的“共享”webpack 包加载所有依赖项。

window.SystemJS = window.System

function insertNewImportMap(newMapJSON) {
  const newScript = document.createElement('script')
  newScript.type = 'systemjs-importmap'
  newScript.text = JSON.stringify(newMapJSON)
  const allMaps = document.querySelectorAll('script[type="systemjs-importmap"]')

  allMaps[allMaps.length - 1].insertAdjacentElement(
    'afterEnd',
    newScript
  )
}

const devDependencies = {
  imports: {
    react: 'https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.development.js',
    'react-dom': 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.development.js',
    'react-dom/server': 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom-server.browser.development.js',
    'single-spa': 'https://unpkg.com/single-spa@4.3.2/lib/umd/single-spa.min.js',
    lodash: 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js',
    rxjs: 'https://unpkg.com/rxjs@6.4.0/bundles/rxjs.umd.js',
  }
}

const prodDependencies = {
  imports: {
    react: 'https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js',
    'react-dom': 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js',
    'react-dom/server': 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom-server.browser.production.min.js',
    'single-spa': 'https://unpkg.com/single-spa@4.3.2/lib/umd/single-spa.min.js',
    lodash: 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js',
    rxjs: 'https://unpkg.com/rxjs@6.4.0/bundles/rxjs.umd.min.js',
  }
}

const devMode = true // you will need to figure out a way to use a set of production dependencies instead
if (devMode) {
  insertNewImportMap(devDependencies)
} else {
  insertNewImportMap(prodDependencies)
}

2个回答

更新:

刚刚意识到,您的问题是针对微前端(不仅是微服务),因此通常与与 Webpack 共享库无关。将微前端添加到您的标签/标题并更新了答案以更加关注此主题。


所以我的问题只有一个:我不想复制像 react、react-dom(任何其他)这样的供应商库。我想让它们在其他 [Micro Frontends](与 webpack 捆绑在一起)之间共享

您可以做的是通过将Webpack externals属性添加到配置中来从微前端的输出包中排除依赖项

微前端的 webpack 配置:

module.exports = {
  ...
  externals = {
    react: 'React',
    'react-dom': 'ReactDOM'
  }
}

以上配置将排除reactreact-dom期望他们在全局变量ReactReactDOM然后,您可以通过将库包含在index.html根应用程序(又名拼接层)脚本中来共享这些依赖项

<html>
  ...
  <body>
    ...
    <script src="<your-host>/react.prod-16.9.0.min.js"></script>
    <script src="<your-host>/react-dom.prod-16.9.0.min.js"></script>
  </body>
</html>

如果您有其他常用组件要共享,也可以将库脚本集成到组件库中

include as 脚本的原因是:我们不希望我们的容器在构建时需要/导入微前端,以避免所有应用程序之间的构建/发布/版本管理耦合。相反,微前端的一个目的是实现部件的完全独立部署,其中包括从构建、测试到发布的持续交付步骤。

我知道拥有一些全局内容是什么不好的做法(这违反了与 webpack 捆绑的整个想法)。

当然,您会在应用程序之间创建某种形式的耦合。但是如果你有一个成熟的、稳定的、通用的库,所有部分都共享,这是一个合理的决定。

希望,它有帮助(现在)!

今天实现这一目标的最佳方法是使用 Webpack 在 v5 中发布的新module联合技术。这种方法不使用 SystemJS,而是使用 Webpack 的内部结构。我们尝试了几种不同的微前端方法,但这个方法胜过所有方法,并且目前在生产中为我们成功运行。设置它肯定存在一些挑战,但值得开发人员提高生产力。

这是创建者 Zack Jackson 制作的信息站点,它应该提供您需要的所有资源:https : //module-federation.github.io/

这是 webpack 文档的链接,它更多地处理技术问题,而不是如何实际设置完整的微前端架构:https : //webpack.js.org/concepts/module-federation/