在写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。
有两个方法解决
- 换用gulp-uglify-es它使用terser支持 ES6 + 语法压缩。
- 先用 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 的变化。
本文链接: https://www.fengkx.top/post/gulp-uglify-es6-babel/
发布于: 2020-03-16