實(shí)現(xiàn)vue-cli(一):gulp自動(dòng)化構(gòu)建

一如输、大概思路

一般自動(dòng)化構(gòu)建做的主要是以下幾件事情:

(一)開發(fā)階段的構(gòu)建
  1. 將scss轉(zhuǎn)成css,并在臨時(shí)目錄下生成對(duì)應(yīng)的css文件(在開發(fā)階段不需要壓縮旭旭,所以將壓縮放在單獨(dú)的步驟里)谎脯。
  2. 將es6等瀏覽器不支持的新特性用babel轉(zhuǎn)成瀏覽器支持的js語(yǔ)法,并生成文件持寄。
  3. 根據(jù)提供的html模板(主要做的是數(shù)據(jù)填充)生成對(duì)應(yīng)的html代碼和文件源梭。
  4. 啟動(dòng)一個(gè)服務(wù)器打開頁(yè)面,并監(jiān)聽上面三步和圖片等文件變化稍味,若有變化則刷新頁(yè)面废麻。
(二)發(fā)布階段的構(gòu)建
  1. ...前三個(gè)步驟和開發(fā)階段一樣,都是處理html模庐、js烛愧、css。
  2. 清空構(gòu)建目錄下的所有舊文件掂碱。
  3. 壓縮字體文件和圖片文件資源到構(gòu)建目錄下屑彻。
  4. 將public里不需要處理的資源,直接拷貝生成到構(gòu)建目錄下顶吮。
  5. 將前三步臨時(shí)目錄里的css社牲、js、html文件做壓縮混淆合并處理悴了,并生成對(duì)應(yīng)文件到構(gòu)建目錄下搏恤,將處理后的生成css和js文件插入到html里。

注意前三步的編譯都是在臨時(shí)目錄下湃交,最后壓縮混淆合并才在構(gòu)建目錄下熟空。之所以分兩個(gè)目錄,是因?yàn)樵诘?步對(duì)同個(gè)目錄邊讀邊寫會(huì)產(chǎn)生沖突搞莺。

二息罗、“開發(fā)階段構(gòu)建任務(wù)”具體實(shí)現(xiàn)

(一)準(zhǔn)備工作
  1. 請(qǐng)確保自己本地已有npm或yarn等包管理工具,本文用yarn做演示才沧。
  2. 下載該演示項(xiàng)目迈喉,或者自行vue-cli創(chuàng)建一個(gè)項(xiàng)目。
  3. 在該文件夾下空白處“按shift+鼠標(biāo)右鍵”温圆,選中“在此處打開命令行/powershell窗口”打開命令行窗口挨摸,或者自行通過(guò)命令窗口cd到該文件目錄下。
  4. 命令行輸入yarn init回車岁歉,自行填寫信息一路回車得运,最后生成package.json配置文件。
  5. 命令行輸入yarn add gulp --dev安裝gulp自動(dòng)構(gòu)建工具。
  6. 在演示項(xiàng)目下的gulpfile.js輸入下面代碼(gulpfile.js是gulp的運(yùn)行文件)熔掺。
const { src, dest } = require("gulp")

const extra = () => {
  // src是gulp中讀取文件的方法饱搏,dest是gulp中寫入文件到目標(biāo)位置的方法
  // 將public目錄下,以public為根目錄的所有文件拷貝到dist目錄下
  return src('public/**', {base: 'public'})
    .pipe(dest('dist'))
}

module.exports = {
  extra,
}
  1. 命令行輸入yarn gulp extra(extra是gulpfile.js對(duì)應(yīng)的函數(shù)任務(wù)名)置逻,如果能將public下文件拷貝到dist則證明成功推沸。
(二)css處理
  1. 由于需要依賴到node-sass國(guó)外源可能會(huì)出現(xiàn)安裝失敗的問題,建議先設(shè)置npm的安裝源為國(guó)內(nèi)的淘寶鏡像npm config set registry http://registry.npm.taobao.org诽偷。
  2. 命令行輸入yarn add gulp-sass sass --dev安裝gulp處理sass的插件。
  3. gulpfile.js文件輸入以下代碼疯坤,再執(zhí)行yarn gulp style成功生成temp對(duì)應(yīng)css文件則成功报慕。
