2020 年前端技术发展盘点
2020 年已经结束,这一年里面因为疫情,生活和工作中大家都有受到一定的影响。但是在 2020 年里面前端技术的发展依然没有停止脚步。
而我们作为前端开发者,必定需要对技术的更新换代有所了解。虽然我们不需要去学习所有新出来的技术。但是时刻保持 “了解” 和 “理解” 这些技术是有必要的。
了解这些新的技术和趋势,有效让我们成为更好的开发者,同时在我们日常工作中,这些知识有效帮助我们去解决工作中的技术问题,或者在一个问题中看到更多的解决办法和可能性。
这篇文章盘点了 2020 年里面,关于前端的一些新技术、它们的发展和趋势。
但是我们并不需要所有都去深入了解,我们的重点应该放在这几个方面:
“了解” 这个东西是做什么的
“理解” 这个东西是为了解决什么问题的
“知道” 这个东西可以怎么使用(使用场景)
「1」微前端 (Miro frontends)
"微前端" 应该是我们 2020 年里听的最多的一个前端技术。现在非常多的大厂都在尝试这个新技术来解决大型前端项目中的问题。
虽然我们前端开发中有模块化(modular)的组件(components),但是它相比后端的 “微服务” 是大有不同的。
在了解 “微前端” 之前,我们先给没有接触过后端的同学科补一下后端的 “微服务” 知识。
微服务是什么?
微服务是一种开发软件的架构和组织方法,其中软件由通过明确定义的 API 进行通信的小型独立服务组成。这些服务由各个小型独立团队负责。
上面的专业术语不好理解的话,我们也可以这么理解。微服务 —— 也就是把单独一个业务写成一个独立的服务,有独立的服务器、接口体系、并且有一个单独的团队进行开发与维护。
就比如,淘宝的订单和用户两个 “模块”。一开始这些模块我们可能都会设计在一起的。这样开发起来需要的开发资源和时间就相对比较小。毕竟微服务不是一个 5 - 6 人团队可以 hold 得住的。
等业务变得非常庞大的时候,随着功能和数据的不断在扩大和延伸。这个时候订单和用户模块都变得非常的复杂。这个时候就需要我们把这两个模块单独的拆离出来开发和维护。因为,如果我们不拆离出来,每次改这些模块的一个小功能,都会涉及很多影响。我们就会发现这个系统越来越难迭代,改一个功能或者 bug 都会开始变得非常的困难。
这个就是为什么后端提出了微服务这个概念,为了解决大型应用的维护难题。把业务解耦、隔离、独立化就是解决方案。
既然后端会遇到系统复杂程度过高的情况,自然前端的业务和交互也会越来越复杂。所以最后前端也需要和后端一起建立 “微服务化” 的体系。
微前端是什么?
微前端的起源和后端一样,就是一个模块因为业务和功能的持续发展,导致模块内容的代码越来越复杂,越来越庞大,同时就会造成与其他业务有不可避免的互相影响的关系。
就是这些模块与模块之间的关系,让我们的系统变得越来越难以维护,大大减低了开发的 “敏捷性”。
那么怎么办呢?我们就让一个大型的 app 的业务,按模块拆分成一个一个小的 “服务” 模块。这些小的模块会与后端的接口一样,放在单独的服务器上运行,同时也会有单独的小团队进行专门的开发和维护。
这种微型的独立前端架构体系和系统就叫做 “微前端”。
每个 “微前端” 应用的开发团队,拥有整个应用的生命周期中的自主性。这就包块独立开发、独立版本号管理、独立测试、独立打包、独立渲染、独立更新、独立部署。
在上面的图中,我们就可以看到微前端在一个研发中心里的组织架构。每一个微前端团队都会负责一个独立的业务模块。每一个模块都会有他们自己的核心业务。与其他业务的功能其实是相对独立的,但是业务的流程上他们就会通过数据流、交互流、接口等方面串联起来。
最终用户所体验到的系统,其实跟我们普通的应用没有什么区别。但是大型应用的开发和维护的角度来看,就获得了非常多的好处。
微前端的好处
自主性 —— 可以对每一个微前端应用进行独立的开发、部署、维护和扩展,而不影响其他微前端应用的功能。
专用性 —— 每个微前端应用都是针对一组功能而设计的,并专注于解决特定的问题。如果开发者逐渐将更多的代码增加到一项微前端应用当中,从而让这个微前端应用变得复杂时,那么我们可以将其再次拆分成多项小的微前端应用。
敏捷性 —— 微前端是由若干个小型独立团队形成的一个组织,这些团队负责自己的微前端应用。每个团队在小型而易于理解的环境中进行开发,并且可以更独立,更快速地工作。这个缩短了开发周期的时间。
灵活扩展 —— 通过微前端化应用,我们可以独立扩展组件和功能来满足其他应用的需求。这使团队能够适当调整基础设施需求,准确的衡量功能成本,并在服务需求激增时保持可用性。
轻松部署 —— 微前端支持持续集成和持续交付,可以轻松和放心的尝试新的想法,并可以在无法正常运行时独立回滚某一个应用。由于微前端应用直接都是独立的,所以问题只会发生在自己的应用当中,所以我们可以大胆的试验,更轻松地更新代码,并缩短新功能的上线时间。
技术自由 —— 微前端架构不遵循 “一刀切” 的方法。团队可以自由选择最佳的工具或者框架来解决他们的具体问题。也就是说一个微前端应用可能是用 Vue,然后另外一个可能是用 React 也不是不可以的。因此,构建微服务的团队可以自行选择最佳的工具或者框架。
可重复使用 —— 将前端应用划分成明确定义的模块,让团队可以将功能用于多种目的。专为某项功能编写的前端模块可以用作另一项功能的构建模块。这样应用程序就可以自行引导,因为开发者可以创建新的功能,而无需从头开始编写代码。
弹性 —— 前端应用独立增加了应用程序应对故障的弹性。在整体式架构中,如果一个组件出现故障,可能导致整个应用程序无法运行。通过微前端的拆分架构,应用程序可以通过降低功能而不导致整个应用程序崩溃来处理总体服务故障。
微前端案例
我们了解了微前端是什么,并且它有什么用。那么我们来看看一个微前端在实际开发场景中是怎么样的。
这里幻想一下,我们有一个博客的主页。主要的功能就是为了展示我们的文章内容。当然一个博客其实很简单,在正常开发场景下,也不会给它做微前端的架构设计。
但是如果我们真的想把它做的更强大,那也是可以的:
首先当用户进入我们的首页,可以看到文章的列表,并且用户可以通过关键词来搜索文章。同时也可以通过分类、标签来搜索。更复杂一点的话,我们还可以根据阅读量,热度(通过算法计算热度)来排序和搜索。
每一篇文章必然会有一个详情页,每个详情页都需要展示文章的详细文本。如果我们想加大难度的话,我们还可以根据标签和用户日常的文章浏览记录,来推算用户会对其他什么文章感兴趣。这个时候我们就可以加入相关推荐的文章列表了。
博客必然就会有博主的介绍页(About)、文章分类页(Categories)和文章标签页(Tags)。
当然这个还不是很复杂,但是当我们继续往这个博客平台加入更多的功能,比如最后做成 CSDN、掘金、知乎这样的平台的时候,那么微前端就有必要了!
微前端集成方法
好,如果真的有那么一天,我们变成一个很大的博客平台。那么我们要怎么运用微前端呢?其实集成方法有很多种:
服务器端模板组合 (Server-side template composition)
构建时集成 (Build-time integration)
通过 iframes 在运行时集成 (Run-time integration via iframes)
通过 JavaScript 在运行时集成 (Run-time integration via JavaScript)
通过 Web 组件在运行时集成 (Run-time integration via Web Components)
我们这里就不一一去讲解了,如果我们真的哪一天遇到一个场景需要我们用微前端去解决我们的技术难题时。我们再去深入学习微前端即可。这里主要的目的是让我们了解清楚微前端是什么,*能解决什么*,它是怎么解决的即可。
其实所有的集成方法,都围绕着一个很自然的设计模式 —— 一个应用里面的每一个页面都是一个 “单独的” 微前端应用。而在每一个页面中都会有一个“单独的应用容器(single container application),而它的作用就是:
渲染页面公共头部(headers)和脚步(footers)
解决 “横切关注点(Cross-cutting concern)”,比如身份验证和导航
把多个微前端应用放在一个页面之中,并且告诉每一个微前端应用在什么时候和在哪里渲染到页面上。
大概的页面设计如下:
注意我们这里只讲到微前端的皮毛,其实微前端最核心并不在前端,更多的难点都是在 “云服务器”。如果没有服务器架构、部署、测试和后端接口等等的支撑,微前端是很难以实现的。所以在一般公司的应用场景,其实根本用不上微前端。如果用不上,了解到这里其实已经可以了。到用得上的时候再去深挖更多的知识即可!
「2」原子设计 (Atomic Design)
原子设计也是在 2020 年里面提到的非常多的一个概念。不过这个更多只是一个概念,并不是一个纯方法论。
这个概念是 Brad Frost 提出的,他用化学中的原子组成来分析和拆解一个 web 应用的组成成分。里面包换原子(Atoms)、分子(Molecules)、生物体(Organisms)等。
比如一个搜索分子(Search Molecule)就是由 input-text
(输入文本)+ button
(按钮)+ label
(标题)等原子所组成。然后这些分子组合起来就会变成一个生物体(Organism)。
而生物体(Organism)就会生存在我们页面的布局模版之中,而这些就可以具体化成一个页面,最后显示给到我们的用户。
Brad Frost 把我们前端的组件和界面的设计抽象成化学中的原子组成结构。让我们更加清晰的去理解一个页面、一个组件、一个元素的组成方式。
其实这个概念,可以让我们用一个全新的角度去看待模块化 UI(modular UI)。这种思维方式让我们更深入的理解一个组件的作用和 API,从而在设计组件的时候会更加的清晰和高效。
一个简单易懂的表示图:
原子(Atom)是什么?
原子是物质的基本组成部分。而在组件设计中,原子就是一个组件的最小元素单位,一个组件都是用多个原子所组成的。
在 web 界面中,原子就可以是:HTML 标签
表格的 label
输入框 input
按钮 button
原子单独使用是没有任何意义的,一般都是需要组合其他原子一起使用才能真正发挥它们的作用。
分子(Molecule)是什么?
当我们把原子(Atoms)结合在一起时,事情开始变得更加的有趣。分子(Molecule)是一组结合在一起的原子,是化合物中最小的基本单位。每一个分子都有自己的特性,是我们设计系统的支柱(Backbone)。
比如,一个表格标题、输入框、按钮等元素,它们单独使用时没有太大用处的。但是如果我们把它们组合在一起,变成一个表格。这个时候它们就可以使用了。
在我们用原子组合分子时,我们需要遵循一个原则:“只做一件事,并且做好”。(这个听起来是不是有点像设计模式里面的:“单一职责”?是的,就是这个意思。)虽然分子可能很复杂,但根据经验,他们相对而然都是一些简单的原子而组成的,主要是为了可复用性而生。
生物(Organism)是什么?
分子可以作为我们组建界面的积木。我们可以把分子组合在一起来建立一个生物体(也就是我们的一个界面)。生物体是用一组分子组合而成的,而组成的生物体是界面的其中一部分,它有相对复杂,独特的特性。
就比如上图,我们在组合了一个网页 logo 部分的分子。然后我们把搜索分子和 logo 分子再组合在一起,就变成了界面上头部(生物体)的部分(header organism)。
这个就会开始变得越来越有趣了,生物体不是一个固定的组件,它是用多个分子所组合而成。不同的生物体可能存在使用相同的分子或者原子,但是他们的作用都是有所不同的。
就比如,我们的 logo 和文章图片两个不同的分子,他们都使用了 img
图片标签这个原子。但是这个 img
原子是放在了两个不同职责的分子里面,一个是用在头部作为 logo 展示的,一个是用在文章列表用来展示图片的。
所以在组建分子和用分子组件生物体的时候,我们创建的组件必须是独立的、可移植、可重用的。
模版(Templates)
有了分子组成的生物体(Organism)后, 我们就可以用这些生物体来组建我们的界面模版。这里我们就可以打破化学的类比,拥有对用户和最终输出更有意义的东西。
模版主要是由多个生物体缝合在一起而形成的页面。在这里,我们开始看到组件和模块的设计开始融合在一起,可以看到布局之类的东西开始有所体现了。
模版是非常具体化的,它为所有的这些相对抽象的分子和生物体提供了上下文。模版阶段也是用户可以开始看到设计界面的地方。根据这个设计的创作者 Brad Frost 的使用经验,模版一开始是 HTML 线框,但随着时间的推移,它的保真度会逐渐提高,最终成为可交付的产品。
页面(Pages)
页面(pages)是模版的特定实例。这里,占位符内容被真实的、有代表性的内容所取代,以准确地表现方式描述了用户最终将要看到的内容。
页面是最真实的,因为它们是最有形态的,它通常是大多数人在开发过程中花最多时间来处理和优化的部分。
页面这个阶段非常的重要,因为这里是我们测试设计系统有效性的地方。在上下文本中查看一切,是我们能够回头来修改我们的分子(Molecules)、生物体(Organism)和模版(Templates)的阶段。
页面也是测试模版变化的地方。例如,我们可能想清楚地表达包含 40 个字符的标题最终展示到给用户是什么样子的,但是也想演示 340 个字符是什么样子。当用户的购物车中有一件商品应用了折扣的时候,商品的展示会是怎么样的。这些实际的情况会影响我们如何循环和构建我们的应用。
为什么用原子设计理念?
我们简单理解了原子设计后,我们就可以问问,为什么要用原子设计呢?
其实答案很简单,我们平时去设计一个应用的时候,即使我们没有意识去使用这种思维方式,但是我们一直都是以这种方式在设计的。
原子设计为设计系统提供了一种清晰的方式轮(概念为主),团队成员(开发者、产品经理、设计师等)能够通过实际看到的,摆在他们面前的步骤来更好地理解设计系统的概念。
原子设计赋予我们从抽象到具体的能力。正因如此,我们可以创建促进一致性和可伸缩性的系统,同时在最终的页面中显示内容。
重点是通过组合而不是解耦的方式来构建应用。我们在一开始就创造了一个系统,而不是在事后才去挑选模式。
「3」封装样式和 Shadow DOM
组件开发最重要的一个方面是封装(Encapsulation)—— 就是能把标记(markup)和行为隐藏起来,并与页面上的其他代码分开,这样不同的部分就不会冲突,代码也可以保持整洁。
而要做到这样,Shadow DOM API 就是关键。它可以将一个隐藏的、独立的 DOM 附加到一个元素上。
Shadow DOM 允许将隐藏的 DOM 树附加到常规的 DOM 树中——它以 shadow root 节点为起始根节点,在这个根节点的下方,可以是任意元素,和普通的 DOM 元素一样。
这里,有一些 Shadow DOM 特有的术语需要我们了解:
Shadow host:一个常规 DOM 节点,Shadow DOM 会被附加到这个节点上。
Shadow tree:Shadow DOM 内部的 DOM 树。
Shadow boundary:Shadow DOM 结束的地方,也是常规 DOM 开始的地方。
Shadow root: Shadow tree 的根节点。
我们可以使用与常规 DOM 一样的方式来操作 Shadow DOM —— 例如,添加一个子节点、设置属性、以及为节点添加自己的样式,或者为整个 Shadow DOM 添加样式。
与普通 DOM 不一样的是,Shadow DOM 内部的元素始终不会影响它外部的元素(除了 :focus-within
),这为封装提供了便利。
其实 Shadow DOM 并不是一个全新的东西,它已经被浏览器使用了很长一段时间了。浏览器用它来封装一个写元素的内部结构,以一个有着默认播放控制按钮 <video>
元素为例。
我们所能看到的只是一个 <video>
标签,实际上,在它的 Shadow DOM 中,包含了一系列的按钮和其他控制器。Shadow DOM 标准允许我们自己的元素(custom element)维护一组 Shadow DOM。
这种方式也常常被认同为是组件样式封装的最佳解决方案。
基本用法
首先我们可以使用 Element.attachShadow()
方法来将一个 shadow root 附加到任何一个元素上。
这个方法接受一个配置对象作为参数,这个对象有一个 mode
属性,它的值可以是 open
或者 closed
:
open
: 表示可以通过页面内的 JavaScript 方法来获取 Shadow DOM, 例如使用 Element.shadowRoot
属性:
但是如果我们把 Shadow root 附加到一个自定义元素(Custom element)上,并且把 mode
设置为 closed
,那么我们就不可以从外部获取到 Shadow DOM 了 —— myCustomElem.shadowRoot 将会返回 null
。
其实浏览器中的 <video>
就是这样的,里面就包含了一个不可访问的 Shadow DOM。
如果你想将一个 Shadow DOM 附加到 custom element 上,可以在 custom element 的构造函数中添加如下实现(目前,这是 shadow DOM 最实用的用法):
将 Shadow DOM 附加到一个元素之后,就可以使用 DOM APIs 对它进行操作,就和处理常规 DOM 一样。
详细的使用方式,可以直接去看 MDN 的 《使用 shadow DOM》。
「4」TypeScript 的崛起
最近也有不少文章讲的好像 TypeScript 要一统整个前端江湖。有报告统计,80% 的开发者承认,他们想在下一个项目中使用或者学习 TypeScript。
虽然 TypeScript 还是有它的缺点的,但它让代码更容易理解(对于习惯编写面向对象的同学,确实好理解,但是不熟悉面向对象的同学,就有点难受了)。并且 TypeScript 有利于快速实现,上生产后的 bug 也更少。
那么我们应不应该转 TypeScript 呢?在决定之前,我们还是冷静一下,看看使用 TypeScript 的优缺点,然后根据我们自己团队的技术情况再做选择才是合理的。
使用 TS 的好处
1. 代码更容易理解
很多时候当我们在看一段代码中的一个函数,我们都会问以下问题:
1. 这个参数是可以接受那些的呢?
2. 函数会返回什么值呢?
3. 它需要什么外部数据呢?
4. 它做了什么可以把输入参数变成输出的返回值呢?
在动态类型语言中,通常很难回答前三个问题。
但是在像 TypeScript 这样的静态类型语言中,我们可以立即从 IDE 和编译器中得到上述的所有问题的答案。 不再需要查看整个代码库,不断地向我们的同事提出问题,或者在生产上出错误的风险。
2. 更容易,更快的实现代码
当我想要实现一个新的功能或者组件,我们的工作流大概是这样子的:
初始化组件函数,建立它的构造函数的参数,编写剩下的代码。
如果它需要任何外部或复杂的数据(如用户或文章),那么就要将它保存在我们自己的内存中,并在代码中使用它。
将组件放入你的应用中,并将 props 传递给它。
然后就是测试这个组件,手动或者使用单元测试(这里我们需要确保它能接收到该有的 props,并且它能正常工作。)
如果有什么地方出现了 bug,那么就要回到我们的代码,试着找到哪里出了问题。再回到第 1 步。
上述是在使用 JavaScript 的开发流,那么如果我们用的是 TypeScript 的话就会变得更简单,更高效了:
初始化组件函数,定义它的类型,并且实现它。
如果它需要任何外部或复杂的数据,直接查找它们的接口并复用它们(全部或部分)。
将组件放入你的应用中,并将 props 传递给它。
就是这样!(如果在调用者和被调用者之间正确地匹配了类型定义,那么一切都应该能够完美地工作。现在唯一需要测试的是组件的实际业务逻辑。)
是不是简单很多了?这个也是为什么 TypeScript 出现低级错误概的率会更少的原因。
3. 代码容易重构
在开发中,我们肯定是会有很多代码在编写后,都需要我们去重构的。但是因为往往都涉及太多的东西和文件,所以我们开发者一听到一个项目需要重构代码基本都是这样:
在 TypeScript 中,这类重构的事情变得不那么可怕。往往一个重构只需要轻轻在 IDE 中按一下 “重命名符号(Rename Symbol)” 命令即可。
在动态类型语言中,同时重构多个文件时,我们能得到的最好的帮助就是使用 RegExp 进行搜索和替换。
而在静态类型语言中,不再需要搜索和替换了。使用 IDE 命令,如“查找所有出现的情况”和“重命名符号”,可以看到应用程序中特定的函数、类或对象接口属性的所有出现情况。
如果我们想稍微改进我们的构建系统、重命名组件、还是修改对象或者删除废弃的属性,我们都不必担心破坏任何东西。TypeScript 会帮助我们找到重构后的这些相关联的东西的用法,重新命名它,并如果在我们重构后出现了类型不匹配的情况,它就会发出编译错误的警告。
4. 更少的 bugs
做了多年的前端开发,我们都知道如果有一个人在我们旁边,当我们拼写错变量名、使用了一个不一定会是 null 的值、或者传了一个对象类型参数给一个接收数组类型的函数的时候,能提醒一下我们,那么我们就可以省下 50% 的排错时间。
很高兴的告诉大家,这个好基友就是 TypeScript。
多谢它,现在想编写一个 bug 也变得相对难了。当我们的代码打包的时候,我们可以大概知道我们的代码是可以运行的通的。
5. 更少的样板测试
当我们确定我们传的参数是对的,那么我们就不用去测试所有地方调用了某个方法是否会报错,对方有没有用对参数,用对类型,用对我们提供的方法。
少了这些的顾虑,我们就可以更多的集中在编写业务逻辑的单元测试,而不是代码的语法和准确性的保障测试。
既然我们减少了检测代码中报错的问题,我们就可以花更多的时间来完成新功能和需求。这样我们的代码就不会很复杂,更不容易出错,更容易维护。
6. 帮助开发者写更好的代码
当我们在编写静态类型语言时,首先我们要思考,我们需要的数据类型是怎么样的,然后想我们想产出的数据又是怎么样的。这个过程就需要在我们坐下来开始写代码之前就要想清楚。
其实还有很多同学在开始实现一个功能和需求之前,缺乏了思考和分析。没有认真的思考过整个代码如何编写和逻辑的思路、实现的方法、数据的类型、函数的结构等。但是对于老司机程序员来说,很多都是先思考然后才去动键盘的。
那么 TypeScript 就会要求我们遵循这种好的开发思维。它鼓励我们在坐下来实现功能和代码之前,先要考虑清楚我们要实现的功能的接口类。
TypeScript 的缺点
说了那么多 TypeScript 的优点,我们也来讲讲它的缺点。
1. 需要编译步骤
如果我们是开发 node.js 后端的开发者,使用 TypeScript 确实会变得比较麻烦。因为我们需要先编译了 .ts
的文件,然后才能在 Node 上去运行。
当然如果我们有一个好的打包工具链,这个问题还是可以解决的。但是确实会给 Node.js 后端的同学带来本来没有的麻烦。
不过相对前端开发者来说,这个并不是任何问题。因为现代的前端开发流程,我们都会把所有的前端代码通过 webpack
、grunt
等打包工具来编译我们的代码。
那么 .ts
文件在这个过程已经自动的帮我们编译过来了。所以我们不需要做任何附加的步骤。顶多也是在打包工具中使用 npm
多安装一个编译插件。
2. 设置起来有点困难
不可置疑,这一点确实是事实。比如,在普通 Next.js 和使用 TypeScript 的 Next.js 之间,使用了 TypeScript 我们就要附加 Node.js 服务器、webpack 和 jest test 测试工具。
还有,当我们需要添加一个像 React、Redux、Styled-Components 等 library 的时候,我们都要为他们附加 typedefs
。(比如 @types/styled-components
,不过有一些包本身就自带有 TS typedefs 文件)
但我觉得这些问题并不大,因为在长期开发和维护一个项目的过程中,安装依赖包和设置一个 TypeScript 项目,相对比我们平时编写算法和业务逻辑的频率,其实是非常微小的一部分。基本上这些繁琐的事情都是一次过搞好就行,如果还是觉得繁琐,做一个 toolchain 工具,每次需要操作这些重复的事情的时候,直接用工具帮我们构建即可。
那要不要用 TypeScript 呢?
TypeScript 固然是好,毕竟 Vue 3 的重构中也在很多语言中最后选择了 TypeScript 作为他们的核心语言。
所以 TypeScript 的好处是显而易见的。但是任何的技术选型都要看我们自己所在的团队和公司。如果有 10 个开发者,9 个都不会 TypeScript,并且都不太愿意去学,或者公司根本给不到时间让我们团队去学习新的语言。
那么选择换这个语言就不是最佳的选择。
没有最好的技术,只有最合适当下使用的技术。
「5」Web 组件
Web 组件就是前端的未来。 为什么呢?
因为纯 web 组件与任何的前端框架无关,他们可以在没有框架或者使用任何框架的情况下工作。
因为这些组件更加不受 “JS 疲劳(JavaScript Fatigue)” 所控制,并且大部分浏览器都是支持的。
因为它们的包大小和消耗是更有优势的,加上 VDOM 渲染拥有令人震惊的能力。
这些组件提供了自定义元素、一个 Javascript API (允许我们定义一种新的 html 标记)、html 模板来指定布局,当然还有 Shadow DOM(本质上是特定于组件的)。
这里解释一下什么是 JS 疲劳 —— 就是当我们想学习前端的时候,第一个接触的语言必然就是 JavaScript,但是一旦开展学习后,就会发现这个水是真的深,一大窜的其他关联知识就会如同潮水一样扑面而来。包括,前端框架、Node.js、UI 框架、浏览器知识、工具链等等。学习前端一开始确实是一个非常疲劳的一个领域。
当我们思考未来 UI 开发,以及模块化、可重用性、封装性和标准化的原则时,组件(化)时代应该是怎么样子时,web 组件就会浮现在未来的蓝图上。
想了解更多关于组件化的知识,可以前往我的组件化系列文章:
这个系列还在持续更新中~
「6」状态管理:再见 Redux?
无论是 React 的 Redux 还是 Vue 的 Vuex 其实都是特别难搞的大魔头。尽管随着前端变得越来越模块化,在应用程序中的全局状态管理变得越来越难以控制。但是状态管理(State Management) 像 Redux 和 Vuex 的实用性和实用性使他们成为许多团队的首选解决方案。
所以我们在 2020 年之后可以和 Redux 说再见了吗?不,不完全可以。
然而,在前端框架中开始出现内部状态管理体系(如 React hook、Context-API 等),未来很有可能会废除掉对框架以外的状态管理的依赖。
像 Mobx,一开始这些类型的技术还很少被采用,但是由于它们面向组件和可延伸性的特性,仅仅在 2020 年这一年内,它们开始变得越来越流行,让我们开发者可以探索更多的选择。
想了解更多,可以去了解一下 MobX 的官方文档。
MobX 是一个经过战火洗礼的库,它通过透明的函数响应式编程(transparently applying functional reactive programming - TFRP)使得状态管理变得简单和可扩展。MobX 背后的哲学很简单:
任何源自应用状态的东西都应该自动地获得。
其中包括 UI、数据序列化、服务器通讯,等等。
「7」ESM CDN
ES 模块就是在浏览器使用模块时的标准,而 ES 模块就是被 ECMAScript 所标准化的。使用 ES 模块,你可以很容易地将功能封装到模块中,这些模块可以通过 CDN 来使用。
随着 Firefox 60 的发布,所有主流浏览器都将支持 ES 模块,Node mteam 正在努力向 Node.js 中添加 ES 模块的支持。此外,WebAssembly 的 ES 模块集成也将在未来几年内推出。
「8」渐进式网络应用(PWA)
渐进式网络应用也叫 Progressive Web Apps —— 它利用最新的技术将网页和移动应用程序结合起来。可以把 PWA 想成一个使用 web 技术的网站,但是行为和感觉是一个应用程序(APP)。最近在浏览器、服务的可用性 worker、Push APIs 的发展与进步,允许了用户在桌面安装 web 应用程序,甚至接收推送通知和离线工作。
由于 PWA 提供了亲密的用户体验,而且所有的网络请求都可以通过 service worker 被拦截。因此,必须将应用托管在 HTTPS 上,从而防止 “中间人” 攻击,这也意味着更好的安全性。
当然,PWAs 仍然有局限性,它们不能完全替代本地应用。(不过,它们真的需要那么做吗?)特别是,由于本质上是网页,PWAs 不能使用大多数硬件功能,如 NFC 和蓝牙。然而,并不是所有的应用程序都需要这些功能。
不过 PWAs 开发起来更快、更容易、更便宜,这就是为什么它们在 2020 年成为开发的趋势,并且在下一年肯定会继续成为趋势的原因。
「9」WebAssembly (WASM)
JavaScript 很棒,但是也不是没有缺点。 JavaScript 是存在性能问题的。所有解析型语言都面临同样的问题,而 WebAssembly 是解决这个问题的最新途径。
WebAssembly 最好的一个点是,它并不是一门全新的语言。我们可以用自己喜欢的语言来编写,然后将其编译成 WASM 文件,以便在浏览器中运行。WebAsssembly 目前支持的语言有 C/c++、Elixir、Python、Go、c#/.Net 和 Java。
WebAssembly 不是最近才有的,它已经上市好几年了。但它发展的迅速,提供了越来越多的选择。默认情况下,现在所有主流浏览器都支持它,如果程序员 能拥有它是一件非常有益的事情。
「10」可访问性(a11y)
可访问性,也叫 Accessibility —— 这是 web 应用层序开发中最重要的东西之一。我们相信可访问性,应该是每一个网站开发者的任务列表中的首要任务,不仅是新网站,而旧网站的更新也是一样。
可访问性(或 a11y)是一个计算机系统对用户的 “方便性” 的考量原则。网站应该能在各种设备上正常运行。但它们应该适用于各种“障碍”和“残疾”的用户。A11y 通常指软件和硬件的可访问性。
在网页开发方面,可以透过以下途径达成易读性:
更大或可自定义的字体大小
可选的高对比度的页面
支持语音合成/文本到语音的转换
视频字母
所有语音都附有文本
导航语音识别
纯语言文字
突出重要部分
一致的导航和尽可能少的步骤
简化授权(但不牺牲安全性)
用键盘导航,而不是鼠标/触控板
语义 HTML
a11y 这个名字来自于 “accessibility” 中有 13 个字母,所以在 “a” 和 "y" 之间有 11 个字母。但如果你仔细看,a11y 看起来像 “ally” 这个词 —— 意思是朋友、助手、拍档的意思。
「11」JavaScript 框架 (Frameworks)
最后我们来讲一下 2020 年中一些我们可以关注的前端框架。
Gatsby.js
Gatsby 是一个 SSG,全称是 Static Site Generator(*静态站点生成器*)。如果我们认为静态站点已经成为过去,反而它们是全新的技术趋势。
GatsbyJs 最大的优点之一是它不需要传统的服务器;它与 BYOC(Bring Your Own Content —— 自带内容)一起工作,可以基于 CMS、CSV、API 和 markdown 文件中的数据构建网站。Gatsby 还使用一种高端 API 查询语言 GraphQL 来构建数据层。
掌握 GatsbyJs 要求开发者了解 React Native 和/或 GraphQL,但我们不需要马上就有深入的知识 —— 我们可以同时学习 Gatsby + React Native + GraphQL,也就是边学着做 Gatsby 边学习 React 和 GraphQL。
因为 GatsbyJs 是一个 SSG,所以它非常适合开发电子商务网站。这个基于 React 的生成器,可以帮助我们在一瞬间就能加载完网站。我们这里说的不是秒,而是毫秒级的加载速度。任何电子商务企业所有者都知道,有时页面加载时的延迟,会对客户是否购买产品产生很大的影响。这个也适用于其他类型的网站。
Vue 3 - One piece
在 2019 年的 6 月底,Evan You(尤雨溪)和 vuejs 背后的团队发布了一个关于 Vue 3 框架的新迭代的 RFC(征求意见 —— Request For Comment),在社区中遇到了相当多的否定。但是最后这个事实证明,这些负面的反馈并没有那么影响 Vue 3。
一些 web 开发者陷入困境,因为 Vue.js 突然有了一个基于函数的组件 API(Component API)来取代大部分人已经熟悉的对象 API。然而,这并不完全正确,新的基于函数的组件 API 是对排序的补充,如果我们愿意,我们是可以与传统的对象 API 一起使用的。
Vue 3 组合 API 中的新语法具有更好的逻辑性,有助于更好的代码结构。一些开发者甚至说它稍微缩短了代码。而且 Vue 3 架构可以作为 Vue 2 的插件使用,只需要使用 Vue Composition(组合式) 库即可。
然后在 2020 年 9 月 18 日,Vue 3 的正式版发布了,命名为 One Piece(这个名字很多同学一看就知道来源于海贼王)。
Vue 3 带来的新特性
1. 性能
双向相应原理由
Object.defineProptry
改为基于 ES6 的Proxy
,这样使颗粒度更大,速度更快,从而消除了之前存在的警告;重写了 Vdom,突破了 Vdom 的性能瓶颈;
进行了模块编译的优化;
进行了更高效的组件初始化逻辑;
2. Tree-Shaking 支持
支持了 tree-shaking
(剪枝):像修剪树叶一样把不需要的东西给剪切掉,这样 Vue 3 的体积就变得更小了。
因为有了 tree-shaking
,vue 3 中的模块只有需要的时候才会被打入到包里。优化后, Vue 3 打包出来的体积将会是原来的一半(仅 13kb)。就算我们把所有的功能都引入了,打包出来也只有 23kb,依然还是比 Vue 2.x 更小。
有了这个,像 keep-alive
、transition
、甚至 v-for
都是可以按需引入了。
3. Composition API
其实 Composition API
的灵感来自于 React Hooks
, 它是比 mixin
更强大的存在。它可以提高代码逻辑的复用性,从而实现与模版的独立性;同时函数式的编程代码的可压缩性更强。
另外,Reactivity
在 Vue 3 中独立开来,意味着 Vue 3 的响应式模块可以与任何其他的框架相组合使用。
4. Fragments
不再限制 template
只有一个根结点。并且 render
函数也支持返回数组,有点像 React 中的 React.Fragments
。
5. 更好的 TypeScript 支持
Vue 3 拥有更好的类型推导,使得 TypeScript 的支持变得非常好。
6. 自定义 Renderer API
实现了用 DOM 的方式进行 WebGL
编程。
Svelte.js
Rich Harris 在 2019 年的 JSConf EU 上发布,Svelte(中文意思是 “苗条”)与 Vue 相似又不同。类似的是,它也是一个组件架构。然而,与 Vue 不同的是,Svelte 的组件编译器是在构建时(Build Time)运行的。这使得我们可以只加载需要展示目前 APP 的组件。我们不需要使用任何的虚拟 DOM(Virtual DOM)。
Svelte 使用一套简单的语法,使开发者能够从标记访问变量,而不是使用每个框架都不一样的状态包装器(state wrapper)。这就使得 Svelte 成为 web 开发新手的一个近乎完美的框架(就是非常好上手)。而对于有丰富经验的开发者来说,Svelte 意味着可以更快地编写代码,从而获得更高性能的网站。
在它发布之后的一年里,Svelte 经历了许多的重大改进和更新,最终形成了许多开发人员现在所说的,最简单和最漂亮的框架之一。
「12」CSS 框架
框架就是为了使一切变得更简单,其中包括被众多历史遗留困扰的 CSS。让我们看看 2020 年里 CSS 中流行的技术。
Houdini CSS
在最新的 web 发展趋势中,Houdini(取名于著名的魔术师 Harry Houdini)是一个非常独特的框架。基本上,Houdini 是一个 API 集合,为开发者提供了对 CSS 对象模型的访问。这个意味着,如果你需要 CSS 中还没有的样式,没有必要用 JavaScript 去修改或者覆盖。我们直接使用 Houdini CSS 架构,就可以编写被浏览器视为 CSS 并被解析的代码去操作样式。
使用这种方式可以使解析花费的时间更少,开发者不需要等待浏览器提供商扩展的 CSS,设计可以变得更加易于定制和更独特。
不过还有一个问题:并不是所有的主流浏览器都支持 Houdini。但是现在我们只能等待这个框架被所有主流浏览器支持。
Bulma
Bulma 是现代的行业趋势之一。他是用 Sass 扩展构建的,基于 CSS 灵活的框布局模块,或也被称为 Flex 布局。 Flexbox 是一个经常用于构建响应式网站的模块。
Bulma 是一个免费的开源 CSS 框架,它提供了一系列由社区创建的主题,这些主题都遵循这一个原则,就是尽可能的少写样式。由于使用了 Sass 构建,它实现起来非常简单,而且可以自定义。由于 Bulma CSS 代码的简单性,用它构建的网站通常与所有浏览器兼容,几乎没有问题。目前,它是开发者中最流行的 CSS 框架之一,而且看起来在 2021 年里面还是会保持这一个地位。
Tailwind
Tailwind CSS 框架已经存在一段时间了,但是在 2020 年才得到更高的关注度。
如果我们看谷歌的热度趋势图,我们可以看到 Tailwind CSS 的热度还在持续的往上升。
Tailwind 的特别之处在于它不是一个 UI 工具包,这使它与其他 CSS 框架不同。它没有内置的 UI 组件,相反, Tailwind 提供了一组部件(英文叫 widgets)来快速的开发出 UI 组件或者界面,而这些部件是使用一系列的 class 工具叫 Atomic CSS 。这意味着我们可以按照自己的需求从头开始构建或者自定义开发 UI 组件,而不被其他 CSS 框架提供的主题和样式所限制。
不过,我们需要熟悉这套 Atomic CSS 工具,这就使得对开发者来说使用 Tailwind 会更有一点挑战性和学习曲线。好的一面就是,它会给我们最自由的 UI 开发体验,并且可以快速实现 UI 组件样式和易于维护。
总结
在 2020 年里面,前端领域依然在高速发展中。新的技术在不停的涌出,已有的技术和框架也在不断的更新迭代。随着技术的发展,前端这个领域在 2021 年里面依然会继续以光速发展。
很多在前端领域的同学在很多群里都会说 “不要再更新啦,不要再出新的框架啦,学不动了~”
所以我们真的所有的新技术都要学吗?并不是的,重点是我们不要为了技术而技术,而是为了解决问题而学一门新技术。我觉得这个很值得我们深思的。
我反而觉得,重点不是框架那个以后发展更好,而是了解每个框架为什么存在,当下有什么问题导致有了这些框架,以后可能会有什么问题,可能需要什么东西来解决。
说到这里很多同学就会问,“那么我们应该往哪个方面发展呢“ ?
我觉得月影老师说的可以参考:
”基础和底层知识,基础和底层知识,基础和底层知识。”
因为所有框架也好,新技术也好。我们也不确定以后会出来什么,最后哪个可能会一统天下,或者那个会默默的隐退江湖。
所以重点是我们需要学习,保持可以快速上手任何框架和技术的能力。其实无论是 Vue,React,Angular 还是 Flutter。底层不都是 JavaScript 吗?甚至 Node.js 也是。然后更底层呢?不就是计算机基础知识吗?如果我们这些学通透了,那么以后出来什么各种花样,难道我们不能在一周内学会吗?(可能不能一周内,但是快速上手还是可以的嘛)
基础知识还有像数学,这些都是永世不会变的知识。而往往这些知识都是我们开发者的基础。而这些基础才是我们真正能适应这个技术高速发展的时代。也是这些基础让我们不会害怕任何的变化。因为我们拥有可以适应任何变化的能力。
我们需要关注前端每年的发展、热点、和趋势。但是不需要盲目的跟风,甚至去深入学习新的东西。更多是观望这些科技的发展,了解它们,当我们需要用到它们的时候再去深度学习它们,解决我们当下在项目中遇到的问题。这个才是正确的方向和心态。
开源项目推荐
Hexo Theme Aurora
最近博主在全面投入开发一个可以 “迈向未来的” Hexo 主题,以极光为主题的博客主题。
如果你是一个开发者,做一个个人博客也是你简历上的一个亮光点。而如果你有一个超级炫酷的博客,那就更加是亮上加亮了,简直就闪闪发光。
如果喜欢这个主题,可以在 Github 上给我点个 🌟 让彼此都发光吧~
主题 Github 地址:https://github.com/auroral-ui/hexo-theme-aurora
主题使用文档:https://aurora.tridiamond.tech/zh/
博主开始在 B 站直播学习,欢迎过来《直播间》一起学习。
我们在这里互相监督,互相鼓励,互相努力走上人生学习之路,让学习改变我们生活!
学习的路上,很枯燥,很寂寞,但是希望这样可以给我们彼此带来多一点陪伴,多一点鼓励。我们一起加油吧! (๑ •̀ㅂ•́)و
我是来自《技术银河》公众号的三钻,一位正在重塑知识的技术人。下期再见。
版权声明: 本文为 InfoQ 作者【三钻】的原创文章。
原文链接:【http://xie.infoq.cn/article/4e4dcd3895f4f537ac92eaa77】。未经作者许可,禁止转载。
评论