「微前端」- 将微服务理念扩展到前端开发(实践篇)

前言与大纲

本文分为理论和实战上下两篇。本篇为微前端的实战篇,共计约 5k 字,预计阅读时间 10 mins。

在技术雷达之「微前端」- 将微服务理念扩展到前端开发(上:理论篇)中,我们介绍了微前端在单体应用和微服务的架构演进中所产生的缘由,将微服务理念运用到前端开发就是为了解决臃肿前端的当前现状。与此同时,合理拆分微前端也给我们的应用开发带来显而易见的好处,在本篇当中我们将逐一介绍微前端的实践方案与可能遇到的问题和对应的优化建议。

文章大纲

  • 微前端的可选实践方案(4 种 +)

  • 创建更小的 Apps(而不是 Components)

  • 如何组合微前端的 App 模块?

  • Option 1: 使用后端模板引擎插入 HTML

  • Option 1.1: 渐进式从后端进行加载

  • Option 2: 使用 IFrame 隔离运行时

  • Option 3: 客户端 JavaScript 异步加载

  • Option 4: WebComponents 整合所有功能模块

  • 不同 App 模块之间如何交互?

  • More Options…

  • 微前端的页面优化与实例

  • 多模块页面加载问题与优化建议

  • 微前端在 AEM(CMS)项目的应用

  • 现成解决方案:Single-SPA “meta framework”

  • 总结与思考:微前端的优缺点

  • 微前端的优点

  • 微前端的缺点

  • 持续思考…

  • 附:参考资料

微前端的可选实践方案(4 种+)

创建更小的 Apps(而不是 Components)

首先让我们来创建一个典型 Web 应用程序的基本组件(Header、ProductList、ShoppingCart),以 Header 组件为例:


# src/App.js

export default () =>

 

Logo

;

然后需要注意的是我们会用到 Express 对刚刚创建的 React 组件进行服务器端渲染,使之成为一个 App 模块:


# server.js

fs.readFile(htmlPath, 'utf8', (err, html) => {

 const rootElem = '
'; const renderedApp = renderToString(React.createElement(App, null)); res.send(html.replace(rootElem, rootElem + renderedApp)); });

再依次创建其他 Apps 并独立部署:

  • https://microfrontends-header.herokuapp.com/

  • https://microfrontends-products-list.herokuapp.com/

  • https://microfrontends-cart.herokuapp.com/

如何组合微前端的 App 模块?

在每个独立团队创建好各自的 App 模块后,我们就可以将网站或 Web 应用程序视为由各种模块的功能组合。下文将介绍多种技术实践方案来重新组合这些模块(有时作为页面,有时作为组件),而前端(不管是不是 SPA)将只需要负责路由器(Router)如何选择和决定要导入哪些模块,从而为最终用户提供一致性的用户体验。

Option 1: 使用后端模板引擎插入 HTML


# server.js

Promise.all([

 getContents('https://microfrontends-header.herokuapp.com/'),

 getContents('https://microfrontends-products-list.herokuapp.com/'),

 getContents('https://microfrontends-cart.herokuapp.com/')

 ]).then(responses =>

 res.render('index', { header: responses[0], productsList: responses[1], cart: responses[2] })

 ).catch(error =>

 res.send(error.message)

 )

);


# views/index.ejs

 

 

 Microfrontends Homepage

 

 

 <%- header %>

 <%- productsList %>

 <%- cart %>

 

但是,这种方案也存在弊端,即某些 App 模块可能会需要相对较长的加载时间,而在前端整个页面的渲染却要取决于最慢的那个模块。

比如说,可能 Header 模块的加载速度要比其他部分快得多,而 ProductList 则因为需要获取更多 API 数据而需要更多时间。通常情况下我们希望尽快将网页显示给用户,而在这种情况下后台加载时间就会变得更长。

Option 1.1: 渐进式从后端进行加载

当然,我们也可以通过修改一些后端代码来渐进式地(Progressive)往前端发送 HTML,但与此同时却徒增了后端复杂度,并且又将前端的渲染控制权交回了后端服务器。而且我们的优化也取决于每个模块加载的速度,若是进行优化就必须按一定顺序进行加载。

「微前端」- 将微服务理念扩展到前端开发(实践篇)_第1张图片
image.png

Option 2: 使用 IFrame 隔离运行时




 

 

 



我们也可以将每个子应用程序嵌入到各自的