What does it mean by Framework agnostic?
框架不可知一般意味着确切地说,即不可知或独立于任何框架。
举个例子,公司或产品团队经常处理以下优先事项:
-
通常在大公司中,有多个团队致力于其产品前端的各种模块或部分。这些团队通常是自主和自主的,这意味着他们选择自己的 Javascript 框架来进行前端开发。
-
但是,作为一家公司,无论每个团队选择与什么合作,您都希望确保产品的所有不同模块和部分的用户体验相同。
为了平衡这两个相互竞争的优先事项,框架不可知 Web 组件库的概念派上用场。为了使其成为一家公司,您鼓励您的团队开发一个独立于任何框架(如 Vue、Angular、React)的 Web 组件库。无论使用什么框架,团队都可以互换使用这些组件。
什么是微前端
Micro Frontends 一词于 2016 年底首次出现在 ThoughtWorks Technology Radar 中。它将微服务的概念扩展到前端世界。当前的趋势是构建一个功能丰富且功能强大的浏览器应用程序,也就是单页应用程序,它位于微服务架构之上。随着时间的推移,前端层(通常由一个单独的团队开发)不断增长并且变得更加难以维护。这就是我们所说的前端单体。
微前端背后的想法是将网站或 Web 应用程序视为由独立团队拥有的功能组合。每个团队都有自己关心和专攻的不同业务或任务领域。团队是跨职能的,从数据库到用户界面,端到端地开发其功能。
然而,这个想法并不新鲜。它与自包含系统概念有很多共同之处。在过去,像这样的方法被称为垂直化系统的前端集成。但微前端显然是一个更友好、更简洁的术语。
Monolithic Frontends Monolithic Frontends

Organisation in Verticals End-To-End Teams with Micro Frontends

什么是现代前端应用?
为了从更广泛的角度来看,Aral Balkan 写了一篇关于他所谓的文档到应用程序连续体的博客文章。他提出了滑动比例的概念,其中一个由静态文档构建并通过链接连接的站点位于左端,而一个纯行为驱动的、无内容的应用程序(如在线照片编辑器)位于右侧。
如果您将项目放在此范围的左侧,则网络服务器级别的集成非常适合。使用此模型,服务器从构成用户请求的页面的所有组件中收集并连接 HTML 字符串。更新是通过从服务器重新加载页面或通过 ajax 替换部分页面来完成的。 Gustaf Nilsson Kotte 写了一篇关于这个主题的综合文章。
当您的用户界面必须提供即时反馈时,即使是在不可靠的连接上,纯服务器渲染站点也不再足够。要实现 Optimistic UI 或 Skeleton Screens 等技术,您还需要能够在设备本身上更新您的 UI。 Google 的术语 Progressive Web Apps 恰如其分地描述了成为网络的好公民(渐进式增强)同时提供类似应用程序的性能的平衡行为。这种应用程序位于站点应用程序连续体中间的某个地方。在这里,仅基于服务器的解决方案已不再足够。我们必须将集成移动到浏览器中。
微前端背后的核心概念
- 技术不可知
每个团队都应该能够选择和升级他们的堆栈,而无需与其他团队协调。自定义元素是隐藏实现细节同时为其他人提供中立界面的好方法。
- 隔离团队代码
即使所有团队都使用相同的框架,也不要共享运行时。构建自包含的独立应用程序。不要依赖共享状态或全局变量。
- 建立团队前缀
就目前无法隔离的命名约定达成一致。命名空间 CSS、事件、本地存储和 Cookie,以避免冲突并澄清所有权。
- 优先使用本机浏览器功能而不是自定义 API
使用浏览器事件进行通信,而不是构建一个全局的 PubSub 系统。如果您真的必须构建跨团队 API,请尝试使其尽可能简单。
- 构建弹性站点
即使 JavaScript 失败或尚未执行,您的功能也应该很有用。使用通用渲染和渐进增强来提高感知性能。
DOM 就是 API
自定义元素,来自 Web 组件规范的互操作性方面,是集成到浏览器中的一个很好的原语。 每个团队使用他们选择的 Web 技术构建他们的组件,并将其包装在自定义元素中。
例如:
<order-minicart></order-minicart>
这个特定元素(标签名、属性和事件)的 DOM 规范充当其他团队的合同或公共 API。 优点是他们可以使用组件及其功能而无需了解实现。他们只需要能够与 DOM 交互。
但是仅自定义元素并不能满足我们所有的需求。 为了解决渐进增强、通用渲染或路由,我们需要额外的软件。
此页面分为两个主要区域。 首先,我们将讨论页面组合——如何将不同团队拥有的组件组合成一个页面。 之后,我们将展示实现客户端页面转换的示例。
Page Composition
除了用不同框架编写的代码的客户端和服务器端集成本身之外,还有很多应该讨论的侧面主题:隔离js的机制,避免css冲突,按需加载资源,团队之间共享公共资源,处理数据获取 并为用户考虑良好的加载状态。 我们将一步一步地讨论这些主题。
The Base Prototype
该模型拖拉机商店的产品页面将作为以下示例的基础。
它具有一个变体选择器,可在三种不同的拖拉机型号之间切换。 更改产品图片时,会更新名称、价格和建议。 还有一个购买按钮,可将选定的变体添加到购物篮中,顶部的迷你购物篮会相应更新。