const { src, dest } = require("gulp")
const sass = require('gulp-sass')

const style = () => {
  return src('src/assets/styles/*.scss', {base: 'src'})
    .pipe(sass({outputStyle: 'expanded'})) // _開頭的sass文件被認(rèn)為是依賴文件,不會(huì)被轉(zhuǎn)換压怠。expanded可以讓右括號(hào)換行而不是跟在分號(hào)后面
    .pipe(dest('temp'))
}

module.exports = {
  style,
}

由于后續(xù)需要加載比較多的gulp插件眠冈,需要頻繁寫require,此處采用一個(gè)gulp-load-plugins來(lái)自動(dòng)加載所需插件菌瘫,命令行輸入yarn add gulp-load-plugins --dev蜗顽,代碼改寫為如下

const { src, dest } = require("gulp")
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()

const style = () => {
  return src('src/assets/styles/*.scss', {base: 'src'})
    .pipe(plugins.sass({outputStyle: 'expanded'})) // _開頭的sass文件被認(rèn)為是依賴文件,不會(huì)被轉(zhuǎn)換雨让。expanded可以讓右括號(hào)換行而不是跟在分號(hào)后面
    .pipe(dest('temp'))
}

module.exports = {
  style,
}
(三)js處理
  1. 命令行輸入yarn add gulp-babel @babel/core @babel/preset-env --dev安裝gulp轉(zhuǎn)碼js的插件雇盖。
  2. gulpfile.js文件增加以下代碼,再執(zhí)行yarn gulp script成功生成temp對(duì)應(yīng)已轉(zhuǎn)碼好的js文件則成功栖忠。
const script = () => {
  return src('src/assets/scripts/*.js', {base: 'src'})
    .pipe(plugins.babel({presets: ['@babel/preset-env']}))
    .pipe(dest('temp'))
}

module.exports = {
  ...,
  script,
}
(四)html處理
  1. 命令行輸入yarn add gulp-swig --dev安裝gulp啟動(dòng)服務(wù)器并監(jiān)聽文件變化的插件崔挖。
  2. gulpfile.js文件增加以下代碼,再執(zhí)行yarn gulp page成功生成temp對(duì)應(yīng)已插入好數(shù)據(jù)的html文件則成功庵寞。
const data = {
  menu: [],
  pkg: require('./package.json'),
  date: new Date(),
}

const page = () => {
  return src('src/*.html', {base: 'src'})
    .pipe(plugins.swig({data, defaults: {cache: false}})) // 指定頁(yè)面中的插值data狸相,根據(jù)模板生成html。記得忽略緩存捐川,否則可能更新失敗
    .pipe(dest('temp'))
    .pipe(bs.reload({stream: true}))
}

module.exports = {
  ...,
  page,
}
(五)服務(wù)器上啟動(dòng)頁(yè)面并監(jiān)聽變化
  1. 命令行輸入yarn add browser-sync --dev安裝gulp對(duì)頁(yè)面模板進(jìn)行編譯的插件脓鹃。
  2. gulpfile.js文件增加以下代碼,再執(zhí)行yarn gulp serve古沥,成功在瀏覽器啟動(dòng)頁(yè)面瘸右,并且修改sass/js/html時(shí)會(huì)同步刷新頁(yè)面變化則成功。
const { src, dest, watch } = require("gulp")
const browserSync = require('browser-sync') // 不是gulp插件所以要自己導(dǎo)入
const bs = browserSync.create() // 創(chuàng)建服務(wù)器

