前言
近期在开发Hybird新需求时用到了地图,而因为地图的定位地址是异步拿到结果的,而多个点与定位地址的距离计算需要等到定位结束,所以这里可以用async函数来做,但是以前项目用到gulp只停留在ES5阶段,导致ES6语法打包出来的js在部分系统低的安卓机上不支持而报错,所以这里需要babel编译
一、引入Babel进行ES6编译
项目以前用的GulpV3,也趁这次终于升级到V4了
1. 依赖安装
npm install -D gulp-babel @babel/core @babel/preset-env
2. babel在gulp中的简单配置
const gulp = require('gulp')
const {task,dest,src} = require('gulp')
const babel = require('gulp-babel')
task('testBabel', function () {
let step = src('./js/*.js')
.pipe(babel({
presets:['@babel/preset-env']
}))
.pipe(dest('./test'))
return step;
})
3. 拿一个js来测试下
// test.js
const a = 1;
const b = 2;
let foo = function () {
return a+b
}
async function test() {
let c = 10;
let d = await foo() + c
return d;
}
test().then(res => {
console.log(res)
})
- 通过运行
gulp testBabel
可以看到test
文件夹下出现了(ES6转ES5)编译后的test.js
文件。 - 出现问题:用一个html来引用刚编译后的js运行看,发现报错
Uncaught ReferenceError: regeneratorRuntime is not defined
- 原因:在test.js中引用了async函数,而这是需要ES6新API部分,babel默认情况下是只转译语法,而对新API的支持需要额外加入
polyfill
,现在polyfill其实有三种类型,区别可以看这篇文 - 解决:
npm install -D @babel/plugin-transform-runtime
,npm install -S @babel/runtime
- 原因:在test.js中引用了async函数,而这是需要ES6新API部分,babel默认情况下是只转译语法,而对新API的支持需要额外加入
task('test', function () {
let step = src('./js/*.js')
.pipe(babel({
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-transform-runtime']
}))
.pipe(dest('./test'))
return step;
})
4. 再次测试,发现这次报错不一样了,Uncaught ReferenceError: require is not defined
.
- 原因:babel编译后的代码是遵循commonJS的模块化规范的,所以这里还需要引用一个模块化bundler。
- 解决:引入
browserify
npm install -D browserify vinyl-buffer vinyl-source-stream
const gulp = require('gulp')
const {task,dest,src,series} = require('gulp')
const babel = require('gulp-babel')
const browserify = require('browserify')
const buffer = require('vinyl-buffer')
const stream = require('vinyl-source-stream')
task('test', function () {
let step = src('./js/*.js')
.pipe(babel({
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-transform-runtime']
}))
.pipe(dest('./test'))
return step;
})
task('browserify', function (cb) {
return browserify({
entries: './test/test.js',
debug: true
})
.bundle()
.on('error', function (error) {
console.log(error.toString())
})
.pipe(stream('test.js'))
.pipe(buffer())
.pipe(dest('./test/testBundle'));
cb() //这一句其实是因为V4不再支持同步任务,所以需要以这种方式或者其他API中提到的方式
})
exports.build = series('test','browserify') //series是gulpV4中新方法,按顺序执行
5. 再次执行,浏览器终于不报错啦~~
- 但实际项目中,往往用到gulp也不是单文件入口编译,所以在browserify的文件入口entry处可以通过编写读文件脚本的方式来对一个文件夹下的js进行模块化打包
- 例:
let enviroment = process.env.NODE_ENV || 'development'
const folder = {
src:'src/',
dist:'webapp/',
temp:'./.tmp/'
}
// 文件读取
const es = require('event-stream')
const fs = require('fs')
const join = require('path').join
function findSync(startPath){
let result = []
function finder(path){
let files = fs.readdirSync(path)
files.forEach(val=>{
let fPath = join(path,val)
let stats = fs.statSync(fPath)
if(stats.isDirectory()) finder(fPath)
if(stats.isFile()) result.push({path:'./'+fPath,name:val})
})
}
finder(startPath)
let res = result.map(item=>{
item.path = item.path.replace(/\\/g,'/')
return item
})
return res
}
// 模块化打包
task('browserify',function(cb){
let files = findSync(folder.temp+'js')
var task = files.map(entry=>{
return browserify({
entries:entry.path,
debug:true
})
.bundle()
.on('error',function(error){
console.log(error.toString())
})
.pipe(stream(entry.name))
.pipe(buffer())
.pipe(dest(folder.dist+'js'))
})
es.merge.apply(null,task)
cb()
})
二、整体Gulp工程构建
1. 一些常用gulp插件
gulp-htmlclean
:HTML代码压缩gulp-rev
,gulp-rev-collector
:为资源加MD5后缀(防浏览器缓存)gulp-useref
:对HTML引用的资源进行合并(通过特定标签注释)gulp-clean-css
:CSS代码压缩gulp-uglify
:JS压缩gulp-imagemin
:图片压缩gulp-less
:less预编译gulp-connect
:本地网络服务gulp-postcss
&autoprefixer
:CSS自动前缀补全gulp-clean
:文件清理