やりたいこと
- フロントエンド側をデプロイした後に、画面を開き続けてるユーザを強制的にリロードさせたい
- バージョン管理はできるだけ自動化したい
作ったもの
- AWS CodeBuildのbuldspec.yml
- 自動でバージョンを採番する
- バージョンをビルドしたモジュールに埋め込む
- 最新のバージョン情報をAWS S3にファイルとして保存する
- バージョンを比較するAWS Lambda
- 強制リロードするフロントエンド
AWS CodeBuildのbuldspec.yml
${CODEBUILD_RESOLVED_SOURCE_VERSION}
でCodeBuildが把握しているソースのバージョンを取得できます。(詳細)
それを使って、./src/version.js
を置換しています。
build:
commands:
- sed -i -e "s/CODEBUILD_RESOLVED_SOURCE_VERSION/${CODEBUILD_RESOLVED_SOURCE_VERSION}/g" ./src/version.js
- cat ./src/version.js
AWS S3に${CODEBUILD_RESOLVED_SOURCE_VERSION}
の出力結果を配置しています。
post_build:
commands:
- echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} > version
- aws s3 cp ./version s3://${S3_BUCKET_NAME}/ --acl bucket-owner-full-control
バージョンを比較するAWS Lambda
S3とクエリで指定されたバージョンとの比較をしています。その結果を返します。
このLambdaはクライアント端末から実行されるので、外部アクセスを許可するようにします。
bucket = s3.Bucket(backet_name)
obj = bucket.Object(OBJECT_KEY_NAME)
response = obj.get()
body = response['Body'].read()
if event['queryStringParameters']['version'] == body:
全文
import json
import datetime
import boto3
# バケット名,オブジェクト名
STG_BUCKET_NAME = 'frontend-stg-source'
PRO_BUCKET_NAME = 'frontend-pro-source'
OBJECT_KEY_NAME = 'version'
s3 = boto3.resource('s3')
def lambda_handler(event, context):
print(event['queryStringParameters'])
bucket_name = ''
# バリデーションチェック
if not 'queryStringParameters' in event.keys():
return {
'statusCode': 400,
'body': 'not parameter key'
}
# 環境を指定されているか確認
if not 'env' in event['queryStringParameters'].keys():
return {
'statusCode': 400,
'body': 'not env parameter key'
}
# パラメータチェック
if not 'version' in event['queryStringParameters'].keys():
return {
'statusCode': 400,
'body': 'not version parameter key'
}
# 環境別にバケット名が違うので、バケット名を取得する
if event['queryStringParameters']['env'] == 'staging':
backet_name = STG_BUCKET_NAME
elif event['queryStringParameters']['env'] == 'production':
backet_name = PRO_BUCKET_NAME
else:
# 環境指定が間違っているのでエラー
return {
'statusCode': 400,
'body': 'not expect env parameter key'
}
# S3からデータを取得します
bucket = s3.Bucket(backet_name)
obj = bucket.Object(OBJECT_KEY_NAME)
response = obj.get()
body = response['Body'].read()
body = body.decode('utf-8')
body = body.strip()
print({'client': event['queryStringParameters']['version'], 's3': body})
if event['queryStringParameters']['version'] == body:
return {
'statusCode': 200,
'body': json.dumps( "OK" )
}
else:
return {
'statusCode': 202,
'body': json.dumps( "NG" )
}
1. 最新バージョン出なかったらリロードするフロントエンド
以下は「URLが変わったら」という意味です。つまりページ遷移したらバージョンチェック処理が実行されます
watch(() => route, function (to, from) {
リクエストの結果がNGの場合はリロードする処理です。
if (res.data == 'NG') location.href = location.href
全文
<script lang="ts" setup>
import {watch} from 'vue'
import {useRoute} from "vue-router";
import * as Version from "@/version"
import axios from 'axios'
const route = useRoute()
watch(() => route, function (to, from) {
const request = axios.create({
timeout: 9000
})
request({
url: 'https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws',
method: "get",
params: {
version: Version.Version,
env: import.meta.env.VITE_ENV
}
})
.then((res) => {
console.log("バージョン確認:" + res.data)
if (res.data == 'NG') location.href = location.href
})
.catch((error) => {
console.log(error)
})
}, {deep: true})
</script>
ちなみに。version.jsの中身
以下一文だけです。CODEBUILD_RESOLVED_SOURCE_VERSIONはbuildspec.ymlでsedを使って書き換えられます。importしたjavascriptで定義済みの定数が使えます。
export const Version = "CODEBUILD_RESOLVED_SOURCE_VERSION"
これで、CodeBuildを使ってデブロイされたら、自動でソースバージョンが保管されて、ページ遷移するたびに呼ばれるチェック処理によって、NGの場合は自動更新されるようになりました。