本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
样式和 CSS
层叠样式表 (CSS) 是一种用于集中确定文档呈现方式的语言,而不是对文本和对象进行硬编码格式化。该语言的级联功能旨在通过使用继承来控制样式之间的优先级。当你在微前端上工作并创建管理依赖关系的策略时,该语言的级联功能可能是一个挑战。
例如,两个微前端共存于同一页面上,每个微前端都为 HTML 元素定义了自己的样式。body
如果每个文件都获取自己的 CSS 文件并使用style
标签将其附加到 DOM,则如果它们都定义了常见的 HTML 元素、类名或元素 ID,则该 CSS 文件将覆盖第一个文件。有不同的策略可以处理这些问题,具体取决于你为管理样式而选择的依赖策略。
当前,平衡性能、一致性和开发者体验的最流行的方法是开发和维护设计系统。
设计系统 — 一种共享的方法
这种方法使用系统在适当时共享样式,同时支持偶尔出现的差异,以平衡一致性、性能和开发者体验。设计系统是以明确标准为指导的可重复使用的组件的集合。设计系统开发通常由一个团队推动,由多个团队提供意见和贡献。实际上,设计系统是一种共享可以导出为 JavaScript 库的低级元素的方法。Micro-Frontend 开发人员可以将该库用作依赖项,通过组合预制的可用资源来构建简单的接口,也可以作为创建新接口的起点。
以需要表单的微前端为例。典型的开发者体验包括使用设计系统中可用的预制组件来撰写文本框、按钮、下拉列表和其他用户界面元素。开发人员不需要为实际组件编写任何样式,只需为它们的外观编写样式即可。要构建和发布的系统可以使用 webpack Module Federation 或类似的方法将设计系统声明为外部依赖项,这样就可以在不包括设计系统的情况下打包表单的逻辑。
然后,多个微前端可以做同样的事情来解决共同的问题。当团队开发可在多个微前端之间共享的新组件时,这些组件将在成熟后添加到设计系统中。
设计系统方法的一个主要优点是高度的一致性。虽然微前端可以编写样式,偶尔还会覆盖设计系统中的样式,但几乎没有必要这样做。主要的低级元素不经常更改,它们提供了默认情况下可扩展的基本功能。另一个优势是性能。有了好的构建和发布策略,您就可以生成最少的共享包,由应用程序 shell 进行检测。当按需异步加载多个特定于微前端的捆绑包时,您可以进一步改进,而网络带宽占用空间最小。最后但并非最不重要的一点是,开发者体验非常理想,因为人们可以专注于构建丰富的界面,而无需重新发明轮子(例如每次需要在页面中添加按钮时编写 JavaScript 和CSS)。
缺点是,任何类型的设计系统都是依赖关系,因此必须对其进行维护,有时还必须更新。如果多个微前端需要共享依赖项的新版本,则可以使用以下任一方法:
-
一种编排机制,可以偶尔获取该共享依赖项的多个版本而不会发生冲突
-
将所有受抚养人转移到使用新版本的共享策略
例如,如果所有微前端都依赖于设计系统的 3.0 版本,并且有一个名为 3.1 的新版本可以共享使用,则可以为所有微前端实现功能标志,以便以最小的风险进行迁移。有关更多信息,请参阅 “功能标志” 部分。另一个潜在的缺点是,设计系统通常解决的不仅仅是造型。它们还包括 JavaScript 实践和工具。这些方面需要通过辩论和合作达成共识。
实施设计系统是一项不错的长期投资。这是一种流行的方法,任何从事复杂前端架构工作的人都应该考虑使用它。它通常需要前端工程师以及产品和设计团队进行协作并定义相互交互的机制。安排时间以达到所需状态很重要。获得领导层的赞助也很重要,这样人们才能长期建造可靠、维护良好且性能良好的东西。
完全封装的 CSS-一种不共享的方法
每个微前端都使用约定和工具来克服 CSS 的级联功能。例如,确保每个元素的样式始终与类名而不是元素的 ID 相关联,并且类名始终是唯一的。通过这种方式,所有内容都限于单个微前端,并且将不必要的冲突风险降至最低。尽管有些工具通过使用将样式捆绑在一起,但应用程序外壳通常负责在微前端的样式加载到DOM中。 JavaScript
不共享任何内容的主要优点是降低了在微前端之间引入冲突的风险。另一个优势是开发者的经验。每个微前端都与其他微前端没有任何共享。单独发布和测试更简单、更快捷。
不共享方法的一个主要缺点是可能缺乏一致性。目前尚无评估一致性的系统。即使目标是复制共享的内容,但在平衡发布速度和协作速度时也变得具有挑战性。常见的缓解措施是创建衡量一致性的工具。例如,你可以创建一个系统,使用无头浏览器自动截取页面中呈现的多个微前端的屏幕截图。然后,您可以在发布之前手动查看屏幕截图。但是,这需要纪律和治理。有关更多信息,请参阅 “平衡自主权与对齐方式” 部分。
根据用例的不同,另一个潜在的缺点是性能。如果所有微前端都使用大量的样式,则客户必须下载大量重复的代码。这将对用户体验产生负面影响。
这种不共享的方法应仅适用于仅涉及几个团队的微前端架构,或者可以容忍低一致性的微前端。在组织研究设计系统时,这也可能是自然而然的初始步骤。
共享全局 CSS — 一种共享的方法
通过这种方法,所有与样式相关的代码都存储在中央存储库中,贡献者通过处理 CSS 文件或使用 Sass 等预处理器为所有微前端编写 CSS。进行更改时,构建系统会创建一个 CSS 包,该包可以托管在 CDN 中,并由应用程序 shell 包含在每个微前端中。Micro-Frontend 开发人员可以通过本地托管的应用程序 shell 运行其代码来设计和构建应用程序。
除了降低微前端之间冲突风险的明显优势外,这种方法的优势还在于一致性和性能。但是,将样式与标记和逻辑分开会使开发人员更难理解样式是如何使用的、它们如何演变以及如何弃用它们。例如,引入新的类名可能比了解现有类以及编辑其属性的后果要快。创建新类名的缺点是捆绑包大小的增长,这会影响性能,并且可能会在用户体验中引入不一致之处。
虽然共享的全局 CSS 可以作为 monolith-to-micro-frontends迁移的起点,但对于涉及一两个以上团队协作的微前端架构来说,它很少有好处。我们建议尽快投资设计系统,并在设计系统开发过程中实施不共享的方法。