不要肆无忌惮地在你的项目中使用 ES78910 了~

34,209 阅读4分钟

如果我有故事,你有 star 吗~

故事背景

在一次 code review 中,我在我们的项目(项目基于 vue-cli 3 创建)中找到了这句代码 MDN

[1, 2, [3, 4, [5, 6]]].flat(Infinity); // [1, 2, 3, 4, 5, 6]

嗯嗯~多维数组扁平化,很酷炫霸拽吊炸天~

我再一看兼容性..

图片

打扰了..

先脑补一波互怼的画面

我 : 老哥,你这个 API 是 ES2019 新特性啊,万万使不得啊~

图片

同事: 我有 vue-cli 3 啊~ 他封装好了 Babel 啊, 我大 vue-cli 3 天下无敌啊~

我 : 我...我真想跳起来打他的膝盖啊~ 凭一句话 好像是毫无说服力啊,是时候表演真正的技术了..

说(睡)服同事

core-js

Modular standard library for JavaScript. Includes polyfills for ECMAScript up to 2019: promises, symbols, collections, iterators, typed arrays, many other features, ECMAScript proposals, some cross-platform WHATWG / W3C features and proposals like URL. You can load only required features or use it without global namespace pollution.

core-js 是 babel 转码的核心包,它使用 es5 API实现了一些 ECMAScript 到 2019 年的 polyfills,并且提供按需加载,且使用它不污染全局名称空间。

@babel/preset-env

@babel/preset-env is a smart preset that allows you to use the latest JavaScript without needing to micromanage which syntax transforms (and optionally, browser polyfills) are needed by your target environment(s). This both makes your life easier and JavaScript bundles smaller!

@babel/preset-env 是一个智能插件集合,允许您使用最新的 JavaScript ,而不需要对目标环境所需的API转换(以及可选的 browser polyfills)进行微管理。这不仅使您的生活更轻松,而且 JavaScript 包也更小!

下面我们简单了解一下它的其中两个核心配置项.

useBuiltIns

"usage" | "entry" | false, defaults to false.

(提供"usage" | "entry" | false 三个配置项,默认值为 false)

This option configures how @babel/preset-env handles polyfills.

(这个配置项用来决定@babel/preset-env 如何处理 polyfills)

When either the usage or entry options are used, @babel-preset-env will add direct references to core-js modules as bare imports (or requires). This means core-js will be resolved relative to the file itself and needs to be accessible.

(当使用 usage 或 entry 配置项时,@babel-preset-env 将直接(entry)引用(或按需(usage)引入)core-js 模块,这意味着 core-js 将对文件本身进行解析)

Since @babel/polyfill was deprecated in 7.4.0, we recommend directly adding core-js and setting the version via the corejs option.

(由于@babel/polyfill 在 7.4.0 中被弃用,我们建议直接添加 core-js 并通过 corejs 选项设置版本。)

corejs

2, 3 or { version: 2 | 3, proposals: boolean }, defaults to 2.

(指定 corejs 版本,2 或 3,默认值为 2)

This option only has an effect when used alongside useBuiltIns: usage or useBuiltIns: entry, and ensures @babel/preset-env injects the correct imports for your core-js version.

(此选项只有在 useBuiltIns 选项配置为 entry 或 usage 时才生效,并确保@babel/preset-env 为您的 core-js 版本注入正确的引入)

Ok,接下来我们来看一哈 Vue-cli 3 的 babel 配置~

// babel.config.js
module.exports = {
  presets: ['@vue/app']
};

可以看到 vue-cli 3 这边用的预设集合是自己封装的@vue/app,我们在 node_modules 找到@vue/app 的 package.json

图片

// package.json

"dependencies":{

  "@babel/preset-env": "^7.0.0 < 7.4.0",

  "core-js": "^2.6.5"
}

可以看到依赖里有 core-js 2.x 版本和@babel/preset-env ~

打开@vue/app 的 index.js

//index.js  部分代码

const envOptions = {
  spec,
  loose,
  debug,
  modules,
  targets,
  useBuiltIns, //  划重点,此处值 已定义为 'usage'
  ignoreBrowserslistConfig,
  configPath,
  include,
  exclude: polyfills.concat(exclude || []),
  shippedProposals,
  forceAllTransforms
};

presets.unshift([require('@babel/preset-env'), envOptions]);

由上,我们可以得出结论,vue-cli 使用的 vue-preset-app 封装了@babel/preset-env`,且配置

useBuiltIns: 'usage';

corejs 没做配置,所以为默认值 2

useBuiltIns: 'usage';
corejs: 2;

这么一看,结合我们上面所讲知识,flat 是应该会被转成 es5 咯 ? 啪啪啪,打脸?

倔强的我上 github 打开了 core-js

图片

奇怪的是,我在 core-js 2.65 版本里并没有找到 flat API的实现.

图片

求知欲爆炸的我,翻了 core-js@3 的文档,找到了以下这段话

图片

发现 Array.prototype.flat API是在 core-js@3 才加入的。

图片

结论

vue-cli 3 使用的是 core-js2.x 版本,所以并不能转义 Arrary.prototype.flat 这个API。

实践

得出理论 不实践一波 好像不符合我的风格啊~

npm init -y

npm i @babel/core @babel/preset-env -D
const babel = require('@babel/core');

const code = `[1, 2, 3, 4, [5, 6, [7, 8]]].flat(Infinity);`;
const ast = babel.transform(code, {
  presets: [
    [
      '@babel/preset-env',
      {
        useBuiltIns: 'usage',
        corejs: 2
      }
    ]
  ]
});
// 用core-js@2 来看看转码后的结果
console.log(ast.code);

// "use strict";

// [1, 2, 3, 4, [5, 6, [7, 8]]].flat(Infinity);
const babel = require('@babel/core');

const code = `[1, 2, 3, 4, [5, 6, [7, 8]]].flat(Infinity);`;
const ast = babel.transform(code, {
  presets: [
    [
      '@babel/preset-env',
      {
        useBuiltIns: 'usage',
        corejs: 3
      }
    ]
  ]
});
// 用core-js@3 来看看转码后的结果
console.log(ast.code);

// "use strict";

// require("core-js/modules/es.array.flat");

// require("core-js/modules/es.array.unscopables.flat");

// [1, 2, 3, 4, [5, 6, [7, 8]]].flat(Infinity);

ok~ 完美验证结论! 代码地址

vue-cli将在version 4 支持core-js 3

图片

思考

不可否认 vue-cli 是一个非常优秀的脚手架,它提供了一个很 nice 的工程化解决方案。

webpack 构建

babel 编译

postcss 兼容

...

我在一些简历上 经常看到 熟练使用 xxx 脚手架,难道我们应该熟练的是使用脚手架吗 ?

我们在享受工具带给我们的便利跟快感时,是不是也应该想想自己对前端工程化了解多少呢 ?