自動化構(gòu)建和構(gòu)建工具Gulp

自動化構(gòu)建

什么是構(gòu)建
  • 構(gòu)建是將源代碼轉(zhuǎn)換成生產(chǎn)代碼的過程
為什么構(gòu)建
  • 一些代碼需要編譯(CSS,JS), 保證瀏覽器的兼容性
    將 Less 或 Sass 轉(zhuǎn)換成 CSS
    將 ES6+ 的新語法轉(zhuǎn)成 ES5
  • 有些代碼需要壓縮(CSS,JS,HTML,圖片等)
    壓縮之后的代碼體積更小,加載更快,節(jié)省帶寬
  • 有些代碼需要做格式化校驗,統(tǒng)一代碼風(fēng)格
  • 構(gòu)建過程:源代碼通過編譯、壓縮、格式化等等轉(zhuǎn)化成生成代碼
什么是自動化構(gòu)建
  • 不管是代碼壓縮還是 less 轉(zhuǎn)換,通過手動方式進(jìn)行工作量巨大,自動化構(gòu)建是指將手動構(gòu)建任務(wù),進(jìn)行排列組合,然后通過命令(或工具)自動執(zhí)行的過程
  • 實現(xiàn)自動化構(gòu)建最簡單的方式是 npm scripts (npm 腳本)
npm scripts
  • npm 在 package.json 文件里面,使用 scripts 字段定義腳本命令
{
  "scripts": {
    // 命令名稱: 任務(wù)
    "foo": "node bar.js"
  }
}
# `scripts` 字段是一個對象。它的每一個屬性,對應(yīng)一段腳本。比如,`foo` 命令對應(yīng)的腳本是`node bar.js`。

# 命令行下使用 npm run <命令>,就可以執(zhí)行這段腳本。
$ npm run foo
# 等同于執(zhí)行
$ node bar.js
  • npm 腳本就是 Shell 腳本,因為可以使用 Shell 通配符
"style": "lessc *.less"
"style": "lessc **/*.less"

* 表示任意文件名,** 表示任意一層子目錄

  • 執(zhí)行順序
    如果是并行執(zhí)行(即同時的平行執(zhí)行),可以使用 & 符號
{
  "scripts": {
    "parallel": "node task1.js & node task2.js & node task3.js"
  }
}

如果是串行執(zhí)行(前一個任務(wù)成功后,才執(zhí)行下一個任務(wù)),可以使用 && 符號

{
  "scripts": {
    "series": "node task1.js && node task2.js && node task3.js"
  }
}

但是,& 符號在 Windows 操作系統(tǒng)下不起作用。此時,我們可以借助插件,在 Windows 下實現(xiàn)并行操作:npm-run-all

構(gòu)建樣式文件
  • 構(gòu)建樣式文件就是將開發(fā)環(huán)境下的 JavaScript 源代碼,轉(zhuǎn)成線上環(huán)境使用的代碼。這里的構(gòu)建任務(wù)可能有多個。

  • 在開發(fā)過程中,經(jīng)常使用 ES6+ 新特性時,一些舊的瀏覽器,不支持 JS 的新語法。所以,在項目上線之前,就需要將新的語法特性解析成兼容性更好的 ES5 。最常用的編譯工具是 Babel

  • Babel https://babeljs.io/

# 安裝 babel核心,Babel客戶端
npm i -g babel-core babel-cli

# 安裝轉(zhuǎn)碼規(guī)則
npm i -g babel-preset-env

# 在項目根目錄下,新建 .babelrc 文件(注意文件名前有一個點(diǎn)),并添加轉(zhuǎn)換規(guī)則
{
    "presets": [
      "env"
    ],
}

# 通過 babel 編譯單個 j s文件
babel input.js --out-file output.js
# 或者
babel input.js -o output.js
    
# 通過 babel 編譯整個目錄
babel js --out-dir scripts
# 或者
babel js -d scripts

# 在 package.json 中,添加 babel 解析命令
"scripts": {
    "script": "babel js -d scripts",
}

# 執(zhí)行命令(自動編譯)
npm run script

# 如果 Babel 是局部安裝。則babel 的可執(zhí)行路徑是:./node_modules/.bin/babel命令需要做相應(yīng)的調(diào)整
# babel js -d scripts    ===>   ./node_modules/.bin/babel js -d scripts
  • 添加壓縮命令
# 在 package.json 中,添加 babel 解析和壓縮命令
"scripts": {
    "script": "babel js -d scripts && minify scripts/main.js > scripts/script.min.js",
}
代碼格式校驗

使用 ESLint 來檢測 JavaScript 代碼

# 配置檢測規(guī)則
{
    "env": {
        "browser": true,
        "commonjs": true,
        "es2021": true
    },
    "extends": "eslint:recommended",
    "parserOptions": {
        "ecmaVersion": 12
    },
    "rules": {
        "indent": [ "error", 2 ],       # 使用兩個空格縮進(jìn)
        "quotes": [ "error", "double" ] # 使用雙引號包裹字符串
    }
}
StyleLint

