Gulp 製做寫 Demo 小工具

既然從新學習了 Gulp,那索性就再把之前用 Gulp 寫的東西拿出來,從新寫一遍。此次寫的時候要把要點記錄下來,否則之後忘了就無法回憶了。javascript

由於 Gulp 如今使用沒有之前那麼多了,因此就不寫複雜的應用了。此次寫一個簡單的 Demo 處理工具,只是爲了把 PSD 轉成 HTML 的時候,減小一些重複性操做。css

因爲寫 Demo 的時候,只去關心頁面結構和對應的樣式,所以,不去考慮 js 相關的內容。主要實現如下幾個功能點 :html

  • 在 Gulp 的配置文件中使用 ES6 語法書寫代碼
  • 將 flexible.js 和 reset.css 注入到每一個 html 文件的頭部
  • 使用 SASS 寫樣式
  • 自動增長瀏覽器前綴,處理樣式兼容
  • 自動將 px 轉成 rem
  • 壓縮樣式文件
  • 壓縮圖片
  • 去除 .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 中使用 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 文件的時候,就稍微複雜點了。由於牽涉到壓縮和替換。若是要替換 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'));
});

處理樣式

樣式文件的處理相對就比較複雜一點了。須要實現如下幾個功能點 :

  1. 將 sass 文件轉成 css
  2. 將 px 轉成 rem
  3. 自動增長瀏覽器前綴
  4. 排序 css 屬性
  5. 壓縮 css 代碼

首先定義一個規則,如下劃線開頭的 .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-postcsspostcss-px2rempostcss-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'));

使用

  1. 在 src/html 寫 html 文件
  2. 在頁面的頭部加入 <script type="text/javascript" src="../common/flexible.min.js"></script><link rel="stylesheet" type="text/css" href="../common/reset.css">
  3. 在 src/css 中寫 .scss 樣式
  4. 將圖片放入 imgs 文件夾中
  5. 執行命令 : ./node_modules/.bin/gulp

固然,命令也能夠簡化,就是在 package.json 中配置。

"scripts": {
    "gulp": "gulp"
  }

這個時候在命令行執行命令就變成下面的形式了 :

$ npm run gulp
相關文章
相關標籤/搜索