Vue專案構建持續整合阿里雲CDN
CDN加速是Web應用效能優化和使用者體驗提升的至關重要的一環,當一個專案構建部署時,就需要考慮到如何高效的去完成相關資源的CDN部署。
本文以一個基於vue-cli3
構建的專案例項,來簡單講解如何配合Teamcity,自動進行阿里雲CDN資源部署和持續整合。
專案構建
vue-cli3 預設支援將專案以test
、development
、production
三種模式構建,其中production
模式將在 build 後生成dist
目錄。我們在專案路徑下插入.env.[mode]
格式的檔案就可以實現自定義模式。
通常,預設的構建模式無法滿足專案研發需求。一個專案至少需要包含
development
按照這個模型,我們需要自定義一個deploy
模式,來實現和普通production
打包後,資源引入路徑的區別。
首先,環境建立
在專案根目錄下建立.env.deploy
檔案,新增內容如下:
NODE_ENV=production DEPLOY=online
NODE_ENV
的設定代表webpack構建時使用production
模式,即會生成dist
靜態目錄。
DEPLOY
的設定,是一個我們定義的變數,用於在配置中區分deploy
和production
模式。
其次,配置檔案
在vue.config.js
中,配置BASE_URL
// 根據自定義的變數來進行內容設定 let BASE_URL = '/' switch(process.env.DEPLOY) { case 'online': BASE_URL = 'http://web-cdn.xxx.com/' break default: BASE_URL = '/' } module.exports = { publicPath: BASE_URL, .... }
該配置會使得當程式使用deploy
模式執行時,打包的資源根路徑為我們的CDN地址。
最後,構建命令
在package.json
中,配置使用deploy
模式的打包命令
"scripts": { "build": "vue-cli-service build", "deploy": "vue-cli-service build --mode deploy", ... }
當用戶執行npm run build
時,會生成以/
為資源路徑的檔案;
當用戶執行npm run deploy
時,生成index.html
中的資源路徑就變成了我們配置的CDN路徑。
<!DOCTYPE html> <html> <head> <meta charset=utf-8> <meta http-equiv=X-UA-Compatible content="IE=edge"> <meta name=viewport content="width=device-width,initial-scale=1"> <link rel=icon href=http://web-cdn.xxx.com/favicon.ico> <title>Demo</title> <link href=http://web-cdn.xxx.com/css/chunk-0fabbc4c.08fa0fd2.css rel=prefetch> <link href=http://web-cdn.xxx.com/css/chunk-1025f268.0dc416de.css rel=prefetch> <link href=http://web-cdn.xxx.com/js/app.84dcc9e6.js rel=preload as=script> </head> <body> <div id=app></div> <script src=http://web-cdn.xxx.com/js/chunk-vendors.614ecc0c.js></script> <script src=http://web-cdn.xxx.com/js/app.84dcc9e6.js></script> </body> </html>
阿里雲CDN配置和上傳
接下來,我們要做的就是配置一個CDN,並能夠把這些資源傳上去。
首先,在阿里雲上配置CDN,做好域名CNAME解析,並獲取到阿里雲的accessKeyId
、accessKeySecret
、Region
、BucketName
等資訊,然後選擇一種語言,寫好上傳指令碼。
這裡我們以Node指令碼為例:
// oss-deploy.js let OSS = require('ali-oss') let fs = require('fs') let client = new OSS({ region: 'oss-cn-hangzhou', accessKeyId: 'xxx', accessKeySecret: 'xxx', bucket: 'xxx' }) // 使用async+await方法,實現同步化,方便在失敗後重試處理 async function put(fileName) { try { let result = await client.put(fileName, '../dist/' + fileName) console.log('File Upload Success: ', fileName) } catch (e) { console.log('File Upload Failed: ', fileName) // 這裡省略異常/失敗的重試 } } // 讀取打包後的 dist 路徑,按照原資料夾結構,進行上傳 let readFileList = (path, filesList) => { let files = fs.readdirSync(path) files.forEach(itm => { if (itm) { let stat = fs.statSync(path + itm) if (stat.isDirectory()) { readFileList(path + itm + '/', filesList) } else { filesList.push(path + itm) } } }) return filesList } let dist = readFileList('../dist/', []) // 遞迴執行檔案上傳操作 let i = 0, l = dist.length let uploadAsset = () => { if (i < l) { let name = dist[i].split('../dist/')[1] put(name) i++ uploadAsset() } } uploadAsset()
執行
npm install --save-dev ali-oss node oss-deploy.js
即可看到檔案已經被上傳到了CDN路徑下。
持續整合
上面的兩個模組,已經實現了基本的CDN部署。但我們在專案開發的時候,肯定不希望每次 build完,都去自己執行上傳CDN,再去伺服器上部署。
這裡我們再把TeamCity
上實現自動build、一鍵上線的流程簡單闡述。
TeamCity上的執行指令碼如下:
cd /apps/kaleido-cms/ git pull -f origin master npm install npm run deploy git add dist/* git commit -m "Deploy" git push origin master cd /apps/kaleido-cms/deploy node oss-deploy.js ssh [email protected] "./deploy_cms.sh" ssh [email protected] "./deploy_cms.sh"
因為線上服務通常是叢集模式,而 webpack在不同伺服器執行build,會產生不同的雜湊值版本號,會導致遠端資源無法獲取到。所以我們需要在持續整合部署的伺服器上做build操作,生成dist路徑,上傳到git和cdn。最後再到叢集的每個伺服器上拉取靜態檔案即可。
通過這套操作,最終我們實現了在TeamCity上,一鍵執行打包、上傳CDN、部署的整個流程。