avatar

fengkx's Blog

fengkx

Student & Coder

Guangzhou, China
Build with Hexo and Next.js

Gulp 用 Babel 降级的方式 uglify ES6 JavaScript

在写Purer主题时用的 Gulp,在 minify JavaScript 的时候遇到了问题。花了挺长时间折腾才找到了解决方法。马后炮的说其实并不难,但是因为 Babel,Gulp 等的版本割裂。网上搜到的方法要么已经过时了或者不全浪费了不少时间。下面用一个实例分步骤地记录一下解决方案。

本文写于 2020 年 3 月 16 日

(async function () {
  const $main = document.getElementById("main");
  const resp = await fetch("https://v1.jinrishici.com/all.json");
  const data = await resp.json();
  $main.textContent = data.content;
})();

实例的代码很简单。但是用到了 ES2017 的 async 语法。使用的依赖版本可以在package.json中看到就不赘述了。

UglifyJS 只支持 ES5

我们很轻松的就可以写出类似这样的 gulpfile

const gulp = require("gulp");
const rename = require("gulp-rename");
const uglify = require("gulp-uglify");
const babel = require("gulp-babel");

gulp.task("js", () => {
  return gulp
    .src("main.js")
    .pipe(uglify())
    .pipe(rename({ suffix: ".min" }))
    .pipe(gulp.dest("."));
});

gulp.task("default", gulp.parallel("js"));

一跑就会发现 UglifyJS 报错。

[13:15:26] GulpUglifyError: unable to minify JavaScript
Caused by: SyntaxError: Unexpected token: keyword «function», expected: punc «)»

gulp-uglify使用的UglifyJS只支持 ES5。

有两个方法解决

  1. 换用gulp-uglify-es它使用terser支持 ES6 + 语法压缩。
  2. 先用 Babel 降级

如果不用考虑兼容性问题,使用第一种方法就不需要往下看了。如果我早点知道的话就不会花时间去折腾了

我当时很自然的想到用 Babel 降级。

引入 Babel 之后的 gulpfile 长这样。

const gulp = require("gulp");
const rename = require("gulp-rename");
const uglify = require("gulp-uglify");
const babel = require("gulp-babel");

gulp.task("js", () => {
  return gulp
    .src("main.js")
    .pipe(
      babel({
        presets: ["@babel/preset-env"],
      })
    )
    .pipe(uglify())
    .pipe(rename({ suffix: ".min" }))
    .pipe(gulp.dest("."));
});

gulp.task("default", gulp.parallel("js"));

async 导致的 Babel Polyfill 缺失

gulp build 没有报错。但是假如你也和例子中一样使用了async的话,运行的时候浏览器会报错。

ReferenceError: regeneratorRuntime is not defined

网上找到的信息多半是安装babel-polyfill, 也有说要安装transform-runtime等等方法配置 babel。但是babel-polyfill已经Deprecated了,为了跟得上时代我们还是得跟官方文档,在babel-preset-env 的官方文档就能找了正确的配置方法。我们要引入core-js

安装好 core-js

npm install core-js@3 --save

并且更改 gulpfile 中的 babel options

{
    presets: [
        ['@babel/preset-env', { useBuiltIns: 'usage', corejs: 3 }]
    ],
}

浏览器 Require 缺失

一通操作下来,浏览器仍然会在运行时报错

ReferenceError: require is not defined

说到 require 自然会想到Browserify。于是依照文档借助 Babelify 我们很自然的写出类似这样的 gulpfile

const gulp = require("gulp");
const rename = require("gulp-rename");
const uglify = require("gulp-uglify");
const babel = require("gulp-babel");
const browserify = require("browserify");

gulp.task("js", () => {
  return browserify("main.js")
    .transform("babelify", {
      presets: [["@babel/preset-env", { useBuiltIns: "usage", corejs: 3 }]],
    })
    .bundle()
    .pipe(uglify())
    .pipe(rename({ suffix: ".min" }))
    .pipe(gulp.dest("."));
});

gulp.task("default", gulp.parallel("js"));

build 一下遇到了这样奇怪的错误,

TypeError: file.isNull is not a function

Vinyl stream 不兼容

问题出在 Browserify 的流和 Gulp 的流不兼容。Gulp 的流使用的是Vinyl, 而 browserify 使用的 node fs 的流。我们需要额外做一些转换。

安装相关的包。

npm i -D vinyl-source-stream
npm i -D vinyl-buffer

最终 gulpfile

const gulp = require("gulp");
const rename = require("gulp-rename");
const uglify = require("gulp-uglify");
const babel = require("gulp-babel");
const browserify = require("browserify");
const source = require("vinyl-source-stream");
const buffer = require("vinyl-buffer");

gulp.task("js", () => {
  return browserify("main.js")
    .transform("babelify", {
      presets: [["@babel/preset-env", { useBuiltIns: "usage", corejs: 3 }]],
    })
    .bundle()
    .pipe(source("main.js"))
    .pipe(buffer())
    .pipe(uglify())
    .pipe(rename({ suffix: ".min" }))
    .pipe(gulp.dest("."));
});

gulp.task("default", gulp.parallel("js"));

总结

至此这么一小段 js 终于被编译成可以运行的 minify 的 ES5 了。可是这么一通操作下来引入了 core-js 做 polyfill 体积不减反增maxify

4.0K    main.js
36K     main.min.js

所以说如果不考虑兼容性就直接用gulp-uglify-es好了。

前端的构建工具大版本总是不兼容,网上的信息也很多已经过时了。这篇文章估计在不久之后也会过时的。不得不说跟上时代最好的方法还是官方文档呀。

实例放在了 GitHub,各个步骤都对应的分支。
我们还可以借助github-history来看 gulpfile 的变化

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处。

本文链接: https://www.fengkx.top/post/gulp-uglify-es6-babel/

发布于: 2020-03-16