StyleLint 是檢測 CSS 代碼格式的插件
官網(wǎng):https://stylelint.io/

  • 在項目的根目錄下,創(chuàng)建 .stylelintrc.json 文件,添加如下配置
{
  "extends": "stylelint-config-standard",
  "rules": {
    # 除了使用 stylelint-config-standard,我們還可以在 rules 字段中自定義校驗規(guī)則
    "block-no-empty": true # 代碼塊不能為空
  }
}

自動化構(gòu)建工具Gulp

自動化構(gòu)建工具,可以幫我們又快又好的完成自動化構(gòu)建任務(wù)。相比有 npm scripts,自動化構(gòu)建工具,功能更為強(qiáng)大。更簡單易學(xué)

  • Gulp 的構(gòu)建是基于內(nèi)存實現(xiàn)的,其構(gòu)建速度比 Grunt 快,而且,Gulp 的生態(tài)也很完善,插件質(zhì)量很高。目前最為流行

Gulp

Gulp 是基于 的自動化構(gòu)建系統(tǒng)。

  • Gulp 的特點(diǎn):
  • 任務(wù)化
    所有的構(gòu)建操作,在 gulp 中都稱之為任務(wù)
  • 基于流
    gulp 中所有的文件操作,都是基于 方式進(jìn)行 ( Gulp有一個自己的內(nèi)存,通過指定 API 將源文件流到內(nèi)存中,完成相應(yīng)的操作后再通過相應(yīng)的 API 流出去)
Gulp 使用
  1. 使用 Gulp 之前,先在全局安裝 gulp-cli
    命令:npm i -g gulp-cli
  2. 初始化項目
    npm init --yes
  3. 安裝 Gulp 包
# 安裝 gulp 包,作為開發(fā)時依賴項
npm i gulp -D
  1. 創(chuàng)建 gulpfile 文件
    gulpfile 文件是項目根目錄下的 gulpfile.js,在運(yùn)行 gulp 命令時會被自動加載。在這個文件中,你經(jīng)常會看到類似 src()、dest()、series()parallel() 函數(shù)之類的 Gulp API,除此之外,純 JavaScript 代碼或 Node.js 模塊也會被使用。任何導(dǎo)出( exports )的函數(shù)都將注冊到 Gulp 的任務(wù)(task)系統(tǒng)中

報錯:The following tasks did not complete: task
Did you forget to signal async completion?
解釋:在最新的 Gulp 中,取消了同步代碼模式。約定每個任務(wù)都必須是一個異步任務(wù)
解決:再函數(shù)參數(shù)中,設(shè)定回調(diào)函數(shù)(回調(diào)函數(shù)是異步操作)

  1. 在 gulpfile.js 中注冊 Gulp 任務(wù)

  2. 運(yùn)行 Gulp 任務(wù)

# 運(yùn)行 foo 任務(wù)
# 如需運(yùn)行多個任務(wù)(task),可以執(zhí)行 gulp <task> <othertask>
gulp foo
  1. 創(chuàng)建默認(rèn)任務(wù)
# 默認(rèn)任務(wù)的名稱是 default
exports.default = cb => {
    console.log('default task is running')
    
    cb()
}

# 運(yùn)行默認(rèn)任務(wù), gulp 后無需指定任務(wù)名稱
gulp # 效果等同于 gulp default
組合任務(wù)
  • 按順序執(zhí)行,請使用 series() 方法
  • 并行執(zhí)行,可以使用 parallel() 方法將它們組合起來
const gulp = require('gulp')
# 串行方式執(zhí)行任務(wù),先執(zhí)行task1, 然后執(zhí)行task2, 然后執(zhí)行task3
exports.foo = gulp.series(task1, task2, task3)

# 并行方式執(zhí)行任務(wù),同時執(zhí)行task1,task2,task3
exports.bar = gulp.parallel(task1, task2, task3)

# 執(zhí)行命令
gulp foo # 串行執(zhí)行
gulp bar # 并行執(zhí)行
文件操作

gulp 暴露了 src()dest() 方法用于處理計算機(jī)上存放的文件。在代碼構(gòu)建過程中,需要將源文件,寫入到目標(biāo)目錄。

# 通過 解構(gòu) 的方式引入 gulp 中的函數(shù)
const { src, dest } = require('gulp')

exports.default = () => {
  // 文件操作
  // 將 src/styles 目錄下的 main.css 文件,復(fù)制到 dist/styles 目錄下
  return src('src/styles/main.less', { base: 'src' }).pipe(dest('dist'))
}

# 執(zhí)行命令
gulp default
# 或直接執(zhí)行
gulp

樣式文件構(gòu)建

  • 對樣式文件進(jìn)行轉(zhuǎn)換、壓縮、重命名。
  • 添加 CSS 屬性前綴的操作,之前是通過程序員手動添加的。這類重復(fù)性操作,我們可以通過插件完成。
  • 在 Gulp 中 gulp-autoprefixer 插件,可以根據(jù) caniuse.com 上提供的 CSS 兼容性數(shù)據(jù),自動地給 CSS 屬性加前綴,以保證 CSS 代碼的兼容性問題。