所有 HTML 都是使用纯 JavaScript 和 ES6 模板字符串在客户端生成的,没有依赖项。 代码使用简单的状态/标记分离,并在每次更改时重新呈现整个 HTML 客户端 - 现在没有花哨的 DOM 差异,也没有通用渲染。 也没有团队分离——代码写在一个 js/css 文件中。
Clientside Integration
在此示例中,页面被拆分为三个团队拥有的单独组件/片段。 Team Checkout(蓝色)现在负责与购买过程有关的所有事情——即购买按钮和迷你篮。 Team Inspire(绿色)管理此页面上的产品推荐。 该页面本身归 Team Product(红色)所有。

每个团队的分工
- Team Product
团队产品决定包含哪些功能以及它在布局中的位置。 该页面包含可由 Team Product 本身提供的信息,例如产品名称、图像和可用的变体。 但它也包括来自其他团队的片段(自定义元素)。
How to Create a Custom Element?
让我们以购买按钮为例。 Team Product 包含一个按钮,只需将下列代码添加到标记中的所需位置即可。 为此,Team Checkout 必须在页面上注册元素 blue-buy。
<blue-buy sku="t_porsche"></blue-buy>
class BlueBuy extends HTMLElement {
connectedCallback() {
this.innerHTML = `<button type="button">buy for 66,00 €</button>`;
}
disconnectedCallback() { ... }
}
window.customElements.define('blue-buy', BlueBuy);
现在,每次浏览器遇到新的 blue-buy 标签时,都会调用 connectedCallback。 这是对自定义元素的根 DOM 节点的引用。 可以使用标准 DOM 元素的所有属性和方法,如 innerHTML 或 getAttribute()。

命名元素时,规范定义的唯一要求是名称必须包含破折号 (-) 以保持与即将推出的新 HTML 标签的兼容性。 在接下来的示例中,使用命名约定 [team_color]-[feature]。 团队命名空间防止冲突,这样功能的所有权就变得显而易见,只需查看 DOM。
Parent-Child Communication / DOM Modification
当用户在变体选择器中选择另一台拖拉机时,必须相应地更新购买按钮。 为了实现这个团队产品,可以简单地从 DOM 中删除现有元素并插入一个新元素。
container.innerHTML;
// => <blue-buy sku="t_porsche">...</blue-buy>
container.innerHTML = '<blue-buy sku="t_fendt"></blue-buy>';
旧元素的 disconnectedCallback 被同步调用,为元素提供清理事件侦听器之类的机会。 之后,新创建的 t_fendt 元素的 connectedCallback 被调用。
另一个更高效的选择是仅更新现有元素上的 sku 属性。
document.querySelector('blue-buy').setAttribute('sku', 't_fendt');
如果 Team Product 使用具有 DOM diffing 功能的模板引擎,例如 React,则算法会自动完成。
更多Jerry的原创文章,尽在:"汪子熙":

网友评论