[Web翻译]我们如何在 GitHub 使用 Web 组件

原文地址:github.blog/2021-05-04-…

原文作者:github.blog/author/kodd…

发布时间:2021年5月4日

在GitHub,我们为能提供一流的开发者体验而自豪。我们有相当一部分工作是在我们的前端,我们努力保持尽可能的轻量级、快速和可访问。对于像GitHub这样大的产品,这可能是一项相当艰巨的任务。像许多前端代码库一样,我们利用组件、独立、隔离和可重用的代码片断,使应用团队能够快速有效地提供高保真的用户界面,同时仍然保持我们的高标准质量。

在GitHub,我们正在大力使用Web组件。我们有十几个开源的Web组件,还有几十个是闭源的。

我们是如何做到这一点的

当GitHub在十年前推出时,我们有一个规模不大的前端代码库,主要使用jQuery。十年后,我们有了一个庞大的前端代码库,开始出现成长的烦恼。我们最终放弃了jQuery(原因我们在当时的一篇博文中做了详细说明),开始使用新的技术来更好地解决我们的问题。

我们开始涉足一种叫做Web Components的新技术,这是一套原生的浏览器技术,允许开发定制的HTML元素,并用JavaScript逐步增强。

我们选择使用Web Components是因为我们的代码库已经被结构化为类似组件的行为。然而,随着GitHub单体规模的扩大,我们发现有必要在前端变得难以管理之前实现更好的封装–而Web Components正符合这一要求。Web组件比我们现有的JavaScript行为提供了更好的可移植性和封装性。我们很高兴在我们现有的前端基础设施的基础上尝试使用Web组件,因为它不会产生任何前期成本或 “买进 “一个特定的框架。

我们的第一批两个自定义元素在2014年发货。<relative-time><local-time>,它们以友好的格式显示时间和日期,以及<include-fragment>,它允许我们延迟加载HTML片段。慢慢地,我们意识到这些元素有多么强大,并开始在代码库中全盘替换设计模式,例如用<details-dialog>替换我们的 “facebox “模态对话框模式。我们的组件现在从非常通用的、多用途的行为(如<remote-input>)到特定的单一用途的组件(如<markdown-toolbar>元素和它的兄弟姐妹)。

对于Web Components所提供的功能,仍有一些痛点和隐患。面对由几十个团队的数百名工程师所拥有的如此庞大的代码库,我们需要提供尽可能多的支持和工具,在不使手工代码审查成为瓶颈的情况下对最佳实践进行编码。

改进我们编写组件的方式

为了让工程师有效地编写高质量的Web组件,并鼓励最佳实践,我们一直在开发一些工具,使编写Web组件变得更加容易。

ViewComponent

我们一直在将我们的Rails代码过渡到使用ViewComponent,这是一个用于在Rails中构建可重用组件的框架。ViewComponent与Web Components相辅相成,因为ViewComponent可以与Web Component有一对一的关系,使我们的开发者可以在前端和后端使用单一的抽象概念。

催化剂

Catalyst是我们的开源库,它使编写Web组件变得更容易,它一直是将我们的一些最佳实践联系在一起的驱动力。Catalyst利用TypeScript来添加装饰器,这节省了很多编写Web组件所需的模板。

Catalyst从优秀的Stimulus库和Google的LitElement中获得灵感。它的设计是为了满足我们的开发者的特定需求。我们内部的开发者经验调查显示,在编写代码方面比传统模式有了很大的改进。

你可以在我们的指南中阅读更多关于催化剂和它的惯例、模式和反模式的内容。

工具

我们为开发者提供了一套开源的linter配置。对于一般的代码实践,我们有eslint-plugin-github。我们还有eslint-plugin-custom-elements,它为编写Web组件提供了进一步的检查。将这些提取到开放源码仓库,使我们能够从单体中删除代码,但保持一致。

我们也有内部测试来验证开发人员是否遵循了最佳实践,并确保他们不会继续使用已废弃的模式和行为。我们的一个测试确保一个被废弃的 “脸谱 “模式不会被引入代码库,并建议使用<details-dialog>元素作为替代。

