使用gulp搭建專案

X南川發表於2021-05-26

專案原始碼地址

前期準備工作

安裝 gulp 命令列工具

npm install --global gulp-cli

在專案目錄下建立 package.json 檔案

npm init -y

安裝 gulp,作為開發時依賴項

npm install --save-dev gulp

檢查 gulp 版本

gulp --version
PS D:\a-個人專案管理\使用Gulp搭建專案\gulp-building> gulp --version
CLI version: 2.3.0
Local version: 4.0.2

建立配置檔案

在根目錄下新建 src 資料夾和 gulpfile.js 檔案

src 目錄下新建如下檔案,其中 index.html 作為我們的入口頁面

gulp 中常用方法解釋

src

建立一個流,用於從檔案系統讀取 Vinyl 物件。

函式原型

src(globs, [options])

返回值

返回一個可以在管道的開始或中間使用的流,用於根據給定的 globs 新增檔案。

globs

glob 是由普通字元和/或通配字元組成的字串,用於匹配檔案路徑。可以利用一個或多個 glob 在檔案系統中定位檔案。

src() 方法接受一個 glob 字串或由多個 glob 字串組成的陣列作為引數,用於確定哪些檔案需要被操作。glob 或 glob 陣列必須至少匹配到一個匹配項,否則 src() 將報錯。當使用 glob 陣列時,將按照每個 glob 在陣列中的位置依次執行匹配 - 這尤其對於取反(negative) glob 有用。

特殊字元: * (一個星號)

在一個字串片段中匹配任意數量的字元,包括零個匹配。對於匹配單級目錄下的檔案很有用。

下面這個 glob 能夠匹配類似 index.js 的檔案,但是不能匹配類似 scripts/index.jsscripts/nested/index.js 的檔案。

'*.js'

特殊字元: ** (兩個星號)

在多個字串片段中匹配任意數量的字元,包括零個匹配。 對於匹配巢狀目錄下的檔案很有用。請確保適當地限制帶有兩個星號的 glob 的使用,以避免匹配大量不必要的目錄。

下面這個 glob 被適當地限制在 scripts/ 目錄下。它將匹配類似 scripts/index.jsscripts/nested/index.jsscripts/nested/twice/index.js 的檔案。

'scripts/**/*.js'

desc

dest() 接受一個輸出目錄作為引數,並且它還會產生一個 Node 流(stream),通常作為終止流(terminator stream)。當它接收到通過管道(pipeline)傳輸的檔案時,它會將檔案內容及檔案屬性寫入到指定的目錄中。gulp 還提供了 symlink() 方法,其操作方式類似 dest(),但是建立的是連結而不是檔案( 詳情請參閱 symlink() )。

大多數情況下,利用 .pipe() 方法將外掛放置在 src()dest() 之間,並轉換流(stream)中的檔案。

series

將任務函式和/或組合操作組合成更大的操作,這些操作將按順序依次執行。對於使用 series()parallel() 組合操作的巢狀深度沒有強制限制。

用法

const { series } = require('gulp');

function javascript(cb) {
  // body omitted
  cb();
}

function css(cb) {
  // body omitted
  cb();
}

exports.build = series(javascript, css);

parallel

將任務功能和/或組合操作組合成同時執行的較大操作。對於使用 series()parallel() 進行巢狀組合的深度沒有強制限制。

用法

const { parallel } = require('gulp');

function javascript(cb) {
  // body omitted
  cb();
}

function css(cb) {
  // body omitted
  cb();
}

exports.build = parallel(javascript, css);

watch

監聽 globs 並在發生更改時執行任務。任務與任務系統的其餘部分被統一處理。

用法

const { watch } = require('gulp');

watch(['input/*.js', '!input/something.js'], function(cb) {
  // body omitted
  cb();
});

啟動專案並熱更新

安裝

npm install --save-dev browser-sync

使用

gulpfile.js 檔案中配置如下程式碼

const { series, parallel, src, dest, watch } = require("gulp");
const browserSync = require("browser-sync"); // 啟動專案
const reload = browserSync.reload; // 更新頁面

// 啟動專案
function server() {
  browserSync({
    notify: false, // 關閉通知,頁面右上角不會出現彈框
    port: 3000, // 啟動 3000 埠
    server: {
      baseDir: ["src"], // 配置根目錄,在這個根目錄下啟動伺服器
    },
    callbacks: {
      // 專案啟動成功後執行的方法
      ready: () => {
        console.log("開始監控開發資料夾");
        // 設定要監控的頁面,當被監控頁面發生變化時執行過載方法
        const watcher = watch(["src/**/*.html", "src/**/*.js", "src/**/*.css"]);
        // 監聽到變化後執行
        watcher.on("change", () => {
          // 頁面變化後執行過載方法
          reload();
        });
      },
    },
  });
}

