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

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

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

項目構建

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

通常,默認的構建模式無法滿足項目研發需求。一個項目至少需要包含

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

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

首先,環境創建

在項目根目錄下創建 .env.deploy 文件,添加內容如下:

NODE_ENV=production
DEPLOY=online

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

其次,配置文件

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解析,並獲取到阿里雲的 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 [email protected] "./deploy_cms.sh"
ssh [email protected] "./deploy_cms.sh"

因爲線上服務通常是集羣模式,而 webpack在不同服務器執行build,會產生不同的哈希值版本號,會導致遠程資源無法獲取到。所以我們需要在持續集成部署的服務器上做build操作,生成dist路徑,上傳到git和cdn。最後再到集羣的每個服務器上拉取靜態文件即可。


補充:

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

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章