這次作業要使用 Gulp 來自動化工作流程,作業要求是要將 CSS 跟 JavaScript 檔案都 inline 進 index.html 裡面,不能發出 CSS 跟 JavaScript 的 Request。雖然手動可以做到這件事情,但每次修改 CSS 跟 JavaScript 檔案就要手動 inline,這樣的確很麻煩。
有了上次做 Webpack 作業的經驗,這次讀了兩篇學習資源的文章,知道如何安裝之後就開始動手做作業了。最主要是參考 Gulp 官網 跟胡立老師的 可以幫我自動化嗎,拜託:Gulp。大概是有了上次 Webpack 作業的經驗,這次的 Gulp 作業上手很快,也沒有感覺那麼困難了,除了中間因為 Webpack uglifyJS plugin 卡住了一些時間,大致上都算順利。
Gulp 跟 Webpack 一樣需要用 Node.js 支援,上次的作業後已經比較熟悉 Node.js 跟 npm 的操作,也比較熟悉 command line 的操作,所以這個部分就不會像上次一樣卡關。
Gulp 到底是做什麼用的呢?簡單來說就是幫你把原本需要手動完成的工作,全部自動化。舉例來說,原本我用 Sublime 的套件幫我把 Sass 編譯成 CSS,然後再用另一個套件把 CSS 檔案加入 prefixer,有 Gulp 之後,我就不用再手動處理這些東西,安裝 Gulp plugins 然後寫好程式就可以一次幫我處理好。 而且 Gulp 有各式各樣的 plugins 可以使用,所以當要手動處理的事情越來越多的時候,使用 Gulp 就變得好方便!
這次寫作業的流程:
1. 開啟 cmd.exe 之後,
cd
切換到專案根目錄,安裝 Webpack 跟 Webpack modules 需要的東西,還有創建 package.json。這邊就快速帶過,跟上週的步驟一樣。安裝 Webpack:
npm install --save-dev webpack
創建 package.json:
npm init -y
安裝 jQuery:
npm install jquery --save
安裝 json-loader:
npm install json-loader --save
webpack.config.js 的檔案延用上次作業的檔案,所以直接複製過來這次作業的資料夾內,其他檔案也都是直接複製過來。不過上次是用 Webpack plugin 引入 jQuery,這次則取消 plugin 改成直接在 index.js 裡面寫
var $ = require('jquery');
。這樣 Webpack 的設定大致完成,接下來要安裝 Gulp 跟 Gulp plugins。2. 安裝 Gulp。
npm install --save-dev gulp
3. Gulp 流程。
在 Gulp 官網 上可以搜尋有哪些 plugins,我想要 Gulp 幫我處理的流程是:編譯 Sass 成 CSS -> CSS 加入 prefixer -> minify CSS -> 執行 Webpack -> uglify JS -> Inline CSS 跟 JS。
依照關鍵字去找對應的 plugins,然後安裝,最後再把 plugins 都
require
進 gulpfile.js 裡面,然後寫好執行的程式碼就完成了。原本以為 Webpack 跟 Gulp 要分開執行,問胡立老師 Webpack 是否應該利用 Gulp plugins 一起處理,他說用 Gulp plugins 處理比較好。
4. 安裝 Gulp-sass,用來編譯 Sass 成 CSS。
npm install gulp-sass --save
5. 安裝 Gulp-autoprefixer,幫 CSS 加入 prefixer。
npm install --save gulp-autoprefixer
6. 安裝 Gulp-clean-css,用來 minify CSS。
npm install gulp-clean-css --save
7. 安裝 Gulp-rename,可以幫檔案重新命名。
npm install gulp-rename --save
8. 安裝 Gulp-webpack,用來執行 Webpack。
npm install gulp-webpack --save
9. 安裝 Gulp-inline,用來 inline CSS 跟 JS 檔案到 index.html 裡面。
npm install gulp-inline --save
10. 安裝 Gulp-sequence,用來指定執行 Gulp plugins 的順序。
npm install gulp-sequence --save
Gulp-rename 跟 Gulp-sequence 這兩個不是可以直接聯想到需要安裝的 plugins,我也是看了胡立老師的 可以幫我自動化嗎,拜託:Gulp 這篇才知道的。以上就把所有需要的 Gulp plugins 都安裝好了。
11. 建立 gulpfile.js。概念跟 Webpack 的 webpack.config.js 有點類似。
先把所有需要的東西都
require
進 gulpfile.js:var gulp = require('gulp'); var sass = require('gulp-sass'); var rename = require("gulp-rename"); var autoprefixer = require('gulp-autoprefixer'); var cleanCSS = require('gulp-clean-css'); var webpack = require('gulp-webpack'); var inline = require('gulp-inline'); var gulpSequence = require('gulp-sequence');
Gulp pluings 通常都會附上範例,參考範例就可以大概了解要如何寫出程式碼。
依序寫出程式碼:
1) 編譯 Sass 成 CSS:
gulp.task('sass', function () { return gulp.src('./src/sass/**/*.sass') .pipe(sass().on('error', sass.logError)) .pipe(rename('style.css')) .pipe(gulp.dest('./src/css')); });
這裡大概講解一下上面的程式碼在做什麼。
gulp.task
就是定義一個任務,後面加上自訂的任務名稱 'sass'
跟 function。gulp.src
指定來源檔案的路徑,讓 Gulp 讀到你要他處理的檔案。這裡是說,讀取我目前所在的資料夾 ./
下的 sass
資料夾下的所有資料夾 **
裡面的所有 *.sass
檔案。雖然我只有一個 sass 檔案,直接指定檔名也可以,不過一般大型專案會有許多 sass 檔案,所以就保留了這個寫法。通過
.pipe()
把你的指定傳下去,這裡傳給 sass()
編譯 Sass(後面是錯誤訊息的處理,我只是複製範例上的),然後再傳給 rename()
把檔名改成 style.css,最後傳給 gulp.dest
用來指定輸出檔案的儲存位置。在
.pipe()
裡面的 plugins 名稱要跟一開始 require
進來的變數名稱一樣。譬如說,我原本是 var sass = require('gulp-sass');
,變數是小寫 sass,那就不能變成用大寫 .pipe(SASS().on('error', sass.logError))
。一開始的任務名稱
'sass'
則跟 .pipe()
裡面的指令沒有關係,而是跟最後要執行順序的指令有關。之後的程式碼都大同小異,一樣的邏輯去寫,我大部分都是直接複製 Gulp plugins 裡的範例再修改。
其中 Gulp-sass 範例裡面有
sass:watch
:gulp.task('sass:watch', function () { gulp.watch('./src/sass/**/*.scss', ['sass']); });
原本不太確定
'sass'
跟 'sass:watch'
在使用時機上怎麼區分,後來問胡立老師之後才知道 'sass'
是用在檔案確定都弄好要上傳到伺服器時,而 'sass:watch'
則是用在開發時隨時監看 sass 檔案,有變動就隨時編譯成 CSS。以這次作業的來說,幾乎不會再變動 CSS 了,所以就直接用 'sass'
做編譯。2) 在 CSS 加入 prefixer,並且 minify CSS:
gulp.task('minify-css', function(){ return gulp.src('./src/css/style.css') .pipe(autoprefixer({ browsers: ['last 2 versions'], cascade: false })) .pipe(cleanCSS()) .pipe(rename('style.min.css')) .pipe(gulp.dest('./dist')); });
這個部分其實結合了 Gulp-autoprefixer 跟 Gulp-clean-css,如果要分成兩個部分來寫也是可以,不過我想要讓程式碼簡潔一點,所以就選擇把兩個 plugins 功能結合在一起,然後直接輸出 style.min.css。
3) 執行 Webpack,並用 Webpack plugin uglify JS。
gulp.task('webpack', function() { return gulp.src('./src/js/index.js') .pipe(webpack( require('./webpack.config.js'))) .pipe(gulp.dest('./dist')); });
這裡是我卡關最久的部分,原本使用 Webpack 內建的 uglifyJS plugin,在 webpack.config.js 直接引入:
var uglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
然後 moduels 裡面加入 plugins:
plugins: [ new uglifyJsPlugin() // uglifyJS ]
可是不斷的出現錯誤訊息:
後來找到一篇 Stack Overflow 的文章:Uglify Syntaxerror Unexpected Token Punc,依照上面的方法安裝了 Webpack-uglifyjs 跟 uglify-es:
npm install uglifyjs-webpack-plugin --save npm install uglify-js@github:mishoo/UglifyJS2#harmony --save
也在 webpack.config.js 把引入改成:
var uglifyJsPlugin = require('uglifyjs-webpack-plugin');
但還是一樣出現錯誤訊息,始終無法成功 uglify JavaScript 檔案。似乎是 ES 語法的問題,可是我幾乎沒有用到 ES6 語法,所以想說只要把有問題的地方找出來,不想要另外安裝 Babel-loader (後來直播中,胡立老師有用 Babel-loader 也是無法用 Webpack plugin 成功 uglify JavaScript 檔案,所以應該是 Webpack uglifyJS plugin 的問題。如果有使用 ES6 語法,可能要用 Gulp-minify 來 uglify JavaScript 檔案比較保險)。
後來依照錯誤訊息找到在 utils.js 有問題的一段程式碼:
module.exports = { getLocalString };
原本以為這段應該是 ES5 語法,後來丟到 Babel 官網 的 Try it out 裡面去編譯,後來才知道原來這段是 ES6 語法,編譯後變成:
module.exports = { getLocalString: getLocalString };
改成編譯後的 ES5 語法後就正常了!
當時這段是上週寫 Webpack 作業參考胡立老師的 我也想要模組化開發:Webpack 這篇寫的,加上我自己對 ES6 語法不熟悉,所以才會發生這次的錯誤。之後要找時間好好研究一下 ES6 語法了。
4) Inline CSS 跟 JS 到 index.html 裡面:
gulp.task('inline', function() { return gulp.src('./index.html') .pipe(inline({ base: './' })) .pipe(gulp.dest('./dist')); });
Gulp-inline 裡面的範例寫得很複雜,我的寫法是是最基本的寫法(也是問胡立老師之後才知道原來可以簡化成這樣 XD),
gulp.src
一樣是指定來源檔案的路徑,base:
是寫來源檔案的相對路徑在哪裡,最後 gulp.dest
輸出到 dist
資料夾裡面,把原本的 html 檔案跟輸出後的 html 檔案分開資料夾存放比較好。5) 指定 Gulp 執行順序,
'default'
代表預設會執行這一個:gulp.task('default', gulpSequence('sass', 'minify-css', 'webpack', 'inline'));
12. 在 package.json 裡修改
scripts
下的指令。"scripts": { "build": "gulp" },
13. 在 index.html 裡面修改 CSS 跟 JS 檔案的路徑。
<link href="./dist/style.min.css" rel="stylesheet" type="text/css"> <script src="./dist/bundle.min.js" type="text/javascript"></script>
14. 修改 Sass 檔案裡面的圖片檔案路徑。
我的背景圖片是用相對路徑,輸出後的 style.min.css 已經跑到
dist
資料夾裡面,而不是原本的 src/css
裡,所以圖片路徑也要修改才會讀取到圖片檔案。15. 在 cmd.exe 裡面執行 Gulp。
npm run build
成功的話就會把所有的事情都一次完成,但看我上面的作業過程就知道事情總是不會那麼順利的 XD。
其實真正做作業過程通常是,安裝一個(或多個) plugin 之後 -> 然後寫那一段程式碼 -> 然後執行 Gulp 測試可不可以正常執行。中間要是有出錯,就要去找出錯誤在哪裡。
作業過程中除了 Webpack uglifyJS 有出錯,inline 的時候也因為忘記修改 CSS 路徑沒讀到正確檔案,背景圖片也是忘記改檔案路徑而讀不到圖片檔案。總之,作業過程其實沒有上面寫的那麼順暢,但比起上週 Webpack 作業,至少知道整個流程的感覺,而不是像上次一樣進入一個完全未知領域。
這次作業也是學到很多東西,而且知道 Gulp 可以自動化處理好多事情,以後就可以好好利用~
因為這次作業無法放在 CodePen 上,所以我放上這次作業的 GitHub 跟 GitHub Page。
- hw9 GitHub: https://github.com/pychiang/frontend-intermediate-course/tree/master/answers/hw9
- hw9 GitHub Page: https://pychiang.github.io/frontend-intermediate-course/answers/hw9/dist/index.html
No comments:
Post a Comment