微前端 - 将微服务理念延伸到前端开发中

2018-06-24 00:27:32来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

翻译自 

本文描述了采用不同 JavaScript 技术框架的多个团队中协同构建一个现代化前端 Web 应用所需要的技术、策略和方法。

什么是微前端?

微前端这个术语最初来自 2016 年的 ThoughtWorks 技术雷达[  ],它将微服务的概念扩展到了前端领域。目前的趋势是构建一个功能丰富且强大的前端应用,即单页面应用(SPA),其本身一般都是建立在一个微服务架构之上。前端层通常由一个单独的团队开发,随着时间的推移,会变得越来越庞大而难以维护。这就是传说中的前端巨无霸(Frontend Monolith) [  ]。

微前端背后的理念是将一个网站或者 Web App 当成特性的组合体,每个特性都由一个独立的团队负责。每个团队都有擅长的特定业务领域或是它关心的任务。这里,一个团队是跨职能的,它可以端到端,从数据库到用户界面完整的开发它所负责的功能。

然而,这个概念并不新鲜,过去它叫针对垂直系统的前端一体化或独立系统。不过微前端显然是一个更加友好并且不那么笨重的术语。

一体化的前端

 

 

垂直化组织方式

 

 

什么是现代化前端应用

在介绍中我使用了措辞“构建一个现代化前端应用”,让我们先给出一些这个术语有关的设定。

从一个更广泛的角度来看,Aral Balkan 曾写过一个相关的博客,他把这个概念叫做文档-应用连续统一体。他提出了一个滑动比例尺的概念,在比例尺的最左边是一个网站,由静态文档构成,通过链接相互连接;最右边是一个纯行为驱动的,几乎没内容的应用程序,比如在线图片编辑器。

如果你把你的项目定位在这个范围的左侧,那在 Web 服务器级别的集成会比较合适。在这个模型中,服务器会收集页面中各个组件的内容并将其 HTML 字符串连接起来返回给用户。内容更新则采用从服务端重新加载的方式或者通过 ajax 进行部分替换。Gustaf Nilsson Kotte 针对这个主题写过一篇综合性的文章。

当用户界面需要提供及时反馈时,即使采用不可靠连接,一个纯粹的服务端渲染网站也不够用。为了实现 Optimistic UI 或 Skeleton Screens 这样的技术你需要在设备本身对 UI 进行更新。Google 提出的 PWA 巧妙的描述了这种兼顾各方的做法(渐进增强),同时提供 App 一样的性能体验。这种类型的应用在上面的比例尺中位于文档-应用连续统一体中间的某个地方。在这里纯粹的服务端方案已经不再够用,我们必须将主要逻辑放到浏览器中,这正是本文会重点描述的。

微前端背后的核心理念

技术无关

每一个团队在选择和升级他们的技术栈时应该能够做到不需要和其他团队进行对接。Custom Elements 是一个隐藏实现细节的非常好的方法,同时能够对外提供一个统一接口。

隔离团队代码

即使所有的团队都使用同样的框架,也不要共享一个运行时。构建独立的应用,不要依赖于共享状态或全局变量。

建立各团队的前缀

当隔离已经不可能时要商定一个命名规范。对 CSS、Events、Local Storage 和 Cookie 建立命名空间来避免碰撞并声明所有权。

本地浏览器特性优先于自定义 API

采用浏览器事件进行数据沟通而不是构建一个全局的发布者-订阅者系统。如果你确实需要构建一个跨团队的 API,那就确保它越简单越好。

构建自适应网站

即使 JavaScript 执行失败或是根本没有执行,你的特性也应该是能够使用的。采用通用渲染或渐进式增强来提高可感知的性能。

 

DOM 就是 API

自定义元素 Custom Elements 面向 Web 组件规范中互操作方面,在浏览器中是一个适用于功能集成的基本元素。每个团队采用自己选择的 Web 技术构建他们的组件,并将它们封装到一个 自定义元素 中(比如 <order-minicart></order-minicart> )。这个特定元素的 DOM 声明(标签名、属性和事件)对于其他团队来说体现为一个协定或者叫公共 API。这样做的好处是其他人可以使用这个组件及其功能而不需要知道实现细节,他们只需要能够和 DOM 交互即可。

但仅仅自定义元素是不能满足解决方案的所有需求的。为了处理渐进增强、通用渲染或路由我们还需要软件的其他部分。

本文分为两部分。首先我们会介绍页面组合(Page Composition) —— 如何使用不同团队提供的组件组合成一个页面。然后我们会给出一些示例展示客户端页面转化(Page Transition)的实现。

页面组合

除了采用不同框架编写的客户端或服务端代码集成,还有很多副主题需要讨论:隔离 js的机制、规避 CSS 冲突、按需加载资源、不同团队共享公共资源、处理数据获取和思考提供给用户的加载状态。我们将会依次讨论这些主题。

基本原型

如下的拖拉机模型商店的产品页面将会作为后续示例的基础。

这个页面主要功能是通过一个变量选择器在三个不同拖拉机模型之间进行选择转换,变量改变时产品图片、名称、价格和推荐都会更新。还有一个购买按钮,点击后会将选中的模型添加到购物车中,同时顶部的迷你购物车也会相应更新。

 

 

 

 

所有的 HTML 页面都通过纯 JavaScript和 ES6 模板字符串在客户端生成,没有任何依赖。代码使用一个简单的状态/标记分离方式,一旦有变化整个 HTML 页面都会重新渲染 —— 没有炫酷的 DOM 对比功能,也暂时没有通用渲染。当然也没有团队分离 —— 所有代码都在一个 js/css 文件中。

客户端集成

在如下示例中,这个页面被分隔成不同的组件和片段,分别被三个不同的团队负责。交易组(蓝色)负责所有跟付账流程有关的事情 —— 也就是购买按钮和迷你购物车。推荐组(绿色)负责页面中的产品推荐部分。页面本身则由产品组(红色)负责。

 

 

 

产品组决定哪个功能点被采用以及该功能在页面布局的位置。页面包含的信息可以由产品组自身提供,比如产品名称、图片和可采用的参数,但还可以包括其他团队提供的片段(自定义元素)。

如何创建一个自定义元素

让我们把购买按钮作为一个示例。产品组简单的将 <blue-buysku="t_porsche"></blue-buy> 加入到页面中期望的位置就可以使用这个按钮了。要让这个按钮起作用,交易组还需要在页面中注册元素 blue-buy。

class BlueBuy extends HTMLElement {
  constructor() {
    super();
    this.innerHTML = ` < button type = "button" > buy
    for 66,
    00
			   
			   

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:JavaScript中错误正确处理方式,你用对了吗?

下一篇:移动端日期控件