使用gulp搭建項目

項目源碼地址

前期準備工作

安裝 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, "//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, "//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;