既然從新學習了 Gulp,那索性就再把之前用 Gulp 寫的東西拿出來,從新寫一遍。此次寫的時候要把要點記錄下來,否則之後忘了就無法回憶了。javascript
由於 Gulp 如今使用沒有之前那麼多了,因此就不寫複雜的應用了。此次寫一個簡單的 Demo 處理工具,只是爲了把 PSD 轉成 HTML 的時候,減小一些重複性操做。css
因爲寫 Demo 的時候,只去關心頁面結構和對應的樣式,所以,不去考慮 js 相關的內容。主要實現如下幾個功能點 :html
爲了這幾個小目標,下面開始逐步實現這些功能點。java
使用的 Gulp 版本是
3.9.1
。
建立一個 package.json :node
$ npm init -y
安裝 Gulp 做爲項目的開發依賴 :git
$ yarn add gulp -D
在項目開始以前,首先須要搭建目錄結構。github
. ├── gulpfile.babel.js gulp 的配置文件 ├── package.json ├── src Demo 源代碼存放的目錄 │ ├── common 公共文件存放的目錄,未來注入到html文件中 │ │ ├── flexible.min.js │ │ └── reset.css │ ├── css │ │ ├── _none.scss │ │ └── useful.scss │ ├── html │ │ └── index.html │ └── imgs │ └── test.png ├── task 任務文件夾 │ ├── task-clean.js 刪除 dist 目錄 │ ├── task-css.js 處理 css 的任務 │ ├── task-default.js 默認任務 │ ├── task-html.js 處理 html 的任務 │ └── task-img.js 處理圖片的任務 └── yarn.lock
若是須要在 gulpfile.js 中使用 ES6 相關語法,就須要把 gulpfile.js 改爲 gulpfile.babel.js。更改文件名以後,在文件中寫入 ES6 的代碼。npm
import gulp from 'gulp'; gulp.task('default', () => console.log(123));
運行命令以後,發現,報錯了。json
$ ./node_modules/.bin/gulp [14:15:34] Failed to load external module @babel/register [14:15:34] Failed to load external module babel-register [14:15:34] Failed to load external module babel-core/register [14:15:34] Failed to load external module babel/register
出現這個錯誤是由於使用 ES6 語法後,須要通過 babel 進行轉碼後才能正常執行任務,所以,要配置 babel 相關的內容。gulp
首先是須要安裝 babel 的依賴 :
$ yarn add babel-cli babel-preset-env -D
babel 在運行的時候,須要讀取其配置文件中的信息,將對應的代碼進行轉譯。因此,.babelrc
文件必不可少。
{ "presets": ["env"] }
再次運行 Gulp 命令的時候,會發現仍是有錯誤。
$ ./node_modules/.bin/gulp [14:20:33] Failed to load external module @babel/register
這個錯誤就很奇怪了,命名已經安裝了 babel 的依賴了,爲何還會有這個錯誤呢?這是由於在解析 .babel.js
文件中,加載 babel 組件不正確形成的。babel-core/register 已通過時了,如今使用 babel-register 來代替了。若是要修復這個問題,就須要修改 node_modules 中 interpret 模塊中的 index.js
。
將 module: '@babel/register'
改爲 module: 'babel-register'
。具體修改的位置就是下面代碼中的第三行 :
'.babel.js': [ { module: '@babel/register',
在 gulpfile.babel.js 中,咱們將 task 目錄下的文件加載到該配置文件中,這個時候須要用到的模塊是 require-dir
。
在項目中安裝 require-dir
模塊 :
$ yarn add require-dir -D
模塊完成以後,改造 gulpfile.babel.js。
import requireDir from 'require-dir'; requireDir('./task');
通常狀況下,把最終生成好的文件放入 dist 目錄中,那麼目標目錄就是 dist。
刪除文件夾或文件,通常使用 del
模塊,這個模塊異步方法返回的是一個 Promise 對象。
// ./task/task-clean.js gulp.task('clean', () => { return del('./dist').then(paths => { // 若是 paths 長度爲 0,說明文件夾不存在 if (paths.length) { console.log(paths + ' 刪除成功') } else { console.log('文件夾不存在'); } }); });
經過上面的代碼建立的 clean 任務,在執行任務 clean 的時候,就能夠把 dist 目錄進行刪除了。
圖片的處理相對就比較簡單了,只須要壓縮圖片並拷貝到對應的目錄中就能夠了。壓縮圖片使用的模塊是 gulp-imagemin
。
gulp.task('imgs', () => { return gulp.src([ './src/imgs/*.jpg', './src/imgs/*.png', './src/imgs/*.gif', './src/imgs/*.svg' ], { base: 'src' }) .pipe(imagemin()) .pipe(gulp.dest('./dist')); });
經過上面的代碼建立的 imgs 任務,在執行任務 imgs 的時候,就能夠把 ./src/imgs
中的內容壓縮並拷貝到 ./dist/imgs
中了。
處理 html 文件的時候,就稍微複雜點了。由於牽涉到壓縮和替換。若是要替換 html 中的內容,使用的模塊是 gulp-replace
;若是須要壓縮 html 文件,那麼就須要使用 gulp-htmlmin
。
在這裏,須要替換 html 中引入 flexible.js 的地方爲對應的內容,就須要寫成下面的形式 :
.pipe(replace('<script type="text/javascript" src="../common/flexible.min.js"></script>', () => { // 獲取 flexible.min.js 文件中的內容 let flexibleData = fs.readFileSync(path.resolve(__dirname, '../src/common/flexible.min.js')); // 返回一個流,寫入共下一個內容使用 return `<script type="text/javascript">\n${flexibleData}</script>`; }))
同時初始化 css 的樣式也要注入到 html 文件中,這個時候就要把 html 中對應的路徑替換成對應的文件內容 :
.pipe(replace('<link rel="stylesheet" type="text/css" href="../common/reset.css">', () => { // 獲取 reset.css 文件中的內容 let flexibleData = fs.readFileSync(path.resolve(__dirname, '../src/common/reset.css')); // 返回一個流,寫入共下一個內容使用 return `<style type="text/css">\n${flexibleData}</style>`; }))
對應的文件替換完成以後,就須要刪除 html 文件中的全部註釋信息 :
.pipe(htmlmin({ collapseWhitespace: false, // 刪除文檔中的空格和換行,默認是false,不刪除 removeComments: true // 清除註釋內容 }))
最後就是將對應的 html 文件拷貝到對應的文件夾中。完整的任務代碼以下 :
gulp.task('html', () => { return gulp.src('./src/html/*.html', { base: 'src' }) .pipe(replace('<script type="text/javascript" src="../common/flexible.min.js"></script>', () => { // 獲取 flexible.min.js 文件中的內容 let flexibleData = fs.readFileSync(path.resolve(__dirname, '../src/common/flexible.min.js')); // 返回一個流,寫入共下一個內容使用 return `<script type="text/javascript">\n${flexibleData}</script>`; })) .pipe(replace('<link rel="stylesheet" type="text/css" href="../common/reset.css">', () => { // 獲取 reset.css 文件中的內容 let flexibleData = fs.readFileSync(path.resolve(__dirname, '../src/common/reset.css')); // 返回一個流,寫入共下一個內容使用 return `<style type="text/css">\n${flexibleData}</style>`; })) .pipe(htmlmin({ collapseWhitespace: false, // 刪除文檔中的空格和換行,默認是false,不刪除 removeComments: true // 清除註釋內容 })) .pipe(gulp.dest('./dist')); });
樣式文件的處理相對就比較複雜一點了。須要實現如下幾個功能點 :
首先定義一個規則,如下劃線開頭的 .scss 文件不進行轉換。將如下劃線開頭的 .scss 文件做爲提供公共方法的文件。
gulp.src(['./src/css/*.scss', '!./src/css/_*.scss'], { base: 'src' })
對 .scss 文件進行轉譯,生成的 css 文件不刪除註釋,由於註釋信息在 px 轉成 rem 的時候會用到。在轉換的過程當中,使用的模塊是 gulp-sass
。
.pipe(sass({ outputStyle: 'compact' // sass文件的輸出方式,保留註釋內容 }))
將 px 轉成對應的 rem,須要依賴兩個模塊 gulp-postcss
和 postcss-px2rem
。postcss-px2rem
是核心的轉換模塊。
.pipe(postcss([px2rem({ remUnitpx2rem: 75 // // 將px轉成rem,基準值是75,也就是用 75px/75=1rem })]))
接下來就能夠作 css 的兼容處理,爲屬性增長瀏覽器前綴了。自動增長瀏覽器前綴使用到的模塊是 gulp-autoprefixer
。
.pipe(autoprefixer({ browsers: ['last 2 versions', 'Android >= 4.0'] // 控制增長前綴的版本 }))
根據頁面中的標籤及標籤中的選擇器屬性,來精簡樣式。主要就是使用 postcss 的插件 postcss-uncss
來精簡樣式,可是 postcss-uncss
模塊又依賴 uncss
模塊,所以,這兩個模塊都須要安裝。安裝完成以後,就能夠設置精簡樣式的代碼了。
.pipe(postcss([uncss({ // 去除多餘的樣式 html: ['./src/**/*.html'] })]))
下面作的就是排序和壓縮 css 了。排序 css 屬性用到的模塊是 gulp-csscomb
,壓縮 css 用到的模塊是 gulp-cssnano
。
.pipe(csscomb()) // 排序CSS屬性 .pipe(cssnano()) // 壓縮CSS代碼 .pipe(gulp.dest('./dist'));
在默認任務中,首先序列化任務的執行順序。在每次執行任務以前,先把 dist 目錄刪除,而後執行 html css imgs 任務。這個時候就要使用 gulp-sequence
模塊來定義任務執行的順序。爲了實現任務的順序執行,就要在每一個任務中返回一個流,或者調用一個回調函數,不然執行順序會不正常。
gulp.task('build', gulpSequence('clean', ['html', 'css', 'imgs']));
若是要實現代碼修改,瀏覽器自動刷新,就要使用 browser-sync
模塊了。
gulp.task('default', ['build'], () => { // 啓動瀏覽器 browserSync({ server: { baseDir: './dist' }, }, (err, bs) => { console.log(bs.options.getIn(["urls", "local"])); }); // 監視文件變化,執行對應的任務 gulp.watch('src/html/*.*', ['html']); gulp.watch('src/css/*.*', ['css']); gulp.watch('src/imgs/*.*', ['imgs']); });
在執行默認任務後,修改代碼,並無發現瀏覽器跟着刷新。
$ ./node_modules/.bin/gulp
這是由於每一個任務中沒有通知瀏覽器刷新,所以,要在每一個任務中加入流發生變化,通知瀏覽器刷新。
.pipe(browserSync.reload({ // 管道刷新 stream: true })) .pipe(gulp.dest('./dist'));
<script type="text/javascript" src="../common/flexible.min.js"></script>
和 <link rel="stylesheet" type="text/css" href="../common/reset.css">
./node_modules/.bin/gulp
固然,命令也能夠簡化,就是在 package.json 中配置。
"scripts": { "gulp": "gulp" }
這個時候在命令行執行命令就變成下面的形式了 :
$ npm run gulp