前言
在上篇《【vue-cli3升級】老專案提速50%(二)》文中,評論區好幾個人對文中task任務以及shell打包推送遠端倉庫表示感興趣,希望我多描述些內容…基於此原因、在此基礎上,談一談我在SPA專案打包 =>
部署的工程化內容
PS:只作為本人工作的分享,不作為任何形式的指南、教程、最佳實踐等,也並非手把手系列
專案環境描述
- SPA專案(Vue-cli3)
- Gitlab程式碼倉庫
- node 10.8.0
- npm 6.5.0
- Nginx伺服器
- Linux系統
- Jenkins持續整合部署工具
說下上篇文中Task.js
、run.sh
以下內容請結合《【vue-cli3升級】老專案提速50%(一)》、《【vue-cli3升級】老專案提速50%(二)》閱讀
為什麼這麼做?
結合實際場景羅列兩個吧…
- 為了隨時釋出前端專案,不用等到晚上加班釋出…
- 曾經,在釋出過程中,老闆正在瀏覽…然後白屏了…所以為了釋出時線上使用者無感知
整體流程(畫圖真墨跡啊)
-
執行
run.sh
,以beta
環境為例,專案根目錄執行./run.sh beta
-
在
run.sh
中,初始化beta環境的遠端倉庫,拉取程式碼到本地.deploy/beta
目錄,將.deploy/beta
目錄中的檔案複製到本地dist
目錄 -
在
run.sh
中,執行構建:npm run build_beta
-
在
vue.config.js
中,建立版本號lastVersion
,將版本號lastVersion
加入到css
、js
資原始檔名中(我是加在最前面的,位置隨意,和task.js
中的正則對應) -
在
vue.config.js
中,注入task.js
,執行任務const task = require('./task')task.run(lastVersion)複製程式碼
-
在
task.js
中,將版本號寫入history.js
,判斷是否超出最大值(最大5個歷史版本),超出則執行rmFiles()
,刪除本地dist
目錄中最老的版本資源 -
複製本地
dist
目錄檔案到.deploy/beta
中,提交.deploy/beta
檔案到遠端倉庫
附圖:瞭解下.deploy/beta目錄檔案,history.js檔案,遠端Gitlab倉庫程式碼
【Task.js】
前提:打包時不清除dist檔案目錄,以增量的形式打包。
vue-cli3下可參考《【vue-cli3升級】老專案提速50%(二)》
vue-cli2下在 /build/build.js
中找到以下程式碼註釋掉
// rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err =>
{// if (err) throw err//
})複製程式碼
何時執行?build構建時
作用:利用nodeJs的fs模組操作history.js,儲存最多5個版本,超過5個在本地dist目錄中刪除匹配最老版本的相關資源
程式碼(基本上都加上註釋描述了)
const fs = require('fs') // node fs模組,操作檔案const path = require('path') // node path模組,操作路徑const endOfLine = require('os').EOL // node os模組,不同作業系統的行尾符module.exports = {
maxHistoryNum: 5, // 控制儲存版本最大值 historyFile: path.resolve(__dirname, './dist/history.js'), // 本地dist目錄中的history.js staticDir: path.resolve(__dirname, './dist/'), // 本地dist目錄 // history.js不存在,建立 creataHistoryIfNotExist () {
if (!fs.existsSync(this.historyFile)) {
this.storeHistory([], 'a+')
}
}, // @done 將資料寫到 history.js storeHistory (list, mode) {
let historyFile = this.historyFile let outJson = 'module.exports = [' + endOfLine let listLen = list.length if (list &
&
listLen >
0) {
list.forEach((item, index) =>
{
if (index === listLen - 1) {
outJson += ` ${item
}${endOfLine
}`
} else {
outJson += ` ${item
},${endOfLine
}`
}
})
} outJson += ']' + endOfLine // 以 a+ 的falg標誌在history.js寫入和追加內容 fs.writeFileSync(historyFile, outJson, {
flag: mode
})
}, // 遞迴刪除目錄中的檔案 (構建完成時版本>
最大值時執行) rmFiles (dirPath, regexp) {
let files try {
files = fs.readdirSync(dirPath)
} catch (e) {
return
} if (regexp &
&
files &
&
files.length >
0) {
for (let i = 0;
i <
files.length;
i++) {
let filename = files[i] let filePath = dirPath + '/' + files[i] if (fs.statSync(filePath).isFile() &
&
regexp.test(filename)) {
console.log('刪除過期的歷史版本->
(' + regexp + '):' + filename) fs.unlinkSync(filePath)
} else {
this.rmFiles(filePath, regexp)
}
}
}
}, // @done 更新history.js內容 cleanOldVersionFilesIfNeed (version) {
let staticDir = this.staticDir let maxHistoryNum = this.maxHistoryNum let history = [] try {
history = require(this.historyFile)
} catch (e) {
console.log(e)
} // 加入最新的版本,老的的版本刪除 history.push(version) // 如果歷史版本數超過限制,則刪除老的歷史版本 let len = history.length if (len >
maxHistoryNum) {
let oldVersions = history.slice(0, len - maxHistoryNum) for (let i = 0;
i <
oldVersions.length;
i++) {
let ver = oldVersions[i] let reg = new RegExp(ver) this.rmFiles(staticDir, reg)
} // 更新history檔案 let newVersions = history.slice(len - maxHistoryNum) this.storeHistory(newVersions)
} else {
// 寫入history檔案 this.storeHistory(history)
}
}, // 入口 run (version) {
this.creataHistoryIfNotExist() this.cleanOldVersionFilesIfNeed(version)
}
}複製程式碼
【run.sh
】
我們簡單的分為beta(測試環境)和pro(線上環境)
作用:一鍵打包原生程式碼,提交上傳至遠端程式碼倉庫
先看程式碼:
#!/bin/bash# 初始化上下文。有引數的initContext(){
# dist目錄 source_dir=dist # 獲取引數,beta環境和pro環境 if [ $# -gt 0 ] &
&
[ $1 = 'beta' ];
then # beta環境遠端倉庫地址, git_url=git@beta/example.git # 本地根目錄存放打包程式碼 dest=".deploy/beta" # npm 的指令碼名,對應package.json定義的script node_script=build_beta else # pro環境遠端倉庫地址 git_url=git@pro/example.git # 本地根目錄 dest=".deploy/pro" # npm 的指令碼名,對應package.json定義的script node_script=build_pro fi
}# 初始化git目錄,pull最新程式碼init(){
echo +++init start;
if [ ! -d $dest ];
then git clone $git_url $dest fi # 記錄現在的目錄位置,pwd獲取本地路徑 cur=`pwd` # 進入git目錄 cd $dest # git checkout . git add . git stash # reset為線上最新版本,要先pull一下再reset。 git pull origin master git reset --hard origin/master # 然後再pull一下 git pull origin master # 回到原來的目錄 cd $cur echo ---init end;
}# 重置dist目錄resetDist(){
echo +++resetDist start rsync -a --delete --exclude='.git' $dest/. ./dist echo ---resetDist end
}# 構建build(){
echo +++build start npm run $node_script echo ---build end
}# 檢查是否成功checkBuild(){
if [[ ! -f $source_dir/index.html || ! -d $source_dir/static ]];
then echo error else echo ok fi
}# 複製程式碼到$dest目錄cpCode(){
echo +++cpCode start # 複製程式碼,所有檔案包含隱藏檔案 rsync -r --delete --exclude='.git' $source_dir/. $dest echo ---cpCode end
}# 提交到遠端git倉庫commit(){
echo +++commit start # 記錄現在的目錄位置,最後要回來的 cur=`pwd` # 進入git目錄 cd $dest # 提交的字串 commit_str="commited in `date '+%Y-%m-%d_%H:%M:%S'`" git add . git commit -am "${commit_str
}" git push origin master # 回到原來的目錄 cd $cur echo ---commit end
}# 顯示幫助資訊help(){
# 微信h5版本 echo ----微信h5版本-------- echo ./run.sh build "#"構建程式碼 echo ./run.sh init "#"初始化git倉庫 echo ./run.sh commit "#"提交到git echo ./run.sh "#"執行全部任務 echo ./run.sh hello "#"hello echo ./run.sh test "#"test echo ./run.sh beta "#"一鍵構建和提交beta版本 # app內嵌版本 echo ----app內嵌版本-------- echo ./run.sh app "#"一鍵構建和提交app版本 echo ----幫助資訊-------- echo ./run.sh help "#"幫助
}# 測試用的test(){
echo "a test empty task"
}# 入口if [[ $# -lt 1 || $1 = 'app' || $1 = 'beta' ]];
then # 無引數則打pro包,否則打相應型別的包 if [ $# -lt 1 ];
then type=pro else type=$1 fi echo ===\>
準備構建${type
}版 initContext $type &
&
init &
&
resetDist # 構建程式碼 buildRes=$(build) # 檢查構建結果 echo -e "$buildRes" if [[ $buildRes =~ "ERROR" ]];
then echo "$(tput setaf 1)xxx\>
build error,task abort$(tput sgr0)" else # 程式碼構建成功才繼續。 checkRes=$(checkBuild) if [ $checkRes == "ok" ];
then cpCode &
&
commit echo "$(tput setaf 2)===\>
task complete$(tput sgr0)" else echo "$(tput setaf 1)xxx\>
build error,task abort$(tput sgr0)" fi fielif [ $1 ];
then # 引數不是包型別的,當中函式處理 echo ===\>
準備執行${1
}函式 initContext beta func=$1 $func echo ===\>
task completefi複製程式碼
上篇文章評論區有人問到 rsync
,文中用來同步本地硬碟中的不同目錄。可以看下這篇 教程
Linux
系統已經整合了 rsync
命令,windows
的使用者需要自行安裝(教程),不然會和這位小夥伴一樣遇到 command not found
,本人windows已經3年沒碰了…
以上,是對上篇文章中對打包這塊內容的講解,接下來說下部署
部署工具我接觸過walle、Jenkins
walle的話就是提交對應版本進行釋出,持續整合部署方案的話就是Jenkins了。Jenkins文件
為什麼要做自動化部署?結合自身實際場景描述下:
- 後端有微服務,前端自然不能落下。各個大模組(業務線)都是獨立的工程,比如商城、教育、社群等等。當開發迭代一個版本時,可能就會涉及到A、B、C、D等幾個專案,部署的痛苦就來了…我特麼的一個個打包,然後再一個個的部署…這個過程可能半小時就過去了…效率低下又low,實力不允許這麼做
- 公司有區域網限制,如果在家手動部署,還需要連線VPN,內心是拒絕的
- 我只想安心敲程式碼…別特麼的動不動讓我部署下,打斷老子的思路…
當然,使用Jenkins持續整合方案,該裝的環境還是一個都不能少的…這個也結合自身實際情況自行研究吧
本文也是描述下這個概念,各自實際情況各異,扔需自行研究
安裝什麼的自行文件吧(安裝,外掛,配置等),從新建任務開始
-
進入Jenkins系統,左側新建任務
-
輸入名稱,選擇構建一個自由風格的軟體專案,確定
-
填寫任務描述、原始碼倉庫地址,分支預設master
-
配置觸發器,Gitlab提交程式碼觸發自動構建任務
-
如果需要構建時執行指令碼,比如
npm inpm run build複製程式碼
-
儲存
很簡單的幾個配置步驟就能完成自動化部署任務,簡單高效。自行研究嘗試玩玩吧下篇我再出個Jenkins+Github持續整合的詳細教程好了
結尾
通過這樣的方式打包部署個人認為是適合絕大多數中小公司的,哈哈。我本來考慮的是將css、js部署在cdn伺服器上,index.html單獨部署的,考慮到暫時還沒到需要這麼幹的程度,就不折騰伺服器了,思路大同小異。
在寫這篇文章的時候,正好看到大公司裡怎樣開發和部署前端程式碼?,大家可以瞭解下他們是怎麼設計的。我這中小公司,感覺文中的思路方案也差不多OK的啦
提前寫了,本來說是週末寫的,正好今天不忙,花2小時簡單寫下