// 公開 server 任務,執行 gulp server 執行啟動任務
exports.server = server;

執行

然後在控制檯中執行 gulp server

執行成功如上圖所示,同時自動瀏覽器

壓縮 HTML

安裝

npm install --save-dev gulp-htmlmin gulp-html-replace

配置

下面用到的 gulp-html-replace 替換檔案引用地址,我們需要在 html 中需要替換的地方通過註釋形式來告訴配置檔案我要替換那個地址

標記格式,標記後我們就可以通過標記的名稱來對引用地址進行替換

<!-- build:css -->
<link rel="stylesheet" href="./public/css/index.css">
<!-- endbuild -->

<!-- build:js -->
<script src="./public/js/index.js"></script>
<!-- endbuild -->

配置程式碼

const { series, parallel, src, dest, watch } = require("gulp");
const htmlmin = require("gulp-htmlmin"); // 壓縮html
const htmlreplace = require("gulp-html-replace"); // 替換檔案引用地址
// 配置壓縮html的規則
const indexOptions = {
  removeComments: true, // 清除html註釋
  collapseWhitespace: true, // 壓縮html
  collapseBooleanAttributes: true, //省略布林屬性的值 <input checked="true"/> -> <input checked />
  removeEmptyAttributes: true, // 刪除所有空格作為屬性值 <inpit id=""/> -> <inpit/>
  minifyCss: true, // 壓縮頁面中的css
  minifyJs: true, // 壓縮頁面中的js
};

// 壓縮打包html
function html() {
  return src(["src/view/**/*.html"])
    .pipe(htmlmin(indexOptions)) // 使用上面定義的壓縮配置進行壓縮html
    .pipe(dest("dist/html/")); // 將檔案寫入到 dist/html/ 目錄下
}
// 單獨處理一下 index.html
function indexhtml() {
  return src("src/index.html")
    .pipe(
      htmlreplace({
        // 替換標記的路徑
        css: "css/index.css",
        js: "js/index.min.js",
      })
    )
    .pipe(htmlmin(indexOptions)) // 使用上面定義的壓縮配置進行壓縮html
    .pipe(dest("dist/"));
}

壓縮 CSS

安裝

npm install --save-dev gulp-csso @babel/core

配置

const { series, parallel, src, dest, watch } = require("gulp");
const csso = require("gulp-csso"); // 壓縮css

// 壓縮css
function css() {
  return src("src/public/css/**/*.css").pipe(csso()).pipe(dest("dist/css"));
}

壓縮 JS

安裝

npm install --save-dev gulp-uglify gulp-babel gulp-rename gulp-string-replace

配置

const { series, parallel, src, dest, watch } = require("gulp");
const babel = require("gulp-babel"); // 支援es6以及模組化
const uglify = require("gulp-uglify"); // 壓縮js程式碼
const rename = require("gulp-rename"); // 重新命名檔案
const replace = require("gulp-string-replace"); // 替換字串

// 壓縮js
function js() {
  // 即使這個任務不需要回撥,但也要有一個預設的回撥方法,也可以return
  // cb();
  return src("src/public/js/*.js")
    .pipe(babel())
    .pipe(uglify()) // 壓縮js程式碼
    .pipe(replace(/assetApi/g, "https://www.gulpjs.com.cn")) // 替換程式碼中的 "assetApi"
    .pipe(rename({ extname: ".min.js" })) // 將匹配到的檔案重名名為xxx.main.js
    .pipe(dest("dist/js/")); // 將檔案寫入到 dist/js/ 目錄下
}

清空檔案

安裝

npm install --save-dev gulp-clean

配置

const { series, parallel, src, dest, watch } = require("gulp");
const clean = require("gulp-clean"); // 清空資料夾

// 清空dist資料夾
function cleans() {
  // 獲取到dist資料夾下面的所有檔案,進行清空操作
  return src(["./dist/*"]).pipe(clean());
}

打包程式碼

新建打包任務

/**
 * 打包任務
 * 私有任務也可以在 series 組合中使用
 * series 是順序執行多個任務
 * parallel 是平行執行多個任務
 */
const build = series(cleans, js, html, indexhtml, css, function (cb) {
  // 必須要有一個回撥方法
  cb();
});

// 公開 build 任務,執行 gulp build 執行打包任務
exports.build = build;

在控制檯執行 gulp build

執行成功後會在根目錄下自動生成一個 dist 資料夾

我們開啟打包好的檔案,可以看到配置的一些規則都是生效的

我們在檔案中直接雙擊開啟 dist/index.html

頁面可以正常的顯示出來,表示路徑的引用也是正確的

