最近因為工作上需要,重拾 Gulp 來作套件管理並自動化前端網頁撰寫的流程。想不到隨著 Babel 的版本提升,容易採坑的點也越來越多。這邊筆記下完整腳本和流程供以後參考。
流程
基本流程,瀏覽器端 Babel 編譯
HTML
- 讀取並作對應的調整修改
- 若有更動要重新刷新瀏覽器
SCSS
- 讀取並作 Sourcemap (僅開發階段)
- 加上 auto-prefix
- 壓縮 CSS (僅佈署階段)
- 重新命名資料夾根目錄 (若有需要)
- 輸出到目的地資料夾
- 若有更動要重新刷新瀏覽器
Plugins
- 讀取並作 Sourcemap (僅開發階段)
- 加上 auto-prefix
- 合併成一隻檔案
- 輸出到目的地資料夾
自身撰寫的 JavaScript
- 讀取並作 Sourcemap (僅開發階段)
- 壓縮 JS (僅佈署階段)
- 輸出到目的地資料夾
- 若有更動要重新刷新瀏覽器
監聽檔案和其他
- 監聽 js / css / html 檔案,若有更動就重啟
- 由於是在客戶端瀏覽器進行 babel 轉換,所以引用的 script 寫法要小心
- 例如:<script type=”text/babel” data-presets=”es2015,es2016,es2017“></script>
Babel 部份引入流程
HTML
- 讀取並作對應的調整修改
- 若有更動要重新刷新瀏覽器
SCSS
- 讀取並作 Sourcemap (僅開發階段)
- 加上 auto-prefix
- 壓縮 CSS (僅佈署階段)
- 重新命名資料夾根目錄 (若有需要)
- 輸出到目的地資料夾
- 若有更動要重新刷新瀏覽器
Plugins
- 讀取並作 Sourcemap (僅開發階段)
- 加上 auto-prefix
- 合併成一隻檔案
- 輸出到目的地資料夾
自身撰寫的 JavaScript
- 使用 Glob 抓取所有要編譯的檔案
- 每隻檔案建立各自的 browserify 獨立資料流
- 用 event-stream 合併所有資料流
每隻 browserify 獨立資料流
- 在 browserify 啟用 transform,並用 babelify 來設定 babel 參數來進行編譯
- 參數的方式和於根目錄放置 .babelrc 內的設置是一模一樣的
- 從 babel 7.4 版以後,取消 babel-polyfill
- 由於 gulp 和 node 的資料流格式不同,所以要先用 vinyl-source-stream 來轉換給 gulp 支援
- 由於 uglify 所預期的資料流格式為 buffer ,所以要再度轉換
- 製作 Sourcemap (僅開發階段)
壓縮 JS (僅佈署階段) - 重新命名資料夾根目錄 (若有需要)
- 輸出到目的地資料夾
- 若有更動要重新刷新瀏覽器
監聽檔案和其他
- 監聽 js / css / html 檔案,若有更動就重啟
關鍵套件列表
湊齊以下,你就可以使用 Babel 的相容瀏覽器功能。
1. @babel/runtime
2. @babel/core
3. @babel/plugin-transform-runtime
4. @babel/preset-env
5. @babel/runtime-corejs3
6. babelify
7. browserify
8. vinyl-buffer
9. vinyl-source-stream
10. event-stream
若你只是要全部引入的話,可以直接使用 babel-polyfill 和 babel-standalone。
步驟
Babel 完全引入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
const gulp = require('gulp'); const $ = require('gulp-load-plugins')(); const autoprefixer = require('autoprefixer'); const del = require('del'); const parseArgs = require('minimist'); const path = require('path'); const browserSync = require('browser-sync').create(); const envOption = parseArgs(process.argv.slice(2)).env; const uglify = require('gulp-uglify-es').default; gulp.task('clean', () => { return del(['./demo/dist']); }); gulp.task('html', () => { return gulp .src(['./demo/*.html']) .pipe($.plumber()) .pipe(browserSync.stream({ stream: true })); }); gulp.task('sass', () => { let postcssPlugins = [autoprefixer()]; return gulp .src('./demo/resources/**/*.scss') .pipe($.plumber()) .pipe($.if(envOption !== 'production', $.sourcemaps.init({ loadMaps: true }))) .pipe($.sass().on('error', $.sass.logError)) .pipe($.postcss(postcssPlugins)) .pipe($.if(envOption === 'production', $.cleanCss({ compatibility: 'ie9' }))) .pipe( $.rename(function (path) { path.dirname = '/'; }) ) .pipe($.if(envOption !== 'production', $.sourcemaps.write('./'))) .pipe(gulp.dest('./demo/dist/css')) .pipe(browserSync.stream({ stream: true })); }); gulp.task('plugins', () => { return gulp .src(['./demo/resources/plugins/**/*.js', './node_modules/bootstrap-sass/assets/javascripts/bootstrap.js'], { base: '.', }) .pipe($.plumber()) .pipe($.if(envOption !== 'production', $.sourcemaps.init({ loadMaps: true }))) .pipe($.concat('plugins.js')) .pipe($.if(envOption !== 'production', $.sourcemaps.write('./'))) .pipe(gulp.dest('./demo/dist/js')); }); gulp.task('javascript', () => { return gulp .src('./demo/resources/js/**/*.js') .pipe($.plumber()) .pipe($.if(envOption !== 'production', $.sourcemaps.init({ loadMaps: true }))) .pipe($.if(envOption !== 'production', uglify())) .pipe($.if(envOption !== 'production', $.sourcemaps.write('./'))) .pipe(gulp.dest('./demo/dist/js')) .pipe(browserSync.stream()); }); gulp.task('watch', () => { gulp.watch('./demo/*.html', gulp.series('html')); gulp.watch('./demo/resources/**/*.scss', gulp.series('sass')); gulp.watch(['./demo/resources/js/**/*.js', './demo/resources/plugins/*.js'], gulp.series('plugins', 'javascript')); }); gulp.task('browser-sync', function () { browserSync.init({ server: { baseDir: './demo', directory: true, } }); }); gulp.task('default', gulp.series('clean', 'sass', 'plugins', 'javascript', gulp.parallel('watch', 'browser-sync'))); |
Babel 選擇性引入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
/*將 javascript 的 task 刪除,並新增 browserify*/ const uglify = require('gulp-uglify-es').default; const browserify = require('browserify'); const babelify = require('babelify'); const vinylSourceStream = require('vinyl-source-stream'); const vinylBuffer = require('vinyl-buffer'); const glob = require('glob'); const es = require('event-stream'); gulp.task('browserify', function (done) { /* 1. 用 glob 抓取所有要編譯的檔案*/ /* 2. 給每一個檔案建立各自的 browserify 獨立資料流,並儲存成一個陣列*/ /* 3. 用 event stream 合併所有資料流*/ glob('./demo/resources/js/*.js',function(err,files){ if(err) done(err); let tasks = files.map(function(entry){ /*1. 在 browserify 啟用 transform,並用 babelify 來設定 babel 參數*/ /*2. 參數的方式和於根目錄放置 .babelrc 內的設置是一模一樣的*/ /*3. 從 babel 7.4 版以後,取消 babel-polyfill*/ /*4. 由於 gulp 和 node 的資料流格式不同,所以要先用 vinyl-source-stream 來轉換給 gulp 支援*/ /*5. 由於 uglify 所預期的資料流格式為 buffer ,所以要再度轉換*/ return browserify({entries:[entry]}, { debug: true }) .transform(babelify.configure({ "presets":["@babel/preset-env"], "plugins":[ [ "@babel/plugin-transform-runtime", { "absoluteRuntime": false, "corejs": 3, "regenerator": true, "useESModules": false } ] ] })) .bundle() .pipe($.plumber()) .pipe(vinylSourceStream(entry)) .pipe(vinylBuffer()) .pipe($.if(envOption !== 'production', $.sourcemaps.init({ loadMaps: true }))) .pipe( $.rename(function (path) { path.dirname = '/'; }) ) .pipe($.if(envOption !== 'production', uglify())) .pipe($.if(envOption !== 'production', $.sourcemaps.write('./'))) .pipe(gulp.dest('./demo/dist/js')) .pipe(browserSync.stream()); }) es.merge(tasks).on('end',done) }) }); |
Github
https://github.com/andy922200/gulp4_script_with_babel7
參考資料
- Roya’s Blog 現代化 Web 開發技術學習分享
- 结合Babel 7.4.0 谈一下Babel-runtime 和 Babel-polyfill
- [小菜一碟] 讓 IE(Internet Explorer)也能夠跑 ES6、ES7、ES8 的語法
- System limit for number of file watchers reached
- Browserify : Multiple bundles with gulp
- Gulp 4, Babel & Browserify
- 基于 Gulp + Browserify 构建 ES6 环境下的自动化前端项目
- how can I use babel polyfill to support all IE11 issues with gulp