腳本文件構(gòu)建

  • 對 JS 代碼進(jìn)行 Babel 轉(zhuǎn)換和壓縮

頁面模板構(gòu)建

  • 對 html 文件的構(gòu)建,主要指壓縮 html 文件。其中 gulp-htmlmin 插件可以完成壓縮任務(wù)
  • gulp-htmlmin 插件的解析器是:https://github.com/kangax/html-minifier
  • 我們可以將 style,script 和 html 任務(wù)組合起來。因為 style,script 和 html 之間沒有明確的前后順序,所以,可以進(jìn)行并行執(zhí)行,并行執(zhí)行可以提升構(gòu)建效率
# 引入 parallel 函數(shù)
const { src, dest, parallel } = require('gulp')

// 任務(wù)的并行執(zhí)行
const build = parallel(style, script, html)

module.exports = {
  build
}

# 運(yùn)行命令
gulp build

圖片(字體)文件轉(zhuǎn)換

  • 對圖片文件的構(gòu)建,主要是指圖片的壓縮。通過 gulp-imagemin 插件可以完成圖片的壓縮任務(wù)
報錯處理:
gulp-imagemin: Couldn't load default plugin "gifsicle"
gulp-imagemin: Couldn't load default plugin "optipng"
原因:npm 安裝依賴失敗
解決:
1. 配置 hosts
2. 重新安裝 npm i gulp-imagemin -D

文件清除

  • 有時候,我們需要刪除一些構(gòu)建的歷史文件,然后再重新構(gòu)建。刪除文件操作,可以通過 del 插件完成

開發(fā)服務(wù)器

  • 通過web服務(wù)器插件,將 dist 下的代碼,發(fā)布到瀏覽器查看效果。發(fā)布web服務(wù)的插件有很多。推薦功能強(qiáng)大的 browser-sync
# 安裝 browser-sync 插件
npm i browser-sync -D

# 在 gulpfile.js 中添加開發(fā)服務(wù)器的內(nèi)容
const browserSync = require('browser-sync')
const bs = browserSync.create()

// 聲明 web 服務(wù)構(gòu)建任務(wù)
const serve = () => {
  bs.init({
    server: {
      baseDir: './dist' // 指定服務(wù)啟動的目錄
      routes: {
        '/node_modules': 'node_modules' // 引入 Bootstrap 是設(shè)置路徑映射
      }
    }
  })
}

module.exports = {
  clean,
  build,
  serve
}

# 運(yùn)行命令,然后在瀏覽器查看效果
gulp serve
  • 服務(wù)發(fā)布成功后,之前學(xué)習(xí)的內(nèi)容,也可以拿過來使用,例如:Bootstrap
  1. 下載插件
# 因為 Bootstrap 和 jQuery 上線之后還要使用,所以,采用 -S 參數(shù)(上線依賴)
npm i bootstrap@3.4.1 jquery -S
  1. 引入文件
    Bootstrap 和 jQuery 下載后,文件位于當(dāng)前目錄的 node_modules 下
# 在 HTML 中引入
<link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css">
......
<script src="/node_modules/jquery/dist/jquery.min.js"></script>
<script src="/node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
  • 引入路徑,需要在 browser-sync 中,通過 routes 參數(shù)映射后,才能正確引入
  1. 使用 Bootstrap

監(jiān)視變化(熱更新)

  • 監(jiān)視 src 下文件變化的頁面更新,代碼一旦更新,瀏覽器上的頁面效果也隨之更新。

  • 此時,我們需要監(jiān)視兩個目錄的變化,一個是 dist 目錄,一個是 src 目錄。

  • 監(jiān)視 dist 目錄下代碼的變化

    # 通過 browser-sync 中的 files 字段
    files: 'dist/**'
    
  • 監(jiān)視 src 目錄下代碼的變化

    # 通過 gulp 中的 watch 函數(shù)
    watch(被監(jiān)視的文件,對應(yīng)的任務(wù))
    

最終的代碼如下:

# 在 gulpfile.js 中添加監(jiān)視文件變化的代碼
const serve = () => {
  // watch(被監(jiān)視的文件,對應(yīng)的任務(wù))
  watch('src/index.html', html)
  watch('src/styles/*.less', style)
  watch('src/js/*.js', script)
  watch('src/images/**', image)

  // 初始化服務(wù)
  bs.init({
    notify: false,      // 禁用瀏覽器右上角的 browserSync connected 提示框
    files: 'dist/**',   // 監(jiān)視 dist 下 文件的變化,然后在瀏覽器上實時更新
    server: {
      baseDir: './dist', // 指定服務(wù)啟動的目錄
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
}

// 組合任務(wù)
const build = parallel(style, script, html, image)
const dev = series(clean, build, serve)

// 導(dǎo)出任務(wù)
module.exports = {
  build,
  dev,
  serve
}

# 運(yùn)行命令,更新代碼文件,查看頁面變化
gulp dev

此時,不管是 dist 目錄下,還是 src 目錄下。只要代碼發(fā)生變化,我們就可以在瀏覽器上實時看到效果。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容