公众号
前言
如果喜爱我的文章,欢送关注微信公众号:前端学社。精彩内容不容错过
思考问题
带着一下三个问题阅读文章,上面三个问题也是面试中常常会被问到的,因为作为工具开发者(这里要和业务项目区离开) 如果想提供一个高质量的npm包给他人应用,必然会遇到以下问题
@babel/runtime
的庐山真面是什么?@babel/plugin-transform-runtime
又是什么?@babel/runtime
和@babel/plugin-transform-runtime
之间是什么关系?
@babel/runtime是什么
咱们先看一下一个代码演示
Demo代码仓库地址 tutor-runtime01
step1: 装置npm包
npm install --save-dev @babel/cli @babel/core @babel/preset-env
step2: 批改.babelrc
配置文件内容
{ "presets": [ [ "@babel/preset-env" ] ]}
转换之前的代码:
async function foo () { return 1}
因为async 在 chrome55版本 才反对,所以咱们设置指标环境配置表文件 .browserslistrc
内容如下:
# async 在 chrome55版本, 50版本不反对 asyncchrome 50
执行npm run build
,查看转换后的后果
"use strict";function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }function foo() { return _foo.apply(this, arguments);}function _foo() { _foo = _asyncToGenerator(function* () { return 1; }); return _foo.apply(this, arguments);}
转换之后,发现@babel/preset-env
在做语法转换的时候,注入了这些函数申明,以便语法转换后应用。这些函数申明称之为辅助函数。
问题来了,假如你是工具开发者, 编译并公布后的npm包外面 蕴含了很多相似 asyncGeneratorStep
和_asyncToGenerator
自定义辅助函数。如果有一个业务的我的项目,依赖了10个npm包,每个npm包都自定了相似 asyncGeneratorStep
和_asyncToGenerator
自定义辅助函数, 相当于反复减少了10次,这样会导致包的体积十分大。所以,接下来要解决如何将雷同的辅助函数共用。
如何解决呢?
答案: 把这些辅助函数申明放到一个npm包外面,须要的时候间接通过import
或require
形式从npm包引入。这样即便在多的文件,然而引入门路是一样的。通过webpack这一类的构建工具打包的时候,npm包只会引入一次,达到了复用的成果。
那么有没有将所有可能须要的辅助函数集中到一起的npm包呢?
答案: @babel/runtime
就是
此刻,你明确了什么是@babel/runtime
是什么了吗?如果不明确在看一遍后面的内容。
@babel/plugin-transform-runtime 是什么?
下面咱们提到,@babel/runtime
蕴含了所有辅助函,理论开发中,不可能手动引入@babel/runtime/helpers
外面的辅助函数。须要借助@babel/plugin-transform-runtime
的神奇力量。
其实@babel/plugin-transform-runtime
只做了以下两件事件。
- 1:主动移除语法转换后内联的辅助函数,应用
@babel/runtime/helpers
里的辅助函数来代替; 2:当代码里应用了
core-js
的API,主动引入@babel/runtime-corejs3/core-js-stable/
,以此来代替全局引入的core-js/stable
;如果你还不理解core-js 那么先去看看我之前写的文章《手把手教你如何配置Babel(2)——揭开core-js的面纱》
上面离开对这两局部进行demo演示:
先看一下如何 主动移除语法转换后内联的辅助函数:Demo代码仓库地址tutor-runtime02
装置npm包
npm i @babel/runtime npm i -D @babel/cli @babel/core @babel/preset-env @babel/plugin-transform-runtime
增加.babelrc
配置
{ "presets": [ [ "@babel/preset-env" ] ], "plugins": [ "@babel/plugin-transform-runtime" ]}
执行npm run build
查看后果:
"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));function foo() { return _foo.apply(this, arguments);}function _foo() { _foo = (0, _asyncToGenerator2.default)(function* () { return 1; }); return _foo.apply(this, arguments);}
能够看到,编译后的后果中,主动导入了所须要的辅助函数。
仔细的人可能发现了,本章节的两个demo中,并没有设置babel/preset-env
的参数。也就是 只做了语法转换,没有补齐API。那么@babel/plugin-transform-runtime
是如何补齐API的呢?让咱们提揭示持续往下看
如何补齐API
在《手把手教你如何配置Babel(3)—实在我的项目中如何去打补丁》章节外面,咱们通过如下形式全局引入polyfill
import `@babel/polyfill`//或者 import 'core-js'
这种形式是在全局补齐了API,对浏览器全局对象进行了从新赋值。例如 Promise,重写了window.Promise及其原型链
所以,当不想扭转或补齐浏览器的window.Promise,就不能手动的导入@babel/polyfill
或core-js/stable与regenerator-runtime/runtime
。此时,咱们能够借助@babel/plugin-transform-runtime
实现 API转换。
@babel/plugin-transform-runtime
参数很多,咱们先看一下corejs
。
corejs option | Install command |
---|---|
false | npm install --save @babel/runtime |
2 | npm install --save @babel/runtime-corejs2 |
3 | npm install --save @babel/runtime-corejs3 |
corejs:2和corejs:3区别
- corejs值为2:仅反对全局变量(例如:Promise)和动态属性(例如:Array.from)
- corejs值为3:不仅反对反对全局变量(例如:Promise)和动态属性(例如:Array.from),而且还反对实例属性(例如:[].includes)
所以3版本反对的性能更多,上面咱们用2版本做一个demo解说。3版本的demo,大家能够去下载源码看一下 - corejs:2代码仓库地址
- corejs:3代码仓库地址
配置.babelrc
{ "presets": [ [ "@babel/preset-env" ] ], "plugins": [ [ "@babel/plugin-transform-runtime", { //这里应用的2版本 对应须要装置npm install --save @babel/runtime-corejs2 "corejs": 2 } ] ]}
装置npm包
npm i --save @babel/runtime-corejs2npm i --save-dev @babel/cli @babel/core @babel/preset-env @babel/plugin-transform-runtime
编译前代码:
Promise.resolve()
编译后代码:
"use strict";var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));_promise.default.resolve();
参考文献
Babel
- Babel官网
- 99% 的前端开发者没弄明确的 babel 常识
- Babel 插件有啥用
- 一文搞清楚前端 polyfill
- @babel/plugin-transform-runtime
- @babel/plugin-transform-runtime 到底是什么?
browserslist
- browserslist
- browserslist 指标浏览器配置表
- browserslist详解
Monorepo
- Monorepo
- 应用 MonoRepo 治理你的前端我的项目
- NPM 模块中的scope