使用Github Actions自动编译、打包、发布Vue项目,并使用JSDelivr作为CDN加速
本文最后更新于 1524 天前,其中的信息可能已经有所发展或是发生改变。

内容纲要

去年5月CUPOJ前端使用Vue进行了重构,因此使用Vue-CLI打包变成了每次发布新的变更必不可少的一个任务。

由于前端项目本身代码量较大,逻辑也比较复杂,打包起来对性能要求相对较高。平时都是在学校服务器直接打包后复制dist目录下的文件到指定文件夹来部署。

每次都执行同样的代码比较痛苦,便写了一个简单的脚本,把整个过程变成了一键部署。若是能够把整个过程CI化,会大大提升平时发布的效率。

于是学习了Lucien的Github Actions以及部署CDN的方式,进行了一下改造。

目标

  • 使用CI自动编译并发布Release版本
  • 自动部署代码到生产环境
  • CDN加速静态资源

构建Github Actions工作流

根据给出的文档,Github Actions会自动扫描repo下.github/workflows目录下的*.yml文件,载入Actions workflow中。


由于许多的流程是共通的,因此官方把这些共通的流程发布成为一个模块,称作action。每个用户都可以使用别人发布的action,也可以自己发布action。这一点我不在这里展开,这里重点将如何利用它们进行发布。

参考官方文档给出的语法,我们总结出一个大致的yml格式。

对于一个workflow,我们要先对它命名:

name: Publish releases to CDN repository

给出workflow的触发条件:

on:
  push:
    branches:
      - typescript
    paths:
      - 'package.json'
      - 'src/**'
      - 'public/**'

需要完成的工作:
其中publishjobs的名称,你可以随意命名。一个jobs可以有多个执行的job
job存在if语句,则条件成立时执行job
if语句的逻辑请参考官方文档。

stepworkflow执行的步骤。 按编写顺序执行。

这里简单介绍一下step包含的内容:
一个step可以是引用别人的action,如下面的Checkout code
根据action要求填入的with属性,输入需要填写的内容。

对于每个step,给出对应的name为该操作命名。

可以用if条件语句决定step是否执行。
该语句相关语法请参考官方文档。

run语法可以执行一至多行命令。

run: # 单行命令
run: |
    # 多
    # 行
    # 命
    # 令

env: 为每个step加入环境变量。

由于我们需要自动编译并发布,因此我需要建立一个提供Node.js的发布环境,并从repo拉取代码,安装依赖并编译后,发布到目标的仓库。

为了能够发布到目标的仓库,我们需要生成token,用于push操作验证身份。

前往https://github.com/settings/tokens可生成token。

由于token需要被保密,我们在Github中你需要执行Action的仓库点击Settings,在左边的菜单找到Secrets填入你刚才生成的token, 命名为GITHUB_ACTIONS_TOKEN。你也可以命名为其他的变量名。后面会在文件中使用。

准备工作就绪以后,在.github/workflows目录创建一个yml文件,编写action

name: Publish releases to CDN repository

on:
  push:
    branches:
      - typescript
    paths:
      - 'package.json'
      - 'src/**'
      - 'public/**'

