はじめに
以下の記事で、Amazon S3 と CloudFront を使って HTTPS でサイトを独自ドメインで公開する方法が分かりました。
では、React の SPA (Single Page Application)を S3 + CloudFront 環境にデプロイしてキャッシュをクリアするまで自動化するにはどうすればいいでしょうか。
この記事ではその方法についてご紹介します。
なお、環境は以下の通りで、AWS SDK はすでにインストール済みであることを前提にしています。
- Windows 10
- React 16.8.8
- Node 11.10.1
- Visual Studio Code
React プロジェクトの作成
React プロジェクトを下記コマンドで作成します。
なお、TypeScript のプロジェクトを作成したいのでオプションをつけていますが、JavaScript で開発したい場合は不要です。
> npx create-react-app reacttest --scripts-version=react-scripts-ts
必要なパッケージのインストール
S3 へのアップロード、および CloudFront のキャッシュをクリアするのに必要なパッケージをインストールします。
> npm install aws-sdk --save-dev > npm install mime-types --save-dev > npm install node-uuid --save-dev
デプロイスクリプトの作成
プロジェクトのルートパスにscript
フォルダを作成し、そのフォルダの下にdeploy.js
を新規作成します。
そして、以下のコードを貼り付け、config の設定を書き換えます。
基本的に config を書き換えればうまくいくと思うのでコピペでもいいと思いますが、詳細を確認したい場合は参考サイトを参照してください。
なお、アクセスキー ID とシークレットアクセスキーは、外部に漏洩しないよう厳重に管理してください。
const AWS = require("aws-sdk"); // imports AWS SDK const mime = require('mime-types') // mime type resolver const fs = require("fs"); // utility from node.js to interact with the file system const path = require("path"); // utility from node.js to manage file/folder paths var uuid = require('node-uuid'); // configuration necessary for this script to run const config = { s3BucketName: '{S3バケット名}', folderPath: '../build', // path relative script's location accessKeyId: '{アクセスキーID}', // IAM user's AccessKeyID secretAccessKey: '{シークレットアクセスキー}', // IAM user's SecretAccessKey DistributionId: '{CloudFrontのID}' // DistributionId of CloudFront }; /* S3 のファイルアップロード設定 */ // initialise S3 client const s3 = new AWS.S3({ signatureVersion: 'v4' }); // resolve full folder path const distFolderPath = path.join(__dirname, config.folderPath); // Normalize \\ paths to / paths. function unixifyPath(filepath) { return process.platform === 'win32' ? filepath.replace(/\\/g, '/') : filepath; }; // Recurse into a directory, executing callback for each file. function walk(rootdir, callback, subdir) { // is sub-directory const isSubdir = subdir ? true : false; // absolute path const abspath = subdir ? path.join(rootdir, subdir) : rootdir; // read all files in the current directory fs.readdirSync(abspath).forEach((filename) => { // full file path const filepath = path.join(abspath, filename); // check if current path is a directory if (fs.statSync(filepath).isDirectory()) { walk(rootdir, callback, unixifyPath(path.join(subdir || '', filename || ''))) } else { fs.readFile(filepath, (error, fileContent) => { // if unable to read file contents, throw exception if (error) { throw error; } // map the current file with the respective MIME type const mimeType = mime.lookup(filepath) // build S3 PUT object request const s3Obj = { // set appropriate S3 Bucket path Bucket: isSubdir ? `${config.s3BucketName}/${subdir}` : config.s3BucketName, Key: filename, Body: fileContent, ContentType: mimeType } // upload file to S3 s3.putObject(s3Obj, (res) => { console.log(`Successfully uploaded '${filepath}' with MIME type '${mimeType}'`) }) }) } }) } /* CloudFrond のキャッシュクリア設定*/ var cloudfront = new AWS.CloudFront({ apiVersion: '2018-06-18', accessKeyId: config.accessKeyId, secretAccessKey: config.secretAccessKey, }); var timestamp = new Date(); var string_timestamp = String(timestamp.getTime()); var invalidate_items = ['/*']; // 全キャッシュクリア var item_count = invalidate_items.length var params = { DistributionId: config.DistributionId, InvalidationBatch: { CallerReference: string_timestamp, Paths: { Quantity: item_count, Items: invalidate_items } } }; // S3にファイルアップロード実行 walk(distFolderPath, (filepath, rootdir, subdir, filename) => { console.log('Filepath', filepath); }); // CloudFront キャッシュクリア実行 cloudfront.createInvalidation(params, function(err, data) { if (err) console.log(err, err.stack); else console.log(data); });
デプロイの設定
pakage.json
のscripts
配下に、以下の2行を追加します(追加時に、一行前の末尾にカンマを付けるのを忘れないこと)。
"predeploy": "yarn build", "deploy": "node ./scripts/deploy.js"
デプロイの実行
以下のコマンドを実行することで、ビルド&デプロイ、キャッシュのクリアまで行うことができます。
> yarn deploy
うまくいきましたね。
おわりに
スクリプトさえ用意できれば、自動デプロイは難しくないことが分かります。
スクリプトを公開してくれた参考サイトの方に感謝ですね。
なお、CloudFront の無効化(キャッシュクリア)は、1000回/月 を超えると課金されるのでスクリプト利用時は気をつけてください。