編譯 ES6 JSX 語法 | HTML 自動載入 CSS JS | 本地端伺服器
本文目的為介紹以 Gulp 打造 React Redux Router ES6 的開發及產品環境,以下將會說明所需的套件及設定方式,依建制步驟拆成五個篇章,關於 React Redux ES6 等相關知識不在此篇筆記介紹範圍。
第一篇 - 編譯 ES6 JSX 語法 | CSS JS 自動載入 | 本地端伺服器
- 編譯 JSX 及 ES6 語法 | Babel Browserify
- HTML 自動載入 CSS JS | Bower Wiredep Gulp Inject
- 建立開發用伺服器及自動重新載入 | Gulp Connect
- 編譯 SASS 語法 | Gulp Sass
- JavaScript 語法偵錯 | ESLint
- 單元測試 | Jest
第三篇 - 環境變數 | 程式碼壓縮 | 檔案壓縮 | 輸出隨機檔名
- 轉換開發及產品環境變數 | Browerify Dotenv Envify
- JavaScript SASS 程式碼壓縮 | Gulp Sass Uglify
- 產品環境下打包所有 JS CSS 檔案 | Gulp Useref
- 輸出的 CSS JS 檔案附加不重複的檔名 | Gulp Rev
第四篇 - 彙整 Gulp task
- 彙整 Gulp task - development
- 彙整 Gulp task - production
第五篇 - 導入 Redux React-Router 架構
- 導入 Redux Router 架構 | React Redux Router
前三篇會依序介紹每個功能及建置方式,第四篇會將零碎的 task 打包成一連串的動作,做成開發及產品環境的指令集,第五篇會把 react-redux 和 react-router 基本架構導入。
基本需求:已安裝 NodeJS 及了解如何使用 npm,並知道如何使用 Gulp 建立 task,第四篇有彙整 Gulp task 的部分,需要理解 NodeJS CommonJS 的模組語法。
編譯 JSX 及 ES6 語法 | Babel Browserify
React 使用 JSX 語法組織 HTML 架構,JSX 為 JavaScript 的 expression,然而現在的瀏覽器是無法讀懂它及 ES6 語法,因此我們需要編譯它,將它轉換為瀏覽器看得懂的語法,以下是使用 browserify babel 搭配 gulp 編譯 ES6 及 JSX 的設定內容:
$ npm install --save react react-dom
$ npm install --save-dev gulp babel-plugin-react-html-attrs babel-preset-es2015 babel-preset-react babel-preset-stage-0 babelify browserify watchify vinyl-buffer vinyl-source-stream
在專案的根目錄建立 .babelrc 檔案,設定 babel 的編譯規則。
// .babelrc { "presets": ["es2015", "react", "stage-0"], // react-html-attrs 可以把 JSX 中的 class 轉成 className、for 轉成 htmlFor (選用) "plugins": ["react-html-attrs"] }
同樣在根目錄也建立 gulpfile.js,開始撰寫各個 gulp task
// gulpfile.js var gulp = require('gulp'); var browserify = require('browserify'); var babelify = require('babelify'); var buffer = require('vinyl-buffer'); var source = require('vinyl-source-stream'); var watchify = require('watchify'); // 印出錯誤,並發出事件完成,避免編譯過程因部分錯誤而讓 watch 中的 task 停止。 var handleError = function(err) { console.error(err); this.emit('end'); }; // 開始設定 browserify 編譯規則 var bundler = browserify({ // react 進入點 'entries': 'src/js/index.js', // true 可以讓瀏覽器的 console 印出出現 bug 的行數是來自在哪一個檔案的哪一行,而不是最後編譯後的檔案的哪一行,方便在開發環境中 debug 'debug': true, // watchify 必須加入以下兩個屬性 'cache': {}, 'packageCache': {}, // 使用 babelify 轉換:會讀取根目錄 .babelrc 檔案的 babel 轉換規則 'transform': [babelify] }); // 若是開發環境中,每次我們在撰寫 .js 檔案的時候,將整個 React 專案重新編譯會太慢,watchify 提供 update 事件,讓重新編譯的速度更快。 var watcher = watchify(bundler); // browserify 依據設定進行編譯,並將檔案匯出至指定資料夾。 gulp.task('script', function() { return watcher .bundle() .on('error', handleError) .pipe(source('bundle.js')) .pipe(buffer()) .pipe(gulp.dest('dist/js/')); }); // 監聽程式碼的更新事件,以再次觸發編譯 watcher.on('update', function() { gulp.start('script'); });src/js/index.js 為我們的 react 專案進入點,試著在 index.js 中寫些簡單的內容:
// src/js/index.js import React from 'react'; import ReactDOM from 'react-dom'; ReactDOM.render( <h1>hello, world</h1>, document.getElementById("root") );
接者執行編譯:
$ gulp script此時可以看見 script 這個 gulp task 已經開始並在幾秒後完成,因為我們有監聽 update 事件,所以 terminal 會持續等待我們更改內容,觸發編譯,我們可以試著更改 index.js 的內容並儲存,會顯示 Gulp 已經觸發自動重新編譯,如果這些動作都產生,代表我們已經成功建立編譯 ES6 JSX 的功能,而這部分只有編譯 JS 程式碼的部分,想要在瀏覽器執行這些程式碼需要 html 檔案引入編譯好的 script 及本地端的伺服器,接者兩節會緊接著補上。
HTML 自動載入 CSS JS | Bower Wiredep Gulp Inject
這裡建置的 task 會將 bower 安裝的套件和自己撰寫的檔案一起自動引入到 html 檔中,使用 wiredep 搭配 gulp-inject 就可以達到如此目的,不需要在手動管理 html 中的 script link 標籤。
$ npm install --save-dev gulp-inject wiredep
使用 bower 可以管理前端套件,如 jquery、bootstrap、sweetalert 等。如果 global 安裝 bower 可以像 npm 一樣,使用 bower init 開始設定 bower.json 內容,再使用 bower install <套件名稱> --save 安裝套件,預設會安裝在根目錄的 bower_components 資料夾中,在 bower.json 的 dependencies 屬性中加入剛剛按裝的套件及版本,記得在 .gitignore 中忽略 bower_components 這個資料夾,若要更改安裝的目錄位置,可以在根目錄新增 .bowerrc 檔案,加入更換的資料夾位置:
// .bowerrc { "directory": "./dist/bower_components" }
在 src/ 資料夾底下新增 index.html:
// index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Build React Redux with Gulp</title> <!-- bower:css --> <!-- endbower --> <!-- inject:css --> <!-- endinject --> </head> <body> <div id="root"></div> <!-- bower:js --> <!-- endbower --> <!-- inject:js --> <!-- endinject --> </body> </html>wiredep 會判斷 html 檔案中
<!-- bower:css --> <!-- endbower --> <!-- bower:js --> <!-- endbower -->的位置注入已安裝的 bower package css js。gulp-inject 會判斷 html 檔案中
<!-- inject:css --> <!-- endinject --> <!-- inject:js --> <!-- endinject -->的位置,將指定的檔案注入到該處 css js,接著是建立 gulp task 的設定:
// gulpfile.js var inject = require('gulp-inject'); var wiredep = require('wiredep').stream; gulp.task('inject', function(){ var injectSources = gulp.src( [ 'dist/js/*.js', 'dist/css/*.css' ], { read: false } ); return gulp .src('src/index.html') .pipe(wiredep({'ignorePath': '../dist'})) .pipe(inject(injectSources, {'ignorePath': '/dist'})) .pipe(gulp.dest('dist/')); });
執行
$ gulp inject就會把 src/index.html 的檔案根據設定的 inject 內容匯出至 dist/index.html,這時候就會發現目的資料夾已經把 bower 套件的 css js 跟 bundle.js 自動引入,接著我們需要一個開發用的伺服器。
備註:環境建好後才得知使用 bower 管理前端套件的部分其實 npm 也可以做到的,不同之處在於,以 npm 安裝套件之後,在使用到的檔案直接 import js css,而不是另外使用 script link 的方式直接在全域的環境下加入該套件的 css js 程式碼,個人認為是比較好的方式,可以避免污染全域變數,在後續建立測試環境時也不需要先宣告全域變數有哪些,未來有機會就會用這個方式取代 bower 管理這部分套件的方法了,詳細可以參閱:css-modules
建立開發用伺服器及自動重新載入 | Gulp Connect
使用 gulp-connect 可以建立一個開發用的本地伺服器,同時可以加上 livereload 功能,讓瀏覽器手動重新載入自動化,省去每次都要手動重新載入的麻煩。第四篇會把所寫過的 task 整理起來,搭配成自動重新編譯及自動引入編譯過後的檔案,然後瀏覽器自動重新載入。
$ npm install --save-dev gulp-connect
// gulpfile.js var connect = require('gulp-connect'); // 建立 server: http://localhost:8080 (預設) gulp.task('server', function(){ connect.server({ // 本地伺服器根目錄 root: 'dist/', // 當呼叫 connect.reload 時,瀏覽器是否要重新載入 livereload: true, // 用於 react router,所有 root folder 以下的 request 都會轉導到指定檔案 fallback: 'dist/index.html' }); }); // 觸發 livereload 的 task,若已經跑過 server task,觸發這個 task 就會 reload // 搭配 gulp.watch 來執行 gulp.task('reload', function() { return gulp.src('dist/index.html') .pipe(connect.reload()); });
執行
$ gulp server就能在預設的: http://localhost:8080 中,以瀏覽器看到編譯過後的檔案執行結果。
大致上已經把 ES6 的編譯、html 自動載入執行及瀏覽器自動重新載入的功能做出來了,後續章節再慢慢統整這些 gulp task,讓整個開發/產品環境越來越完善。
留言
張貼留言