jobs:
  publish:
    if: github.repository == 'ryanlee2014/CUP-Online-Judge-NG-FrontEnd'
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [12.x]

    steps:
      - uses: actions/checkout@v2
        name: Checkout code
        with:
          persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token
          fetch-depth: 0 # otherwise, you will failed to push refs to dest repo

      - name: Build env
        run: |
          echo "::set-env name=NEED_BUILD::$(cat NEED_BUILD)"

      - name: Use Node.js environment
        if: env.NEED_BUILD == 'true'
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}

      - name: Build distribution if needed
        if: env.NEED_BUILD == 'true'
        run: |
          npm i
          npm run modern

      - name: Update dist folder to current repository
        if: env.NEED_BUILD == 'true'
        run: |
          git config --local user.email "gxlhybh@gmail.com"
          git config --local user.name "Ryan Lee"
          git add dist
          git commit -m "Auto commit version $(cat public/VERSION)"
          git push -f https://ryanlee2014:$GITHUB_TOKEN@github.com/ryanlee2014/CUP-Online-Judge-NG-FrontEnd.git typescript
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_ACTIONS_TOKEN }}


      - uses: actions/checkout@v2
        name: Checkout CDN Repository
        with:
          repository: ryanlee2014/CUP-Online-Judge-CDN
          path: cdn
          persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token
          fetch-depth: 0 # otherwise, you will failed to push refs to dest repo

      - name: Move file to another repository
        run: cp -r dist/* cdn/


      - name: Commit files and push
        run: |
          cd cdn
          git config --local user.email "gxlhybh@gmail.com"
          git config --local user.name "Ryan Lee"
          git add --all
          git commit -m "deploy `TZ=UTC-8 date +'%Y-%m-%d %H:%M:%S'`"
          git tag "v`cat VERSION`"
          git push -f https://ryanlee2014:$GITHUB_TOKEN@github.com/ryanlee2014/CUP-Online-Judge-CDN.git master
          git push --tags https://ryanlee2014:$GITHUB_TOKEN@github.com/ryanlee2014/CUP-Online-Judge-CDN.git
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_ACTIONS_TOKEN }}

这个过程的关键在于最后的Commit files and push。刚才我们生成了token, 并命名为GITHUB_ACTIONS_TOKEN。这里可以通过${{}}语法引入yml文件中,通过secret.GITHUB_ACTIONS_TOKEN访问到。

如上所示,通过将GITHUB_TOKEN作为环境变量引入,便可push到目标的仓库中。

发布Release

由于Github可以通过tag发布Release, 因此只需要在执行完打包后添加一个tag并push到目标repo即可。核心代码如下:

git config --local user.email "gxlhybh@gmail.com"
git config --local user.name "Ryan Lee"
git add --all
git commit -m "deploy `TZ=UTC-8 date +'%Y-%m-%d %H:%M:%S'`"
git tag "v`cat VERSION`"
git push -f https://ryanlee2014:$GITHUB_TOKEN@github.com/ryanlee2014/CUP-Online-Judge-CDN.git master
git push --tags https://ryanlee2014:$GITHUB_TOKEN@github.com/ryanlee2014/CUP-Online-Judge-CDN.git

这部分代码便是上面yml文件的最后一个step

自动部署到目标环境

Github提供了webhook功能,可以在Settings -> Webhook中设置。

点击Add Webhook, 便可进入添加webhook界面。

通过设置Webhook触发的URL和path和触发Secret(随便设置一个并记录下来), 设置Content-type为application/json,便完成初期工作。

URL格式:${href}${pathname}, 如http://oj.cupacm.com/webhook 中 http://oj.cupacm.com是href, /webhook 是pathname

接着我们可以通过一个webhook daemon服务来响应Github的POST操作。这里参考CUP-Online-Judge-Webhook-Service

src/config.json中有四个参数项,分别是

{
    "secret": "#刚才设置的secret",
    "path": "#触发webhook的pathname",
    "port": #监听的端口,
    "shell": "#执行shell文件的命令"
}

使用nginx或其他Web Server将webhook的pathname反代到服务端口,即可触发Webhook, 程序会自动执行shell文件。
只需要在shell文件中编写好自动部署的脚本即可完成全自动部署工作。

使用JSDelivr作为CDN加速

前面我们使用CI发布了Release, 因此我们可以通过JSDelivr给出的Github Release包访问的文档,从JSDelivr CDN上拉取静态资源。

根据官网给出的访问方式如下:

// load any GitHub release, commit, or branch
// note: we recommend using npm for projects that support it
https://cdn.jsdelivr.net/gh/user/repo@version/file


// load jQuery v3.2.1
https://cdn.jsdelivr.net/gh/jquery/jquery@3.2.1/dist/jquery.min.js


// use a version range instead of a specific version
https://cdn.jsdelivr.net/gh/jquery/jquery@3.2/dist/jquery.min.js
https://cdn.jsdelivr.net/gh/jquery/jquery@3/dist/jquery.min.js

// omit the version completely to get the latest one
// you should NOT use this in production
https://cdn.jsdelivr.net/gh/jquery/jquery/dist/jquery.min.js

// add ".min" to any JS/CSS file to get a minified version
// if one doesn't exist, we'll generate it for you
https://cdn.jsdelivr.net/gh/jquery/jquery@3.2.1/src/core.min.js

// add / at the end to get a directory listing
https://cdn.jsdelivr.net/gh/jquery/jquery/

然而这并不能完全把请求转向CDN。
参考CUP-Online-Judge-NG-FrontEnd
前面发布的指令中,对于每个Release包,均从VERSION文件中读取Release版本,而根据repo中给出的打包过程,我们发现VERSION文件版本是从package.json中读取version字段生成的。因此我们可以根据此修改vue.config.js文件,使Vue-Router使用CDN资源

给出如下例子

const version = require("./package.json").version;
const webPath = `https://cdn.jsdelivr.net/gh/ryanlee2014/CUP-Online-Judge-CDN@v${version}/`;

module.exports = {
    publicPath: process.env.NODE_ENV === "production" && !process.env.DISABLE_CDN ? webPath : "/"
};

通过设置publicPath, 我们可以把请求转到CDN文件上,实现静态资源CDN化的目标。

我估计上面的内容没几个人能看得懂,不过我还是要先写下来备忘

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