const serve = () => {
  // 由于bs.init只監(jiān)聽了temp下已經(jīng)編譯好文件的變化岩齿,但我們真正編輯是在src下的未處理文件尊浓,所以要先監(jiān)聽src文件變化觸發(fā)編譯到temp觸發(fā)bs監(jiān)聽
  watch('src/assets/styles/*.scss', style)
  watch('src/assets/scripts/*.js', script)
  watch('src/*.html', page)
  // 圖片等資源不在temp目錄下,監(jiān)聽到變化了要手動(dòng)調(diào)用bs.reload
  watch([
    'src/assets/images/**',
    'src/assets/fonts/**',
    'public/**',
  ], bs.reload)

  bs.init({
    notify: false, // 不提示刷新
    port: 2000,
    open: true, // 是否自動(dòng)打開瀏覽器
    files: 'temp/**', // 哪些文件需要監(jiān)聽修改
    server: { // 先根據(jù)routes配置去指定目錄找文件纯衍,找不到再根據(jù)baseDir配置去找
      routes: { // 遇到/node_modules路徑時(shí)去node_modules目錄下找文件
        '/node_modules': 'node_modules',
      },
      baseDir: ['temp', 'src', 'public'], // 需要尋找對(duì)應(yīng)文件時(shí)栋齿,可以先在temp目錄下找有沒有,沒有再找src再public
    },
  })
}

module.exports = {
  ...,
  serve,
}
(六)整合為開發(fā)階段構(gòu)建任務(wù)

此處通過(guò)gulp的兩個(gè)方法parallelseries來(lái)整合上面四步任務(wù)。parallel方法可以同時(shí)開始執(zhí)行任務(wù)瓦堵,series方法是按順序先后執(zhí)行任務(wù)基协。整合代碼如下,命令行yarn gulp develop即可運(yùn)行該任務(wù)菇用。

const compile = parallel(style, script, page) // 因?yàn)槿齻€(gè)任務(wù)互不影響所以用parallel
const develop = series(compile, serve) // 要先編譯才有temp目錄澜驮,才能監(jiān)聽變化,所以用series

module.exports = {
  compile,
  develop,
}

三惋鸥、“發(fā)布階段構(gòu)建任務(wù)”具體實(shí)現(xiàn)

(一)清空構(gòu)建目錄
  1. 命令行輸入yarn add del --dev安裝刪除文件的插件杂穷。
  2. gulpfile.js文件增加以下代碼,再執(zhí)行yarn gulp clean卦绣,成功刪除目錄下的指定文件則成功耐量。
const del = require('del')

const clean = () => {
  return del(['dist']) // del返回的是一個(gè)promise
}

module.exports = {
  clean,
}
(二)壓縮圖片和字體
  1. 命令行輸入yarn add gulp-imagemin --dev安裝壓縮圖片的插件。
  2. gulpfile.js文件增加以下代碼滤港,再執(zhí)行yarn gulp image font廊蜒,生成了對(duì)應(yīng)圖片并比原文件小則成功。
const image = () => {
  return src('src/assets/images/**', {base: 'src'}) // **任意文件
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}

const font = () => { // 字體也有svg可以用同樣壓縮
  return src('src/assets/fonts/**', {base: 'src'})
     .pipe(plugins.imagemin())
     .pipe(dest('dist'))
 }

module.exports = {
  image,
  font,
}
(三)拷貝public資源

這段在開頭準(zhǔn)備工作中其實(shí)已經(jīng)講過(guò)溅漾,直接復(fù)制代碼過(guò)來(lái)山叮,不再贅述。

const extra = () => {
  // src是gulp中讀取文件的方法添履,dest是gulp中寫入文件到目標(biāo)位置的方法
  // 將public目錄下屁倔,以public為根目錄的所有文件拷貝到dist目錄下
  return src('public/**', {base: 'public'})
    .pipe(dest('dist'))
}
(四)壓縮處理js/css/html,并將處理后的js/css插入html
  1. 命令行輸入yarn add gulp-useref --dev安裝處理引用關(guān)系的插件暮胧,可以將類似如下的特定注釋內(nèi)的引用文件打包合并到指定文件中汰现。(這段代碼表示把bootstrap.css和test.css兩個(gè)文件打包合并成assets/styles/目錄下一個(gè)vendor.css文件)
