为什么 babeljs.io 输出与 gulp-babel 输出不同?

Why is babeljs.io output different than gulp-babel output?

背景

我正在尝试将我的 ES6 js 转换为 ES5 js。当我访问 https://babeljs.io/repl 网页以测试 babel 应该为预设选项 es2015 输出什么时,它输出 JavaScript 与 gulp-babel 输出不同。

输入ES6 JavaScript

// eslint-disable-next-line no-unused-vars
function getStars() {
    // Round the number like "3.5k" 
    const round = num => (num > 999 ? `${(num / 1000).toFixed(1)}k` : num);

    // Add the most recent star count to the repositories.
    // eslint-disable-next-line no-undef
    document.querySelectorAll('.repositories .repo a').forEach(async (a) => {
        const link = a;
        const name = link.getAttribute('href').split('/').slice(-2).join('/');
        const url = `https://api.github.com/repos/${name}`;
        const { starGazersCount } = await fetch(url).then(res => res.json());

        if (!starGazersCount) return;

        link.querySelector('.stars').innerText = `${'⭐️ '}${round(starGazersCount)}`;
    });
}

babeljs.io 输出 ~期望的输出~

'use strict';

// eslint-disable-next-line no-unused-vars
function getStars() {
    // Round the number like "3.5k" 
    var round = function round(num) {
        return num > 999 ? (num / 1000).toFixed(1) + 'k' : num;
    };

    // Add the most recent star count to the repositories.
    // eslint-disable-next-line no-undef
    document.querySelectorAll('.repositories .repo a').forEach(async function (a) {
        var link = a;
        var name = link.getAttribute('href').split('/').slice(-2).join('/');
        var url = 'https://api.github.com/repos/' + name;

        var _ref = await fetch(url).then(function (res) {
        return res.json();
        }),
            starGazersCount = _ref.starGazersCount;

        if (!starGazersCount) return;

        link.querySelector('.stars').innerText = '⭐️ ' + round(starGazersCount);
    });
}

gulp-babel输出

"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 () {
function r(e, n, t) {
    function o(i, f) {
    if (!n[i]) {
        if (!e[i]) {
        var c = "function" == typeof require && require;
        if (!f && c) return c(i, !0);
        if (u) return u(i, !0);
        var a = new Error("Cannot find module '" + i + "'");
        throw a.code = "MODULE_NOT_FOUND", a;
        }

        var p = n[i] = {
        exports: {}
        };
        e[i][0].call(p.exports, function (r) {
        var n = e[i][1][r];
        return o(n || r);
        }, p, p.exports, r, e, n, t);
    }

    return n[i].exports;
    }

    for (var u = "function" == typeof require && require, i = 0; i < t.length; i++) {
    o(t[i]);
    }

    return o;
}

return r;
})()({
1: [function (require, module, exports) {
    // eslint-disable-next-line no-unused-vars
    function getStars() {
    // Round the number like "3.5k" 
    var round = function round(num) {
        return num > 999 ? "".concat((num / 1000).toFixed(1), "k") : num;
    }; // Add the most recent star count to the repositories.
    // eslint-disable-next-line no-undef


    document.querySelectorAll('.repositories .repo a').forEach(
    /*#__PURE__*/
    function () {
        var _ref = _asyncToGenerator(
        /*#__PURE__*/
        regeneratorRuntime.mark(function _callee(a) {
        var link, name, url, _ref2, starGazersCount;

        return regeneratorRuntime.wrap(function _callee$(_context) {
            while (1) {
            switch (_context.prev = _context.next) {
                case 0:
                link = a;
                name = link.getAttribute('href').split('/').slice(-2).join('/');
                url = "https://api.github.com/repos/".concat(name);
                _context.next = 5;
                return fetch(url).then(function (res) {
                    return res.json();
                });

                case 5:
                _ref2 = _context.sent;
                starGazersCount = _ref2.starGazersCount;

                if (starGazersCount) {
                    _context.next = 9;
                    break;
                }

                return _context.abrupt("return");

                case 9:
                link.querySelector('.stars').innerText = '⭐️ '.concat(round(starGazersCount));

                case 10:
                case "end":
                return _context.stop();
            }
            }
        }, _callee, this);
        }));

        return function (_x) {
        return _ref.apply(this, arguments);
        };
    }());
    }
}, {}]
}, {}, [1]);

⚠️注意 gulp-babel 输出如何包含 polyfill 函数,例如 _asyncToGenerator & asyncGeneratorStep.

为什么在线babel编辑器在使用es2015预设时不输出这个?

其他有用的文件

下面是我的.babelrc

{
    "presets": [
        "@babel/preset-env"
    ]
}

下面是我的package.json:

{
    "devDependencies": {
        "@babel/core": "^7.0.0",
        "@babel/preset-env": "^7.0.0",
        "babel-eslint": "^10.0.1",
        "babel-preset-env": "^1.7.0",
        "bower": "^1.8.2",
        "eslint-config-standard": "^12.0.0",
        "eslint-plugin-import": "^2.14.0",
        "eslint-plugin-node": "^8.0.0",
        "eslint-plugin-promise": "^4.0.1",
        "eslint-plugin-standard": "^4.0.0",
        "gulp-babel": "^8.0.0",
        "gulp-changed": "^3.2.0",
        "gulp-cssnano": "^2.1.2",
        "gulp-error-handle": "^1.0.0",
        "gulp-eslint": "^5.0.0",
        "gulp-gh-pages": "^0.5.4",
        "gulp-htmlmin": "^5.0.1",
        "gulp-imagemin": "^5.0.3",
        "gulp-include": "^2.3.1",
        "gulp-notify": "^3.2.0",
        "gulp-plumber": "^1.1.0",
        "gulp-postcss": "^8.0.0",
        "gulp-pug": "^4.0.1",
        "gulp-rename": "^1.2.2",
        "gulp-sass": "*",
        "gulp-size": "^3.0.0",
        "gulp-sourcemaps": "^2.6.*",
        "gulp-strip-css-comments": "^2.0.0",
        "gulp-strip-debug": "^3.0.0",
        "gulp-surge": "^0.1.0",
        "gulp-terser": "^1.1.5",
        "gulp-util": "^3.0.8",
        "localtunnel": "^1.8.3",
        "main-bower-files": "^2.13.1",
        "path": "^0.12.7",
        "postcss-cli": "^6.0.1",
        "run-sequence": "^2.2.1",
        "yarn": "^1.12.3"
    },
    "dependencies": {
        "animate.css": "latest",
        "argv": "^0.0.2",
        "autoprefixer": "^9.3.1",
        "babel-polyfill": "^6.26.0",
        "browser-sync": "^2.18.13",
        "browserify": "^16.2.3",
        "bulma": "latest",
        "del": "^3.0.0",
        "gulp": "^3.9.1",
        "gulp-load-plugins": "^1.5.0",
        "hamburgers": "latest",
        "hover": "latest",
        "imagemin-pngquant": "^6.0.0",
        "isinviewport": "latest",
        "jquery": "latest",
        "lost": "^8.2.0",
        "minimist": "^1.2.0",
        "moment": "^2.22.2",
        "node-bourbon": "^4.2.8",
        "node-neat": "^2.0.0-beta.0",
        "psi": "^3.1.0",
        "require-dir": "^1.1.0",
        "rucksack-css": "^1.0.2",
        "vanilla-lazyload": "latest",
        "vinyl-buffer": "^1.0.1",
        "vinyl-ftp": "^0.6.0",
        "vinyl-source-stream": "^2.0.0"
    }
}

下面是我 jsgulp 任务:

'use-strict';

const gulp = require('gulp');
const $ = require('gulp-load-plugins')({ lazy: true });

const browserify = require('browserify');
const source = require('vinyl-source-stream');
const buffer = require('vinyl-buffer');

const paths = require('../../paths.js');
const config = require('../../config.js')();

gulp.task('eslint', () => {
console.log('-> Running eslint');

// Select files
gulp.src(`${paths.to.js.in}/**/*.js`)
// Prevent pipe breaking caused by errors from gulp plugins
    .pipe($.plumber())
// Check for lint errors
    .pipe($.eslint())
// eslint.format() outputs the lint results to the console.
// Alternatively use eslint.formatEach() (see Docs).
    .pipe($.eslint.format())
// To have the process exit with an error code (1) on
// lint error, return the stream and pipe to failAfterError last.
    .pipe($.eslint.failAfterError());
});

gulp.task('js', ['eslint'], () => {
    const env = ((config.environment || process.env.NODE_ENV || 'development').trim().toLowerCase() !== 'production');

    console.log(`-> Compiling JavaScript for ${config.environment}`);

    // Obtain a readable stream containing the processed browserified bundle
    const bundle = browserify({
        entries: paths.to.js.in,
        debug: env,
    })
        .bundle()
    // Convert browserify stream to a gulp-readable steam & buffer
        .pipe(source(config.js.name))
        .pipe(buffer());

    if (env) {
        // Select bundle
        bundle
        // Initialize sourcemaps
        .pipe($.sourcemaps.init())
        // Prevent pipe breaking caused by errors from gulp plugins
        .pipe($.plumber())
        // Concatenate includes
        .pipe($.include({
            includePaths: [`${paths.to.js.in}`],
        }))
        // Transpile
        .pipe($.babel())
        // Catch errors
        .pipe($.errorHandle())
        // Save sourcemaps
        .pipe($.sourcemaps.write('.'))
        // Save unminified file
        .pipe(gulp.dest(`${paths.to.js.out}`));
    } else {
        // Select bundle
        bundle
        // Prevent pipe breaking caused by errors from gulp plugins
        .pipe($.plumber())
        // Concatenate includes
        .pipe($.include({
            includePaths: [`${paths.to.js.in}`],
        }))
        // Transpile
        .pipe($.babel())
        // Catch errors
        .pipe($.errorHandle())
        // Show file-size before compression
        .pipe($.size({ title: 'Javascript In Size' }))
        // Optimize and minify
        .pipe($.terser())
        // Show file-size after compression
        .pipe($.size({ title: 'Javascript Out Size' }))
        // Append suffix
        .pipe($.rename({
            suffix: '.min',
        }))
        // Save minified file
        .pipe(gulp.dest(`${paths.to.js.out}`));
    }
});

@babel/preset-env@babel/preset-es2015 不同 - 前者根据您的目标浏览器兼容性指标打开和关闭插件 (which you can customize).

文档说如果您没有在预设的配置中明确指定目标,将使用以下默认值:

Sidenote, if no targets are specified, @babel/preset-env behaves exactly the same as @babel/preset-es2015, @babel/preset-es2016 and @babel/preset-es2017 together (or the deprecated babel-preset-latest).

另一方面,

@babel/preset-es2015 单独将 编译 ES2015 版本规范中添加的功能。这不包括较新的功能,例如 async/await!如果您想要添加此后的所有功能,则必须添加 all 年度预设。因此,建议您使用 env 预设。

如果您将 https://babeljs.io 切换到 @babel/preset-env 预设(这是年度预设列表下方的一个单独部分),您将获得相同的输出。