ecmascript-6gulpbabeljsecmascript-5gulp-babel

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


Background

I am trying to transpile my ES6 js to ES5 js. When I visit the https://babeljs.io/repl webpage to test out what babel should output for the preset option es2015 it outputs JavaScript that is different than what gulp-babel outputs.

Input ES6 JavaScript

// eslint-disable-next-line no-unused-vars
function getStars() {
    // Round the number like "3.5k" https://stackoverflow.com/a/9461657
    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 output ~Desired Output~

'use strict';

// eslint-disable-next-line no-unused-vars
function getStars() {
    // Round the number like "3.5k" https://stackoverflow.com/a/9461657
    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 output

"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" https://stackoverflow.com/a/9461657
    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]);

⚠️Notice how the gulp-babel output contains polyfill functions such as _asyncToGenerator & asyncGeneratorStep.

Why does the online babel editor not output this when using the es2015 preset?

Other Useful files

Below is my .babelrc:

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

Below is my 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"
    }
}

Below is my js task for gulp:

'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}`));
    }
});

Solution

  • @babel/preset-env is not the same thing as @babel/preset-es2015 - the former turns plugins on and off based on your targeted browser compatibility metrics (which you can customize).

    The docs say that if you don't explicitly specify the targets in the preset's config, the following defaults will be used:

    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 alone, on the other hand, will only compile features that were added in the ES2015 version of the spec. This does not include newer features, such as async/await! If you want all of the features added since then, you will have to add all of the yearly presets. For this reason, it's recommended that you use the env preset.

    If you switch https://babeljs.io to the @babel/preset-env preset (which is a seperate section below the list of yearly presets), you get the same output.