<!-- build:css assets/styles/vendor.css -->
<link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css">
<link rel="stylesheet" href="/node_modules/test/test.css">
<!-- endbuild -->
  1. 命令行輸入yarn add gulp-htmlmin gulp-uglify gulp-clean-css --dev安裝壓縮處理html/js/css的gulp插件,yarn add gulp-if --dev安裝用于判斷當(dāng)前文件類型并做對(duì)應(yīng)處理的gulp插件叔壤。
  2. gulpfile.js文件增加以下代碼瞎饲,再執(zhí)行yarn gulp useref,生成了對(duì)應(yīng)各壓縮文件并插入到html則成功炼绘。
const useref = () => {
   return src('temp/*.html', {base: 'temp'})
    .pipe(plugins.useref({searchPath: ['temp', '.']})) // 指定html里寫的引入文件去哪里找
    // 找到的html嗅战、js、css文件分別做不同的處理
    .pipe(plugins.if(/\.js$/, plugins.uglify()))
    .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
    .pipe(plugins.if(/\.html$/, plugins.htmlmin({
      collapseWhitespace: true,
      minifyCSS: true, // 對(duì)html里的css代碼做壓縮
      minifyJS: true,
    })))
    .pipe(dest('dist'))
 }

module.exports = {
  ...,
  useref,
}
(五)整合為發(fā)布階段構(gòu)建任務(wù)

由于useref執(zhí)行完一次之后俺亮,temp里的html已經(jīng)被壓縮驮捍,特定注釋被刪除,所以再次運(yùn)行useref任務(wù)無(wú)法達(dá)到想要的效果脚曾,所以必須先編譯compile生成注釋代碼东且,再執(zhí)行useref才有效。整合代碼如下本讥,命令行yarn gulp build即可運(yùn)行該任務(wù)珊泳。

// 先刪除舊目錄鲁冯,再執(zhí)行構(gòu)建任務(wù)生成對(duì)應(yīng)文件
const build = series(clean, parallel(series(compile, useref), image, font, extra))

module.exports = {
  compile,
  develop,
  build,
}

四、最終gulpfile.js代碼

const { src, dest, watch, parallel, series } = require("gulp")
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()
const browserSync = require('browser-sync') // 不是gulp插件(gulp-開頭)所以要自己導(dǎo)入
const bs = browserSync.create() // 創(chuàng)建服務(wù)器
const del = require('del')
const data = {
  menu: [],
  pkg: require('./package.json'),
  date: new Date(),
}

const style = () => {
  return src('src/assets/styles/*.scss', {base: 'src'})
    .pipe(plugins.sass({outputStyle: 'expanded'})) // _開頭的sass文件被認(rèn)為是依賴文件色查,不會(huì)被轉(zhuǎn)換薯演。expanded可以讓右括號(hào)換行而不是跟在分號(hào)后面
    .pipe(dest('temp'))
    // .pipe(bs.reload({stream: true})) // 如果bs初始化files項(xiàng)沒配置,也可以在watch到之后在任務(wù)里reload
}

const script = () => {
  return src('src/assets/scripts/*.js', {base: 'src'})
    .pipe(plugins.babel({presets: ['@babel/preset-env']}))
    .pipe(dest('temp'))
    // .pipe(bs.reload({stream: true}))
}

const page = () => {
  return src('src/*.html', {base: 'src'})
    .pipe(plugins.swig({data, defaults: {cache: false}})) // 指定頁(yè)面中的插值data秧了,根據(jù)模板生成html跨扮。記得忽略緩存,否則可能更新失敗
    .pipe(dest('temp'))
    // .pipe(bs.reload({stream: true}))
}

const serve = () => {
  // 由于bs.init只監(jiān)聽了temp下已經(jīng)編譯好文件的變化验毡,但我們真正編輯是在src下的未處理文件衡创,所以要先監(jiān)聽src文件變化觸發(fā)編譯到temp觸發(fā)bs監(jiān)聽
  watch('src/assets/styles/*.scss', style)
  watch('src/assets/scripts/*.js', script)
  watch('src/*.html', page)
  // 圖片等資源不在temp目錄下,監(jiān)聽到變化了要手動(dòng)調(diào)用bs.reload
  watch([
    'src/assets/images/**',
    'src/assets/fonts/**',
    'public/**',
  ], bs.reload)

  bs.init({
    notify: false, // 不提示刷新
    port: 2000,
    open: true, // 是否自動(dòng)打開瀏覽器
    files: 'temp/**', // 哪些文件需要監(jiān)聽修改
    server: { // 先根據(jù)routes配置去指定目錄找文件璃氢,找不到再根據(jù)baseDir配置去找
      routes: { // 遇到/node_modules路徑時(shí)去node_modules目錄下找文件
        '/node_modules': 'node_modules',
      },
      baseDir: ['temp', 'src', 'public'], // 需要尋找對(duì)應(yīng)文件時(shí),可以先在temp目錄下找有沒有录择,沒有再找src再public
    },
  })
}

