前言
近期在開發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
:文件清理