-
Notifications
You must be signed in to change notification settings - Fork 211
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
了解 Babel 6 & 7 生态 #25
Comments
额,好像现在是习惯性的引入babel-polyfill; 其实关于babel-core这个库,如果使用webpack的话,自然会有babel-loader,但是现在loader又不依赖babel-core,是不是一般都不用加入项目的依赖了 |
@mengxingshike2012 "peerDependencies": {
"babel-core": "^6.0.0",
"webpack": "1 || 2 || ^2.1.0-beta || ^2.2.0-rc"
}, |
我只用了这三个 babel-preset-env + babel-polyfill + whatwg-fetch 。 |
@lgh06 才知道 是个不错的选择,不过看起来它是依赖指定node版本或者browser版本来决定引入哪些polyfill的;如果不用内置对象原型上的方法, |
太喜欢Array.from、forEach、Promise,没办法不污染原型了…… 新浏览器里面都内置了,也不能算污染…… |
有个小问题。比如你引用了一些第三方库,直接require是使用的编译后的文件。但是如果第三方库作者使用了es6并且没有使用相应的polyfill来转换类似于for(item of list) 这种语法转换的时候会变成Symbol。造成某一些环境下对其不支持的错误。这应该是开发者本人来引入polyfill解决还是第三方作者在转换的时候就应该引入polyfill转换?还是说是babel本身的一些问题 |
@For-me 我觉得是库作者的责任,他应该提供转换后的可用库文件,或者明确告知使用者必须自己转换。 |
为什么vue-cli生成的项目里,同时使用了 .babelrc: {
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-vue-jsx", "transform-runtime"],
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"]
}
}
} |
@xwenliang 很好的问题。 我仔细查阅了文档,答案是 在 详情可见: 可以看到 vuejs-templates/webpack/ 引入的是 1.3 的 |
@creeperyang 专业👍 |
react不需要同时 用transform-runtime和babel-preset-env ,感觉和vue有关系,或者react里有的工作被babel-preset-react做了 |
请教作者vue-cli 使用的babel-preset-env 是@1.x ,有不能很好地消除未使用的polyfill的缺点,那么为什么不直接使用transform-runtime而是即使用env又使用runtime,这样重复不会造成打包体积变大吗。并且我没发现vue-cli中有useBuiltIns: true。 |
@lawpachi 这个可能是应为transform-runtime对实例方法的支持不是很好,所以只只能结合polyfill来进行转码 |
|
@creeperyang babel7 这里这一段讲的应该是有问题的:
是的, 但是babel-polyfill里面包含了regeneratorRuntim,只要使用了babel-polyfill,就可以支持这个generator。否则就要使用transform-runtime+babel-runtime来支持了 |
@cuiyongjian 赞同第一点,实际操作了一下,entry应该是按照目标浏览器的兼容性把所有需要的polyfill都放上去, |
包括拆分后的runtime-corejs2也不支持添加instance method。 |
@cuiyongjian @YardWill 其实按你们的说法,既然polyfill全引入了,怎么还会有 对于 可以打开
|
我自己的使用結果是,給您們做參考。
如果有用 比較起來 |
我尝试了一下仅用这个preset,然后在index内加上import '@babel/polyfill';使用async await 并没有报ReferenceError: regeneratorRuntime is not defined |
@creeperyang 你也可以看一看最后打包出来的文件,看一下有没有这句代码。我按照上面的配置是能搜索到的。
|
@YardWill 理解你的意思了。你手动引入了 所以我的意思是对的:设置 |
@creeperyang 多谢指教,不过我还有一个问题https://github.com/babel/babel/blob/master/packages/babel-preset-env/src/index.js#L286 为什么entry还需要自己引入polyfill?
|
以一个简单示例来说明。有文件 async function hello(a) {
console.log(a);
}
hello(Promise.resolve(1)); 我们用不同的babel配置来验证一些东西。 1. 如果只设置 可以看到,由于 "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 hello(_x) {
return _hello.apply(this, arguments);
}
function _hello() {
_hello = _asyncToGenerator(
/*#__PURE__*/
regeneratorRuntime.mark(function _callee(a) {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
console.log(a);
case 1:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
return _hello.apply(this, arguments);
}
hello(Promise.resolve(1)); 2. 如果只设置 可以看到文件开头引入了需要的 同时( "use strict";
require("regenerator-runtime/runtime"); // 污染全局,提供 regeneratorRuntime (代码`runtime = global.regeneratorRuntime = inModule ? module.exports : {};`)
require("core-js/modules/es6.promise"); // 污染全局,提供 Promise
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 hello(_x) {
return _hello.apply(this, arguments);
}
function _hello() {
_hello = _asyncToGenerator(
/*#__PURE__*/
regeneratorRuntime.mark(function _callee(a) {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
console.log(a);
case 1:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
return _hello.apply(this, arguments);
}
hello(Promise.resolve(1)); 3. 设置 可以看到,上面的inline代码(如_asyncToGenerator等)被替换成 但( "use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
// @babel/runtime/regenerator 依赖 regenerator-runtime/runtime,但以不污染全局的方式引入。
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
// 然后还是会引入regenerator-runtime/runtime;有重复引入和污染全局的问题;
// TODO:这里需要注意一下!问题待跟进
require("regenerator-runtime/runtime");
// 其实可以看到,core-js 我们并没有作为依赖,但这里却引入了。
// 这一块详见 <https://babeljs.io/docs/en/v7-migration#babel-runtime-babel-plugin-transform-runtime>
require("core-js/modules/es6.promise");
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
function hello(_x) {
return _hello.apply(this, arguments);
}
function _hello() {
_hello = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee(a) {
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
console.log(a);
case 1:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
return _hello.apply(this, arguments);
}
hello(Promise.resolve(1)); 4. 设置 对比下上面,可以发现 "use strict";
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs2/regenerator"));
require("regenerator-runtime/runtime");
// promise 指向 @babel/runtime-corejs2/core-js/promise,被修复正确
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/asyncToGenerator"));
function hello(_x) {
return _hello.apply(this, arguments);
}
function _hello() {
_hello = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee(a) {
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
console.log(a);
case 1:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
return _hello.apply(this, arguments);
}
hello(_promise.default.resolve(1)); |
@creeperyang 我想了解您說的未手動安裝是指 另外
這段我也有找到,但是我自己測試的情況是,在 我有試過用 |
@HsuTing 我说的 手動安裝 更多的意思是必须自己指定 |
现在对generator这里更明白一点了:
写了一篇长文,啰嗦了这些实验过程.. |
有项目地址吗 |
了解
Babel 6
生态现在写一个babel的简介好像已经不太必要了(太晚了😄 )。但大多数情况下,会配置
babel
来编译代码,不代表我们清楚babel
的概念,而且Babel 6
相关的多个babel-xx
包还是容易让人混淆的。所以这里还是希望帮助理清整个Babel 6
生态。参考:
Babel 6
的核心特性(相比5的巨大变化)我刚开始用
babel
的时候,版本是5,一个月后Babel 6
发布——变化简直天翻地覆。相比前一版本,
Babel 6
最大的变化是更模块化,各种内置库都被分散到独立的模块;其次,让所有插件可选,这意味着Babel默认不会编译ES2015代码,并且所有的transformer完全独立;同时,为了减少配置的复杂性,引入了preset;最后,提升了性能。下面列出一些
Babel 6
的核心模块/变化:babel
package被弃用。我们可以看[email protected]的源码,两个提示很明显:
babel-core
。babel-cli
。babel-core
是babel的core compiler,主要用来对你的源码跑一系列变换(transform)。但默认情况下,不会应用任何变换——你必须自己安装和注册这些变换。babel-cli
是babel的command line,有babel
/babel-external-helpers
/babel-node
3个命令。babel-doctor
已被移除,见Moving babel-doctor to a separate package/removing babel/babel#4678。babel
即用于编译代码。babel-external-helpers
用于生成一段js代码(里面是一些helper函数)。这些helper如果被用到,一般被置于生成代码顶部(公用),所以生成的代码不会有内连这些helper好几遍。但是如果你有多个文件的话,你可能又要重复这些helper好几遍了。所以你可以生成这样一份代码,然后在每个文件中直接引入(node通过require
,browser通过<script>
)。详情见external-helpers。babel-node
是方便开发的node二进制(非生产使用),内置了babel-polyfill
,并用babel-register
来编译被require的模块。babel-register
,require hook
,替换了node的require
。node_modules
内的模块,则使用node的require
。require
,自动编译模块。Babel 6
的plugins
详情见https://babeljs.io/docs/plugins/。
这里不多说,只简单说两点:
plugins
。babel-preset-es2015
包括了完整的ES2015
特性,引入它即可编译ES2015
代码到ES5
。用transform还是polyfill实现?
babel-core
仅仅聚焦于code transform,所以不是什么事都可以用babel
来转换的。比如,检索上面的plugins列表,你会发现没有一个plugin用来转换
Promise
;事实上,如果环境不支持Promise
,你应该自己引入相应polyfill。那么什么时候应该用tranform,什么时候该用polyfill呢?如果一个新特性你可以用
ES5
实现,那么,你应该用polyfill,比如Array.from
。否则,你应该用transform,比如箭头函数。babel-polyfill
vsbabel-runtime
这可能是babel中最让人误解的一组概念:当你需要支持
ES2015
的所有特性时,究竟用babel-polyfill
还是babel-runtime
?babel-polyfill
和babel-runtime
是达成同一种功能(模拟ES2015
环境,包括global keywords
,prototype methods
,都基于core-js
提供的一组polyfill和一个generator runtime
)的两种方式:babel-polyfill
通过向全局对象和内置对象的prototype上添加方法来达成目的。这意味着你一旦引入babel-polyfill
,像Map
,Array.prototype.find
这些就已经存在了——全局空间被污染。babel-runtime
不会污染全局空间和内置对象原型。事实上babel-runtime
是一个模块,你可以把它作为依赖来达成ES2015
的支持。比如当前环境不支持
Promise
,你可以通过require(‘babel-runtime/core-js/promise’)
来获取Promise
。这很有用但不方便。幸运的是,babel-runtime
并不是设计来直接使用的——它是和babel-plugin-transform-runtime
一起使用的。babel-plugin-transform-runtime
会自动重写你使用Promise
的代码,转换为使用babel-runtime
导出(export)的Promise-like
对象。注意: 所以
plugin-transform-runtime
一般用于开发(devDependencies),而runtime
自身用于部署的代码(dependencies),两者配合来一起工作。那么我们什么时候用
babel-polyfill
,什么时候用babel-runtime
?babel-polyfill
会污染全局空间,并可能导致不同版本间的冲突,而babel-runtime
不会。从这点看应该用babel-runtime
。babel-runtime
有个缺点,它不模拟实例方法,即内置对象原型上的方法,所以类似Array.prototype.find
,你通过babel-runtime
是无法使用的。require('babel-polyfill')
),这会导致代码量很大。请按需引用最好。The text was updated successfully, but these errors were encountered: