Node.js构建vue工程发布到OSS

更新时间:
复制 MD 格式

本文会介绍如何在Flow中构建vue工程,并将构建产物发布到OSS,然后在应用页面中引用OSS上的静态资源地址。

方案概览

1

开通一个OSS的bucket,假设其地址为:static-serving.oss-cn-beijing.aliyuncs.com

假设构建后的静态资源包含两个文件: 1.1/css/index.css, 1.1/js/index.js。则在上传构建产物之后,可以通过http://static-serving.oss-cn-beijing.aliyuncs.com/1.1/css/index.js 和 http://static-serving.oss-cn-beijing.aliyuncs.com/1.1/js/index.js 来访问。因此把这两个地址写入到应用网页中即可访问。

其中URL中的1.1是版本号。版本号的一般使用方式:

  1. 在测试过程中可以进行覆盖发布,也就是对URL不变,更新静态资源文件内容。使用这种方式,很有可能会由于客户端的缓存,导致静态资源没有自动更新。不过这个对于测试环境来讲不算是一个大问题,这个方式可以避免版本号的快速上涨。

  2. 在正式发布时应该升级版本号,避免对线上正在使用的版本号进行覆盖,以避免预期外的线上变更。

  3. 测试环境的版本号和生产环境的版本号应该是两个序列,以避免混乱。常见的方式有两种

    1. 测试环境和生产环境使用不同的oss bucket,阿里巴巴是类似的做法

    2. 使用不同的版本序列。测试环境加上test后缀,比如0.0.1-test,生产环境使用数字,比如0.0.1。本文后续使用这个方式。

版本号在package.json中进行管理,在Flow的流水线中读取package.json中的version字段,然后根据测试环境和生产环境的版本号规则上传构建产物到指定的OSS路径上。

流水线设计

了解基本原理之后,可以开始配置流水线。

流水线的基本组成

  1. 进行代码扫描,使用云效内置的“JavaScript 代码扫描”步骤

  2. 进行单元测试,使用云效内置的“Node.js 构建”步骤

  3. 进行测试环境发布,使用云效内置的“Node.js 构建”步骤和“OSS 上传”步骤

  4. 进行生产环境发布,和第三步基本相同,由于不希望生产环境的版本号被覆盖,因此需要先检查指定版本是否已经存在,如果存在了,则直接报错退出。

流水线包含 3 个阶段:构建阶段(含 eslint 和 unittest 两个步骤)、构建上传阶段(Vue 构建并上传测试版本)、构建阶段(Vue 构建并上传正式版本,需手动触发)。

代码库

本文使用的示例代码库:https://atomgit.com/flow-example/vue,在这个代码库中植入了一个eslint的问题和一个失败的单元测试。

你可以clone该代码库,并push到codeup上,然后继续下面的配置。

eslint

选择“JavaScript 代码扫描”,勾选“是否使用本地ESLint 配置”,以便使用代码库中.eslintrc.js中的规则。

添加一个红线配置,问题数小于等于0,也就是要求不能有问题。

unittest

配置 Node 版本为 14.8。

选择“Node.js 构建”步骤,使用和本地相同的单元测试命令:cnpm install && cnpm run test:unit

构建并发布到测试环境

配置 Node 版本为 14.8,执行以下命令。

在这个任务中,包含了两个步骤。

“Node.js 构建” 步骤

cnpm install && npm run build
version=`cat package.json | jq -r '.version'`
echo "USER_STATIC_VERSION=${version}-test" > .env

第一行进行构建,产出物在dist目录中。

第二行和第三行从package.json中读取version字段,并添加-test后缀,表示这是一个测试环境的版本,并写入到.env文件中,供后续的步骤使用。

示例中地域选择华北2(北京),Bucket 名称为 vue-static-serving,源文件目录为 dist。

接下来上传到OSS,选择OSS 上传步骤,然后进行服务授权的配置,选择相应的bucket和源文件目录。注意这里的Bucket目录使用的是上一步写入.env的USER_STATIC_VERSION。

构建并发布到生产环境

该步骤与“构建并发布到测试环境”类似。有两点差别:

  1. 版本号不再加-test的后缀。

  2. 覆盖已经发布的版本。

  3. 该任务左上角有小手标记,表示该任务是需要手动点击执行,避免每次流水线运行都更新线上。

下面介绍具体如何配置。

该任务包含提取版本号、OSS 下载、版本存在则失败、Node.js 构建、OSS 上传 5 个步骤。首先是“执行命令”步骤

首先提取版本号,并写入.env供后续流程使用

version=`cat package.json | jq -r '.version'`
echo "USER_STATIC_VERSION=${version}" > .env

下面分别是“OSS下载”步骤,和“执行命令”步骤

OSS 下载步骤中,Bucket 源文件路径配置为 ${USER_STATIC_VERSION}/,目标路径为 dest。

尝试下载这个版本下面的文件,并判断下载的目录中是否为空,如果为空则说明该版本不存在,可以发布,如果不为空,则说明该版本已经失败,直接出错退出。注意,这里的“Bucket源文件路径”需要加上“/”的后缀,否则会匹配上类似“0.0.1-test”之类的路径。

 ls -l dest
 if [ -n "$(ls -A dest)" ]; then
   echo version ${USER_STATIC_VERSION} already exists
   exit 1
 fi

后面的两步就和“构建并发布到测试环境”的一样了,不再赘述。

运行效果

初次运行,由于代码中存在失败的用例和未通过的eslint检查,会失败

流水线运行后,eslint 步骤检测到 2 个阻塞问题,unittest 步骤运行失败,流水线整体状态为失败。

点击日志和测试报告可以看到更多信息

ESLint 扫描报告显示 src/main.ts 文件中存在 2 个阻塞问题,均为 if(true){} 空语句块。

  HelloWorld.vue
    1) renders props.msg when passed

  0 passing
  1 failing

  1) HelloWorld.vue
       renders props.msg when passed:
     AssertionError: expected '...' to not include '...'

修改代码,修复问题

// src/main.ts
- if(true){}
// tests/unit/example.spec.ts
- expect(wrapper.text()).not.to.include(msg)
+ expect(wrapper.text()).to.include(msg)

再次运行,此时package.json中的version为0.1.0。期望能够发布到测试和生产环境。

流水线第二次运行,构建阶段(eslint 和 unittest)及构建上传阶段(测试版本)均成功,正式版本阶段显示为等待中,需手动触发。

手动触发正式版本构建后,所有阶段运行成功,流水线整体状态为成功。

在 OSS Bucket 中可以看到 0.1.0-test 目录下的构建产物(css/、js/、img/、index.html 等)。0.1.0 目录下同样包含完整的生产版本构建产物。

重复发布该版本,测试可以正常发布,但正式会失败。

修改package.json里的version之后再次发布,可以成功的发布测试和线上版本

// package.json
- "version": "0.1.0"
+ "version": "0.1.1"

流水线再次运行成功,所有阶段均通过,版本 0.1.1 的测试和正式版本均成功发布。

OSS Bucket 中 0.1.1-test 目录下包含 css/、img/、js/ 文件夹及 index.html 等构建产物。0.1.1 目录下同样包含完整的生产版本构建产物。

加速访问

OSS的访问速度与地域有关,如果希望通过CDN来加速OSS文件的访问,可以参看这里:绑定CDN加速域名