自動化構建
什么是構建
- 構建是將源代碼轉換成生產代碼的過程
為什么構建
- 一些代碼需要編譯(CSS,JS), 保證瀏覽器的兼容性
將 Less 或 Sass 轉換成 CSS
將 ES6+ 的新語法轉成 ES5 - 有些代碼需要壓縮(CSS,JS,HTML,圖片等)
壓縮之后的代碼體積更小,加載更快,節省帶寬 - 有些代碼需要做格式化校驗,統一代碼風格
- 構建過程:源代碼通過編譯、壓縮、格式化等等轉化成生成代碼
什么是自動化構建
- 不管是代碼壓縮還是 less 轉換,通過手動方式進行工作量巨大,自動化構建是指將手動構建任務,進行排列組合,然后通過命令(或工具)自動執行的過程
- 實現自動化構建最簡單的方式是 npm scripts (npm 腳本)
npm scripts
- npm 在
package.json
文件里面,使用scripts
字段定義腳本命令
{
"scripts": {
// 命令名稱: 任務
"foo": "node bar.js"
}
}
# `scripts` 字段是一個對象。它的每一個屬性,對應一段腳本。比如,`foo` 命令對應的腳本是`node bar.js`。
# 命令行下使用 npm run <命令>,就可以執行這段腳本。
$ npm run foo
# 等同于執行
$ node bar.js
- npm 腳本就是 Shell 腳本,因為可以使用 Shell 通配符
"style": "lessc *.less"
"style": "lessc **/*.less"
* 表示任意文件名,** 表示任意一層子目錄
- 執行順序
如果是并行執行(即同時的平行執行),可以使用&
符號
{
"scripts": {
"parallel": "node task1.js & node task2.js & node task3.js"
}
}
如果是串行執行(前一個任務成功后,才執行下一個任務),可以使用 &&
符號
{
"scripts": {
"series": "node task1.js && node task2.js && node task3.js"
}
}
但是,& 符號在 Windows 操作系統下不起作用。此時,我們可以借助插件,在 Windows 下實現并行操作:npm-run-all
構建樣式文件
構建樣式文件就是將開發環境下的 JavaScript 源代碼,轉成線上環境使用的代碼。這里的構建任務可能有多個。
在開發過程中,經常使用 ES6+ 新特性時,一些舊的瀏覽器,不支持 JS 的新語法。所以,在項目上線之前,就需要將新的語法特性解析成兼容性更好的 ES5 。最常用的編譯工具是 Babel
Babel https://babeljs.io/
# 安裝 babel核心,Babel客戶端
npm i -g babel-core babel-cli
# 安裝轉碼規則
npm i -g babel-preset-env
# 在項目根目錄下,新建 .babelrc 文件(注意文件名前有一個點),并添加轉換規則
{
"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",
}
# 執行命令(自動編譯)
npm run script
# 如果 Babel 是局部安裝。則babel 的可執行路徑是:./node_modules/.bin/babel命令需要做相應的調整
# 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 代碼
# 配置檢測規則
{
"env": {
"browser": true,
"commonjs": true,
"es2021": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 12
},
"rules": {
"indent": [ "error", 2 ], # 使用兩個空格縮進
"quotes": [ "error", "double" ] # 使用雙引號包裹字符串
}
}
- 檢測 JS 代碼風格的工具有多個,除了 ESLint, 另一個常用的是 Standard:
https://github.com/standard/standard
StyleLint
StyleLint 是檢測 CSS 代碼格式的插件
官網:https://stylelint.io/
- 在項目的根目錄下,創建 .stylelintrc.json 文件,添加如下配置
{
"extends": "stylelint-config-standard",
"rules": {
# 除了使用 stylelint-config-standard,我們還可以在 rules 字段中自定義校驗規則
"block-no-empty": true # 代碼塊不能為空
}
}
自動化構建工具Gulp
自動化構建工具,可以幫我們又快又好的完成自動化構建任務。相比有 npm scripts,自動化構建工具,功能更為強大。更簡單易學
- Gulp 的構建是基于內存實現的,其構建速度比 Grunt 快,而且,Gulp 的生態也很完善,插件質量很高。目前最為流行
Gulp
Gulp 是基于 流 的自動化構建系統。
- Gulp 的特點:
- 任務化
所有的構建操作,在 gulp 中都稱之為任務 - 基于流
gulp 中所有的文件操作,都是基于 流 方式進行 ( Gulp有一個自己的內存,通過指定 API 將源文件流到內存中,完成相應的操作后再通過相應的 API 流出去)
Gulp 使用
- 使用 Gulp 之前,先在全局安裝 gulp-cli
命令:npm i -g gulp-cli - 初始化項目
npm init --yes - 安裝 Gulp 包
# 安裝 gulp 包,作為開發時依賴項
npm i gulp -D
- 創建 gulpfile 文件
gulpfile 文件是項目根目錄下的gulpfile.js
,在運行gulp
命令時會被自動加載。在這個文件中,你經常會看到類似src()
、dest()
、series()
或parallel()
函數之類的 Gulp API,除此之外,純 JavaScript 代碼或 Node.js 模塊也會被使用。任何導出( exports )的函數都將注冊到 Gulp 的任務(task)系統中
報錯:The following tasks did not complete: task
Did you forget to signal async completion?
解釋:在最新的 Gulp 中,取消了同步代碼模式。約定每個任務都必須是一個異步任務
解決:再函數參數中,設定回調函數(回調函數是異步操作)
在 gulpfile.js 中注冊 Gulp 任務
運行 Gulp 任務
# 運行 foo 任務
# 如需運行多個任務(task),可以執行 gulp <task> <othertask>
gulp foo
- 創建默認任務
# 默認任務的名稱是 default
exports.default = cb => {
console.log('default task is running')
cb()
}
# 運行默認任務, gulp 后無需指定任務名稱
gulp # 效果等同于 gulp default
組合任務
- 按順序執行,請使用
series()
方法 - 并行執行,可以使用
parallel()
方法將它們組合起來
const gulp = require('gulp')
# 串行方式執行任務,先執行task1, 然后執行task2, 然后執行task3
exports.foo = gulp.series(task1, task2, task3)
# 并行方式執行任務,同時執行task1,task2,task3
exports.bar = gulp.parallel(task1, task2, task3)
# 執行命令
gulp foo # 串行執行
gulp bar # 并行執行
文件操作
gulp 暴露了 src()
和 dest()
方法用于處理計算機上存放的文件。在代碼構建過程中,需要將源文件,寫入到目標目錄。
# 通過 解構 的方式引入 gulp 中的函數
const { src, dest } = require('gulp')
exports.default = () => {
// 文件操作
// 將 src/styles 目錄下的 main.css 文件,復制到 dist/styles 目錄下
return src('src/styles/main.less', { base: 'src' }).pipe(dest('dist'))
}
# 執行命令
gulp default
# 或直接執行
gulp
樣式文件構建
- 對樣式文件進行轉換、壓縮、重命名。
- 添加 CSS 屬性前綴的操作,之前是通過程序員手動添加的。這類重復性操作,我們可以通過插件完成。
- 在 Gulp 中 gulp-autoprefixer 插件,可以根據 caniuse.com 上提供的 CSS 兼容性數據,自動地給 CSS 屬性加前綴,以保證 CSS 代碼的兼容性問題。
腳本文件構建
- 對 JS 代碼進行 Babel 轉換和壓縮
頁面模板構建
- 對 html 文件的構建,主要指壓縮 html 文件。其中 gulp-htmlmin 插件可以完成壓縮任務
- gulp-htmlmin 插件的解析器是:https://github.com/kangax/html-minifier
- 我們可以將 style,script 和 html 任務組合起來。因為 style,script 和 html 之間沒有明確的前后順序,所以,可以進行并行執行,并行執行可以提升構建效率
# 引入 parallel 函數
const { src, dest, parallel } = require('gulp')
// 任務的并行執行
const build = parallel(style, script, html)
module.exports = {
build
}
# 運行命令
gulp build
圖片(字體)文件轉換
- 對圖片文件的構建,主要是指圖片的壓縮。通過 gulp-imagemin 插件可以完成圖片的壓縮任務
報錯處理:
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
文件清除
- 有時候,我們需要刪除一些構建的歷史文件,然后再重新構建。刪除文件操作,可以通過 del 插件完成
開發服務器
- 通過web服務器插件,將 dist 下的代碼,發布到瀏覽器查看效果。發布web服務的插件有很多。推薦功能強大的 browser-sync
# 安裝 browser-sync 插件
npm i browser-sync -D
# 在 gulpfile.js 中添加開發服務器的內容
const browserSync = require('browser-sync')
const bs = browserSync.create()
// 聲明 web 服務構建任務
const serve = () => {
bs.init({
server: {
baseDir: './dist' // 指定服務啟動的目錄
routes: {
'/node_modules': 'node_modules' // 引入 Bootstrap 是設置路徑映射
}
}
})
}
module.exports = {
clean,
build,
serve
}
# 運行命令,然后在瀏覽器查看效果
gulp serve
- 服務發布成功后,之前學習的內容,也可以拿過來使用,例如:Bootstrap
- 下載插件
# 因為 Bootstrap 和 jQuery 上線之后還要使用,所以,采用 -S 參數(上線依賴)
npm i bootstrap@3.4.1 jquery -S
- 引入文件
Bootstrap 和 jQuery 下載后,文件位于當前目錄的 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 參數映射后,才能正確引入
- 使用 Bootstrap
監視變化(熱更新)
監視 src 下文件變化的頁面更新,代碼一旦更新,瀏覽器上的頁面效果也隨之更新。
此時,我們需要監視兩個目錄的變化,一個是 dist 目錄,一個是 src 目錄。
-
監視 dist 目錄下代碼的變化
# 通過 browser-sync 中的 files 字段 files: 'dist/**'
-
監視 src 目錄下代碼的變化
# 通過 gulp 中的 watch 函數 watch(被監視的文件,對應的任務)
最終的代碼如下:
# 在 gulpfile.js 中添加監視文件變化的代碼
const serve = () => {
// watch(被監視的文件,對應的任務)
watch('src/index.html', html)
watch('src/styles/*.less', style)
watch('src/js/*.js', script)
watch('src/images/**', image)
// 初始化服務
bs.init({
notify: false, // 禁用瀏覽器右上角的 browserSync connected 提示框
files: 'dist/**', // 監視 dist 下 文件的變化,然后在瀏覽器上實時更新
server: {
baseDir: './dist', // 指定服務啟動的目錄
routes: {
'/node_modules': 'node_modules'
}
}
})
}
// 組合任務
const build = parallel(style, script, html, image)
const dev = series(clean, build, serve)
// 導出任務
module.exports = {
build,
dev,
serve
}
# 運行命令,更新代碼文件,查看頁面變化
gulp dev
此時,不管是 dist 目錄下,還是 src 目錄下。只要代碼發生變化,我們就可以在瀏覽器上實時看到效果。