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、部署的整个流程。

相关文章
相关标签/搜索