const clean = () => {
  return del(['dist']) // del返回的是一個(gè)promise
}

const image = () => {
  return src('src/assets/images/**', {base: 'src'}) // **任意文件
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}

const font = () => { // 字體也有svg可以用同樣壓縮
  return src('src/assets/fonts/**', {base: 'src'})
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
 }

 const extra = () => {
   // src是gulp中讀取文件的方法拔莱,dest是gulp中寫入文件到目標(biāo)位置的方法
   // 將public目錄下菱皆,以public為根目錄的所有文件拷貝到dist目錄下
   return src('public/**', {base: 'public'})
     .pipe(dest('dist'))
 }

 const useref = () => {
   return src('temp/*.html', {base: 'temp'})
    .pipe(plugins.useref({searchPath: ['temp', '.']})) // 指定html里寫的引入文件去哪里找
    // 找到的html篷店、js、css文件分別做不同的處理
    .pipe(plugins.if(/\.js$/, plugins.uglify()))
    .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
    .pipe(plugins.if(/\.html$/, plugins.htmlmin({
      collapseWhitespace: true,
      minifyCSS: true, // 對(duì)html里的css代碼做壓縮
      minifyJS: true,
    })))
    .pipe(dest('dist'))
 }

const compile = parallel(style, script, page) // 因?yàn)槿齻€(gè)任務(wù)互不影響所以用parallel
const develop = series(compile, serve) // 要先編譯才有temp目錄臭家,才能監(jiān)聽變化疲陕,所以用series
// 先刪除舊目錄,再執(zhí)行構(gòu)建任務(wù)生成對(duì)應(yīng)文件
const build = series(clean, parallel(series(compile, useref), image, font, extra))

module.exports = {
  compile,
  develop,
  build,
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末钉赁,一起剝皮案震驚了整個(gè)濱河市蹄殃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌你踩,老刑警劉巖诅岩,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件讳苦,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡按厘,警方通過(guò)查閱死者的電腦和手機(jī)医吊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)逮京,“玉大人卿堂,你說(shuō)我怎么就攤上這事±撩蓿” “怎么了草描?”我有些...
    開封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)策严。 經(jīng)常有香客問我穗慕,道長(zhǎng),這世上最難降的妖魔是什么妻导? 我笑而不...
    開封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任逛绵,我火速辦了婚禮,結(jié)果婚禮上倔韭,老公的妹妹穿的比我還像新娘术浪。我一直安慰自己,他們只是感情好寿酌,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開白布胰苏。 她就那樣靜靜地躺著迹辐,像睡著了一般配阵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上怎炊,一...
    開封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天秧荆,我揣著相機(jī)與錄音倔毙,去河邊找鬼。 笑死乙濒,一個(gè)胖子當(dāng)著我的面吹牛陕赃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播琉兜,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼凯正,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了豌蟋?” 一聲冷哼從身側(cè)響起廊散,我...
    開封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎梧疲,沒想到半個(gè)月后允睹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體运准,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年缭受,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了胁澳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡米者,死狀恐怖韭畸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蔓搞,我是刑警寧澤胰丁,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站喂分,受9級(jí)特大地震影響锦庸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蒲祈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一甘萧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧梆掸,春花似錦扬卷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)嬉挡。三九已至钝鸽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間庞钢,已是汗流浹背拔恰。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留基括,地道東北人颜懊。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像风皿,于是被迫代替她去往敵國(guó)和親河爹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容