Vue項目構建持續集成阿里雲CDN

CDN加速是Web應用性能優化和用戶體驗提高的相當重要的一環,當一個項目構建部署時,就須要考慮到如何高效的去完成相關資源的CDN部署。css

本文以一個基於 vue-cli3 構建的項目實例,來簡單講解如何配合Teamcity,自動進行阿里雲CDN資源部署和持續集成。html

項目構建

vue-cli3 默認支持將項目以 testdevelopmentproduction 三種模式構建,其中 production 模式將在 build 後生成 dist目錄。咱們在項目路徑下插入 .env.[mode] 格式的文件就能夠實現自定義模式。vue

一般,默認的構建模式沒法知足項目研發需求。一個項目至少須要包含node

  1. 本地調試 - 即開發過程當中的 development 模式,不生成 dist 靜態目錄,使用 vue-dev-server運行項目;
  2. 測試環境 - 即基本的集成測試,須要文件靜態化,部署到測試環境;
  3. 線上環境 - 即用戶環境,也須要文件靜態化,並作CDN加速等性能優化措施;

按照這個模型,咱們須要自定義一個 deploy 模式,來實現和普通 production打包後,資源引入路徑的區別。webpack

首先,環境建立git

在項目根目錄下建立 .env.deploy 文件,添加內容以下:web

NODE_ENV=production
DEPLOY=online

NODE_ENV的設置表明webpack構建時使用production模式,即會生成 dist靜態目錄。
DEPLOY的設置,是一個咱們定義的變量,用於在配置中區分deployproduction模式。vue-cli

其次,配置文件npm

vue.config.js 中,配置 BASE_URLjson

// 根據自定義的變量來進行內容設置
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解析,並獲取到阿里雲的 accessKeyIdaccessKeySecretRegionBucketName等信息,而後選擇一種語言,寫好上傳腳本。

這裏咱們以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 root@10.0.0.1 "./deploy_cms.sh"
ssh root@10.0.0.2 "./deploy_cms.sh"

由於線上服務一般是集羣模式,而 webpack在不一樣服務器執行build,會產生不一樣的哈希值版本號,會致使遠程資源沒法獲取到。因此咱們須要在持續集成部署的服務器上作build操做,生成dist路徑,上傳到git和cdn。最後再到集羣的每一個服務器上拉取靜態文件便可。


補充:

  1. 在同一臺服務器上,只要文件徹底不變,咱們使用vue-cli3構建生成的最終文件的哈希值版本號就不會產生改變。所以,對於用戶來講當咱們更新版本時,並不會對用戶形成全部緩存文件失效的性能和體驗影響。
  2. 在阿里雲的CDN上,是使用協商緩存的ETag來進行文件資源緩存,所以重名新文件覆蓋舊文件時,如文件內容徹底一致,Etag也會保持一致,對用戶來說也沒必要擔憂緩存問題;如文件發生變動,用戶協商緩存也將沒法命中,就會取新的資源文件。
  3. 有些方法是把靜態資源的請求發到Nginx,而後再轉發到CDN地址。筆者認爲,這樣會形成全部資源須要重定向、而且在Nginx上沒法設置緩存信息,性能上不如本文介紹的直接構建生成CDN地址的HTML文件的方法。

經過這套操做,最終咱們實現了在TeamCity上,一鍵執行打包、上傳CDN、部署的整個流程。

相關文章
相關標籤/搜索