完整的開發依賴包

"devDependencies": {
  "@babel/core": "^7.14.3",
  "browser-sync": "^2.26.14",
  "gulp": "^4.0.2",
  "gulp-babel": "^8.0.0",
  "gulp-clean": "^0.4.0",
  "gulp-csso": "^4.0.1",
  "gulp-html-replace": "^1.6.2",
  "gulp-htmlmin": "^5.0.1",
  "gulp-rename": "^2.0.0",
  "gulp-string-replace": "^1.1.2",
  "gulp-uglify": "^3.0.2",
  "gulp-webserver": "^0.9.1"
}

完整的配置程式碼

const { series, parallel, src, dest, watch } = require("gulp");
const babel = require("gulp-babel"); // 支援es6以及模組化
const uglify = require("gulp-uglify"); // 壓縮js程式碼
const rename = require("gulp-rename"); // 重新命名檔案
const clean = require("gulp-clean"); // 清空資料夾
const csso = require("gulp-csso"); // 壓縮css
const htmlmin = require("gulp-htmlmin"); // 壓縮html
const gulpServer = require("gulp-webserver"); // 啟動專案
const htmlreplace = require("gulp-html-replace"); // 替換檔案引用地址
const replace = require("gulp-string-replace"); // 替換字串
const browserSync = require("browser-sync"); // 啟動專案
const reload = browserSync.reload; // 更新頁面

// 配置壓縮html的規則
const indexOptions = {
  removeComments: true, // 清除html註釋
  collapseWhitespace: true, // 壓縮html
  collapseBooleanAttributes: true, //省略布林屬性的值 <input checked="true"/> -> <input checked />
  removeEmptyAttributes: true, // 刪除所有空格作為屬性值 <inpit id=""/> -> <inpit/>
  minifyCss: true, // 壓縮頁面中的css
  minifyJs: true, // 壓縮頁面中的js
};

// 清空dist資料夾
function cleans() {
  // 獲取到dist資料夾下面的所有檔案,進行清空操作
  return src(["./dist/*"]).pipe(clean());
}

// 壓縮js
function js() {
  // 即使這個任務不需要回撥,但也要有一個預設的回撥方法,也可以return
  // cb();
  return src("src/public/js/*.js")
    .pipe(babel())
    .pipe(uglify()) // 壓縮js程式碼
    .pipe(replace(/assetApi/g, "https://www.gulpjs.com.cn")) // 替換程式碼中的 "assetApi"
    .pipe(rename({ extname: ".min.js" })) // 將匹配到的檔案重名名為xxx.main.js
    .pipe(dest("dist/js/")); // 將檔案寫入到 dist/js/ 目錄下
}

// 壓縮打包html
function html() {
  return src(["src/view/**/*.html"])
    .pipe(htmlmin(indexOptions)) // 使用上面定義的壓縮配置進行壓縮html
    .pipe(dest("dist/html/")); // 將檔案寫入到 dist/html/ 目錄下
}

// 單獨處理一下 index.html
function indexhtml() {
  return src("src/index.html")
    .pipe(
      htmlreplace({
        // 從註釋標記中獲取要替換的路徑
        css: "css/index.css",
        js: "js/index.min.js",
      })
    )
    .pipe(htmlmin(indexOptions)) // 使用上面定義的壓縮配置進行壓縮html
    .pipe(dest("dist/"));
}

// 壓縮css
function css() {
  return src("src/public/css/**/*.css").pipe(csso()).pipe(dest("dist/css"));
}

// 啟動專案
function server() {
  browserSync({
    notify: false, // 關閉通知,頁面右上角不會出現彈框
    port: 3000, // 啟動 3000 埠
    server: {
      baseDir: ["src"], // 配置根目錄,在這個根目錄下啟動伺服器
    },
    callbacks: {
      // 專案啟動成功後執行的方法
      ready: () => {
        console.log("開始監控開發資料夾");
        // 設定要監控的頁面,當被監控頁面發生變化時執行過載方法
        const watcher = watch(["src/**/*.html", "src/**/*.js", "src/**/*.css"]);
        // 監聽到變化後執行
        watcher.on("change", () => {
          // 頁面變化後執行過載方法
          reload();
        });
      },
    },
  });
}

/**
 * 打包任務
 * 私有任務也可以在 series 組合中使用
 * series 是順序執行多個任務
 * parallel 是平行執行多個任務
 */
const build = series(cleans, js, html, indexhtml, css, function (cb) {
  // 必須要有一個回撥方法
  cb();
});

// 公開 server 任務,執行 gulp server 執行啟動任務
exports.server = server;
// 公開 build 任務,執行 gulp build 執行打包任務
exports.build = build;

相關文章