class FaceboxDeprecationTest < Test::Fast::TestCase
  EXPECTED_NUMBER_OF_FACEBOXES = 44

  # Find facebox triggers set with rel=facebox, in either HTML attributes or
  # as part of hash assignment (for rails helpers)
  REGEX_FOR_FACEBOX_BINDING = %r|rel\s*[=:]>?\s*["']?facebox|
  REGEX_FOR_DATA_FACEBOX = %r|data-facebox\s*=>?\s*|

  def test_limit_facebox
    actual_rel_facebox = grep(REGEX_FOR_FACEBOX_BINDING, options: %w[-In], paths: %w[app/**/*.erb])
    actual_data_facebox = grep(REGEX_FOR_DATA_FACEBOX, options: %w[-In], paths: %w[app/**/*.erb])
    count = actual_rel_facebox.count("\n") + actual_data_facebox.count("\n")

    assert_operator count, :<=, EXPECTED_NUMBER_OF_FACEBOXES, <<-EOL
It looks like you added a facebox. Please use <details-dialog> instead.

If you must increment EXPECTED_NUMBER_OF_FACEBOXES in this test, please
/cc @github/ui-frameworks-reviewers in your pull request, as we may be able to help! Thanks.
EOL

    assert_equal EXPECTED_NUMBER_OF_FACEBOXES, count, <<-EOL
It looks like you removed a facebox. YOU ARE AWESOME! ? ? ? ? ?
Please decrement EXPECTED_NUMBER_OF_FACEBOXES in this test and treat yourself to
something special.  You deserve it.
EOL
  end
end
复制代码

我们的网络组件的新生命周期

从一个特定的应用程序的前端行为到一个开源的Web组件的道路始于单片机代码库中的催化剂组件。那些适合提取的组件会被概括成一个强大的、严格的行为、无依赖性的Web组件。

在单体中,工程师们可能会对想法进行原型化,并在不断修改的同时使用功能标志慢慢地将其交付。在组件经过一段时间的生产测试后,我们会寻找机会将组件提升到自己的仓库中。我们也会定期评估代码库,以找到可重用的模式、通用的行为,或者那些有令人信服的理由被提升到自己的仓库的组件。

从催化剂开始

我们鼓励开发者在dotcom monolith内开发用户界面时编写Catalyst组件。从一开始就使用Catalyst的好处是,这个库可以抽象出一些编写Web组件的常见陷阱,并强制执行最佳实践。

注册一个Web组件可能会产生一些模板,但我们通过命名惯例和洒上TypeScript装饰器使其变得简单。催化剂中的动作使事件监听比管理全局事件监听器更容易。突变现有HTML的目标比在浏览器中渲染HTML模板更好。

从单体中提取一个组件

当组件包含在我们的应用程序中时,当它们在不同的环境中被使用时,可能会有特定的应用程序代码被添加到它们中。当你有特定的需求需要满足时,应用特定的代码是可以的,但如果一个组件要在其他情况下工作,它就需要灵活和通用。大多数情况下,这是以硬编码选项的形式出现的,应该使其可配置。归纳出一个组件,使其更具有可移植性,这对其他团队的重复使用至关重要。

在提取催化剂组件之前,我们删除了催化剂的特定功能,并将其转换为普通的网络组件。为什么要删除团队声称能使编写Web组件更容易的库?虽然Catalyst对开发者有好处,但我们希望我们的组件是零依赖性的。要求GitHub组织以外的开发者在为组件贡献代码之前了解Catalyst,是我们不希望发生的额外摩擦。

开源组件意味着特殊要求

虽然单片机组件可能与特定的应用逻辑紧密耦合,有第三方的依赖性,并依靠现有的测试,但我们对开源组件有一套不同的标准。我们的开源组件应该有接近0的依赖性,与框架和库无关,轻量级,无风格,与任何其他组件解耦,并且应该只做一件事,而且是一件好事。

虽然我们希望我们的组件是无依赖性的,但我们也希望从单体中获得同样的健壮性保证,这包括类型。我们将TypeScript定义与我们的组件一起,也使用ES模块编写,以使捆绑器能够轻松消费它。我们还确保有一个完整的测试套件和linter设置,使用我们的标准化配置。

<typing-effect>元素就是一个经历了开源生命周期的组件的优秀例子。GitHub内部的一个产品工程团队最近制作了一个灵感来自终端的用户界面原型,其中的文字看起来就像有人在打字一样。在之前的一个项目中,我们使用了优秀而强大的typed.js来制作打字动画,因此该团队最初再次使用了这个库。

该团队已经建立的UI部分是轻量级的,而我们的工具识别出在页面上添加typed.js将使捆绑的大小增加五倍。UI系统团队要求产品工程团队考虑其他选择。我们发现,我们对这个应用程序所需要的功能是有限的,因此值得尝试自己建立它。

产品工程团队为新的用户界面编写了我们自己的打字动画的第一个版本。使用Catalyst,它花了不到一天的时间和不到40行的代码。意识到其他团队可以使用这种效果,我们决定把它放到生命周期的步骤中。我们重构了这个组件,使其没有依赖性,将其从Catalyst库中 “弹出”,并将该组件作为<typing-effect>开源。

结果

总的来说,我们对自上一篇文章以来对GitHub前端所做的改变感到非常兴奋。根据我们进行的内部开发者调查,我们的开发者对Catalyst和ViewComponent非常满意

开发者喜欢ViewComponent的封装,使其更容易测试UI并增加开发者的信心。开发人员认为Catalyst是一种从 “旧式 “JavaScript中获得的可喜变化,而不需要大规模地跳跃到一个不同的框架或范式。

下一步是什么?

我们正在继续以 “GitHub元素 “的名义开放更多的通用开源行为网络组件。我们在 github.com/github/gith… 上有这些元素的集合,它与我们在 webcomponents.org 上的页面同步。

我们对Web Components的未来感到兴奋,并继续关注对HTML规范的修改建议。最近,我们最兴奋的两项提议是模板部件声明式阴影DOM提议。这些建议将使工程师们更容易发布Web组件,并将解决我们对Web组件当前状态的一些共同痛点。我们已经在一个ponyfill中实现了模板部件的最小可行部分,目前正在生产中使用,我们非常希望看到它在更广泛的社区中得到推广。

特别感谢

感谢Keith Cirkel启动这篇文章,感谢Ben Scofield和Joel Hawksley审查这篇文章,感谢Nick Holden与我们合作,提取<typing-effect>元素。


通过www.DeepL.com/Translator(免费版)翻译

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享