9

向 Modern JavaScript 转型

 3 years ago
source link: https://zhuanlan.zhihu.com/p/345085461
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

向 Modern JavaScript 转型

自 2011 年 browserify 诞生开始,到我们现在更为广泛应用的 webpack/ rollup / parcel 等构建工具的普及,构建及工程化已经变成了前端开发者的开发生态中不可或缺的部分。日常开发中,我们已经习惯跟随 ESMAScript 或 TypeScript 的新特性,这些特性往往具有更简单的语法、更高的执行效率,比较典型的例子就是 ES6 中 class:

class Person {
  constructor(name) {
    this.name = name;
  }

  greeting() {
    return `Hi, this is ${this.name}.`;
  }
} 

class Man extends Person {}

但如果要用构建函数和原型链去实现两个类的声明并实现继承,我相信大多数人会崩溃:

function Person(name) {
  this.name = name;
}

Person.prototype.greeting = function() {
  return `Hi, this is ${this.name}.`;
}

function Man(name) {
  Persona.call(this, name);
}
Man.prototype = Object.assign(Person.prototype);
Man.prototype.constructor = Man;

问题在于,这些提效的新特性并不能 100% 的运行在所有的浏览器中,比如上个时代的噩梦 - IE8. 在这样的背景之下,就诞生了 6to5 这样的编译器,来帮助我们把开发时的 ES6 的语法编译成 ES5 的语法,从而执行在浏览器中,当然 6to5 也跟随我们一起进化,变成了现在的 babel.

babel 也不是万能膏药,虽然帮助我们解决了语法的问题,但也带来了一些副作用,比如编译后的代码通常都会插入一些内置的函数或者 Pollyfill,这也就造成了代码体积的骤增,上文中我们 class Person 的源码实现总共 155B, 使用 babel 编译成 ES5 的代码后,体积变成了 2.7K !

从我们认为的 JavaScript 下一代的标准 的开始 -- ECMAScript 2015 到现在已经过去 5 年多的时间了,ECMAScript 每年都会不断的推进语言标准的更新,而浏览器厂商除了参与标准的指定,也在不断的跟进着新的语言标准在浏览器中的原生实现的支持。不知道你有没有注意到,在 2021 年的今天,class 的浏览器支持率已经达到了 95%, 所有的主流浏览器都已支持 class 特性:

类似于 class 这类特性,如果浏览器已经支持了,但我们还是把编译后的体积更大、执行更慢的 ES5 代码交给浏览器,不管是构建、存储、传输还是执行,无疑都是一种浪费。而这就关系到我们这篇文章的主题:Modern JavaScript.

什么是 Modern JavaScript

Modern JavaScript 指的不是哪一个特定版本的 ECMAScript 标准,而是指的一系列已经被现代浏览器所支持的特性的集合。

我们常说的现代浏览器包括:Chrome, Edge, Firefox, Safari, 它们占了浏览器市场份额的 90% 以上,除此之外,还有一些基于跟上述浏览器相同渲染引擎的浏览器实现,比如 UC, QQ 等也占了 5% 左右的份额。这也就意味着,我们广泛使用的一些特性已经得到了 95% 的支持,主要包括:

  • class
  • 箭头函数 arrow function
  • 构造器 generator
  • 块级作用域 let / const
  • 解构 destructuring
  • Rest 参数 rest and spread parameters
  • 对象简写 object shorthand
  • Async 函数 async / await

Modern JavaScript 不是一个固定的特性集合,它是动态跟随我们所定义的现代浏览器的的支持度的。就目前而言,ES2017 是最接近 Modern JavaScript 的标准。

Legacy JavaScript

对应 Modern JavaScript, 我们编译完的 ES5 的结果就可以称为 Legacy JavaScript, 它是我们向浏览器兼容器委屈求全的结果。

在现代浏览器中,这种转换是得不偿失:我们通过编译让我们的代码支持度从 95% 上升到了 98%, 然而这却给我们带来了 20% 的代码体积的上升,同时代码执行效率会变得更低。另外,在 node_modules hell 的加成下,这个影响可能是指数级的。

  1. 浏览器

<script type="module" />

现代浏览器支持通过 <script type="module" /> 直接在浏览器中 ES6+ 的代码,因此我们可以通过这种方式来为现代浏览器加载 Modern JavaScript, 而小部分的老浏览器则由 fallback 逻辑兜底,加载执行 Legacy JavaScript.

<script type="module" src="https://cdn/modern.js" />
<script nomodule src="https://cdn/ledacy.js" />

2. NPM

{ "exports": "./modern.js" }

[email protected]版本 中,引入了 package.json 中的 exports 字段,来增强原先仅能通过 main 声明的包入口的功能。

{
  "main": "./index.js",
  "exports": {
    ".": "./index.js",
	"./submodule": {
	  "import": "./submodule/index.js",
	  "require": "./submodule/index.cjs"
	}
  }
}

通过上面的入口声明我们可以实现对外暴露默认入口以及 submodule 的入口,并且 submodule 可以根据是 require 还是 import 提供不同的实现:

import pkg from 'pkg';

import submodule from 'pkg/submodule';
const submodule = require('pkg/submodule');

exports 除了提供了 多入口 以及 条件入口 等强大的功能外,也可以作为提供了 Modern JavaScript 实现的依据,因为 [email protected] 已经支持 ES2019 了,所以在构建时如果检测到 node_modules 中的模块提供了 exports entry, 可以为它们单独构建我们的 Modern JavaScript Bundle.

3. Bundle

通过上述浏览器和 NPM 包的对 Modern JavaScript 特性的支持,我们已经解决了出口的问题,并且在不支持的场景下也都可以 fallback 到 Legacy JavaScript 来执行。

接下来只需要资源构建的问题即可,我们需要提供满足 95% 的现代浏览器可执行的 Modern JavaScript Bundle 以及 fallback 剩余的老浏览器的 Legacy JavaScript Bundle.

通过 babel 配合不同的 browserslist targets 就可以简单的达成目标。当然也有一些现成的插件可以直接使用,比如 optimize-plugin, babel-esm-plugin 或者 babel-preset-modern-browsers 等。

而在构建模式上,我们可以选择从源码分别构建出 Modern Bundle 和 Legacy Bundle:

亦或是先从源码构建出 Modern Bundle, 然后从 Modern Bundle 再构建出 Legacy Bundle:

图片来源: https://web.dev/publish-modern-javascript/

Modern JavaScript 其实更像是一种理念,而不是一种技术,通过 Modern JavaScript 可以让开发者、用户享受到技术进步带来的福利,更甚者,Modern JavaScript 所带来的存储、传输、执行上的提升还能为地球 节能减排。

摆脱 ES5 的禁锢,向 Modern JavaScript 转型!

* Transitioning to modern JavaScript

* Publish, ship, and install modern JavaScript for faster applications

* Serve modern code to modern browsers for faster page loads

* Bringing Modern JavaScript to Libraries


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK