Azure Static Web Apps という SPA 用の Azure リソースがあります。React や Vue.js などを実に簡単にホスティングできます。
2020/12時点でまだプレビューで、機能的にはまだこれからなところがありますが、これから間違いなく主役級リソースとなるでしょう。
本記事では React を使った ローカル開発環境の構築と、Azureへのデプロイまでの手順を記載します。
事前準備
以下の準備が必要です。
- Node.jsのインストール
-
Yarnのインストール
- npmと同じパッケージリポジトリを使用するNode.jsのパッケージ管理ツールです。必須ではありませんが、個人的に使用を推奨します。
- Visual Studio Codeのインストール
-
Visual Studio Code Azure Functions 拡張機能
Azure FunctionsをC#で実装する場合は.NET Core 3.1をインストールします。2020/12時点で、.NET 5はまだ対応していません。 -
Azure Functions Core Tools
- npm のパッケージです。グローバルにインストールしますが、あらかじめインストールしなくてもデバッグ実行時にインストールを求められますので、その時にインストールしてください。Windows環境の方で自分でインストールしたい場合はx64版をインストールしてください。リンク先の熟読をお願いします。
- Gitのインストール
-
GitHub アカウント
- アカウントがない場合はこれを機会に作成をお願いします。無料で使用可能です。
GitHub にリポジトリを準備し、ローカルリポジトリと同期
まずは GitHub にリポジトリを作りましょう。myappという名前で私は作ります。publicかprivateかはどちらでもOKです。.gitignoreファイルは作らないでおきましょう。この後の React アプリ作成時に自動的に作成されるため、重複するからです。
Powershell、コマンドプロンプト、bashなどのターミナルからを立ち上げてください。これから GitHub に作った Repository をローカルに clone しますので、ソースを配置したい場所へ移動します。私はソースは常に C:\gitroot 配下に作ることにしていますので、そこに移動します。
clone コマンドは Repository 名のフォルダを自動的に作成しますので、C:\gitroot で下記コマンドを叩きます。<org_name>の箇所は、自分のアカウント名か、組織名(GitHub内の組織)に書き換えてください。
git clone https://github.com/<org_name>/myapp.git
自動作成したフォルダに移動してから、お作法として、最初のコミットには空のコミットを入れておきます。ついでに、もし branch 名が master なら main にリネームしておきます。(リネームはしなくてもいいのですが、最近の流れはmasterというブランチ名を使わないそうです)
cd myapp
git commit --allow-empty -m "first commit"
git branch -M main
無事に変更出来たら、push します。master を main に変更していますので、わざわざ origin へ HEAD を pushする、と指定しなければなりません。
git push origin HEAD
最初の push はこれでいいのですが、毎回 origin HEAD を指定するのは面倒です。今後のために up-stream 先の master を mainに変更しておきます。
git branch --unset-upstream
git branch --set-upstream-to origin/main main
これで以降の push は次のコマンドで簡単になります。
git push
Reactアプリを作成する
自分で1つずつ組み上げてもいいですし、create-react-appを使ってもいいので、Reactアプリを作ります。
create-react-appで作らない場合や既存のReactアプリの場合は、package.json の scripts に build コマンドを作って本番用にビルドした結果をどこかのフォルダに固めるようにしておいてください。後で構成する GitHub Actionsは "yarn run build" を叩く仕様になっているからです。
今回はmyappという名前のReactアプリをcreate-react-appを使ってTypeScriptで作ります。
注意がいるのは、yarn create コマンドもフォルダを自動作成しようとします。なので、このままだと1階層多くなってしまうので、一つ上の階層(C:\gitroot)に移動してからyarn create します。
cd ..\
yarn create react-app myapp --template typescript
動かしてみましょう。
cd myapp
yarn start
CTRL+Cを押下して、yarn を停止しましょう。今後はこのターミナルで React アプリを起動はしません。
Visual Studio Codeでフォルダを開く
yarn start したターミナルが残っている場合は、そこで次のコマンドを叩けばそのフォルダを VSCode で開くことができます。
code . -r
もしくは、エクスプローラーで右クリック→「codeで開く」とするか、 VSCode を起動してから「ファイル」→「フォルダーを開く」を選択してからgit cloneして自動作成されたフォルダを選びます。
以降の作業は VSCode のターミナルを使用します。「ターミナル」→「新しいターミナル」を選択します。
powershell だったり、bash だったりと表示されるターミナルは環境によって様々のはずです。私の場合は Windows で Powershell を使用していきます。
ちなみに私の Powershell ターミナルにカラフルな情報(現在位置と Git 情報)が表示されているのは、別途そういうセットアップをしているからです。ご興味がある方はこちらをどうぞ。
Azure Functions アプリをローカルで作る
一番上の階層にapiフォルダを作ります。ここにAzure Functionsアプリを構成します。(ちなみにapiという名前じゃなくても本当は大丈夫です。後ほどAzure Static Web Apps をAzure上に新規作成するときにAzure Functionsの場所を指定するので、api以外の名前を付けた場合はそれを指定できるからです)
Azure Functions の作成はAzure Functions拡張機能を使います。Visual Studio Codeの「表示」メニューからコマンドパレットを開きます。
Azure Functions:Create New Projectsを一文字ずつ入力していくと選択肢が絞られていきます。選択します。
選択すると、情報入力をウィザード形式で求めてきます。最初は Azure Functions を作る場所です。apiフォルダを指定したいので、Broseを選択してから api フォルダを選択します。
どの言語で実装するのかを選択します。今回はC#で作ります。
次はAzure Functions のトリガーを選択します。選択肢のドロップダウンが表示されるまで5秒ぐらいかかりますので少し待ちましょう。
HttpTriggerを選択します。
最初に作成するメソッド名を選択します。APIのURLでもあります。デフォルトで名前を提案されますが、「GetData」変えます。
メソッド名は後から変更できます。
名前空間を決めます。これも後から変更可能です。今回はデフォルトのままにします。
最後に、APIアクセス時の認証設定です。本番時には認証を入れるべきですが、今回は「認証なし」を意味するAnonymousを選びます。
Azure Functions が作成されるとエクスプローラーはこのようになります。
エラーが大量に出ていると思いますが、パッケージをダウンロードしてないからです。気にせずデバッグ実行してみましょう。(デバッグ実行のプロセスの最中にパッケージもダウンロードします)
左のデバッグ実行メニューをクリックしてから、実行ボタンをクリックします。
もしかしたら、この時に Azure Functions Core Toolsのインストールを求めるポップアップが上がってくるかもしれません。その場合はインストールしてください。
無事に起動すると、URLがターミナルに表示されます。ブラウザで開きましょう。(CTRL+クリックで開きます)
エラーなくメッセージが表示されればOKです。
この後すぐにソースを修正するので、デバッグ実行は停止しておきます。
JSONを返すようにAPIを実装する
ダミーのJSONを返すように実装します。
namespace Company.Function
{
public static class GetData
{
[FunctionName("GetData")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
var results = new Data[] {
new Data { Id = 1, Name = "Sato" },
new Data { Id = 2, Name = "Suzuki" }
};
return new JsonResult(results);
}
}
public class Data {
public int Id { get; set; }
public string Name { get; set; }
}
}
asyncメソッドなのにawaitがないから同期的に実行しますよ、という警告が出ると思いますが無視します。今回そこはどうでもよいところです。
忘れずにデバッグ実行を開始しておきましょう。
APIを呼び出すように React を実装する
外部へのhttpアクセスにはjavascriptのfetchメソッドを使うことができますが、httpステータスエラーを補足しない、という特徴がありますので私は使いません。いつもaxiosを使いますので今回もそうします。VSCode のターミナルで次のコマンドを叩きます。
yarn add axios
App.tsxファイルを以下のように修正します。Azure Functions からデータを取ってきて、それを表示しているだけです。
import React from 'react';
import axios, { AxiosResponse } from 'axios';
function App() {
const [response, setResponse] = React.useState<AxiosResponse>();
React.useEffect(() => {
axios.get('http://localhost:7071/api/GetData')
.then(response => {
// handle success
setResponse(response);
console.log(response);
})
.catch(error => {
// handle error
console.log(error);
})
.then(() => {
// always executed
});
}, []);
return (
<React.Fragment>
{response?.data.map((elm:any, index:number) => {
return (
<div key={index}>id: {elm.id}, name: {elm.name}</div>
)
})}
</React.Fragment>
);
}
export default App;
yarn start で実行してみましょう。(デバッグ実行が表示されていてコマンドが叩けませんか?その場合はターミナル右側に表示されている「2:タスク-host start」をクリックしてみてください。「1:powershell」というのがありませんか?それを選択します)
・・・ブラウザには何も表示されないですね。開発者ツールから、Consoleを開いてみます。
CORS policyにブロックされた、とメッセージが出ています。
ローカル開発用のCORSを設定する
デフォルトの状態では Reactは http://localhost:3000 で Azure Functions は http://localhost:7071 です。ホストは同じですがポートが異なるため、CORS(Cross-Origin Resource Sharing)ではオリジンが異なると判定されてしまい、APIアクセスの結果がエラーとなります。これを解決する方法は二つあって、一つはアクセスされる側であるAzure Functionsで明示的にReact側のオリジンを許可するように設定するか、React側で外部アクセスする時にProxy機能を使ってアクセスするホストを書き換えるかのどちらかになります。
Azure Functions でReact側のオリジンを設定する方法ですが、なぜか SignalR のdocsに設定方法が記載されています。
https://docs.microsoft.com/ja-jp/azure/azure-signalr/signalr-concept-serverless-development-config#enabling-cors
しかし、この方法は何かしら特別な理由がない限りは採用しないでしょう。APIアクセス時のURLを何かしらの方法(環境ファイルなど)を使って切り替えなければいけないですし、デプロイ後の本番環境(Azure Static Web)ではReactアプリもAPIサーバーと同じオリジンになるように構成されるため、余計なCORS設定は削除しておく必要があります。積極的に採用する理由がありません。
通常はReactアプリ側でProxy機能を利用するでしょう。create-react-appで作成した場合はpackage.jsonの一番上の階層(nameやversion等と同じ階層)に次のように実装します。
"proxy": "http://localhost:7071"
create-react-appを使用していない場合や既存のReactアプリの場合は使用しているWebサーバーの仕様次第ですので、ご自身で設定をお願いします。(webpack-dev-serverを使っている方が多いと思います。その場合はwebpack.config.jsのdevServerセクションにproxy設定をすることができます。公式の解説)
Proxy機能を使う場合、APIアクセス時のURLを書き換える必要があります。
axios.get('http://localhost:7071/api/GetData') // 修正前
axios.get('/api/GetData') // 修正後
proxy機能を有効にするために、Reactを実行中の場合はCTRL+C押下で一度停止して、再度yarn startで開始してください。
ブラウザで http://localhost:3000 にアクセスします。このようになれば成功です。
これでローカルの開発環境作成は完成です。Azure Functions のソースにブレークポイントを置いてからブラウザを再読み込みすると、ブレークポイントで止まります。確認してください。
Azure Static Web Appsを作成する
Azureのポータル画面を開き、リソースの作成をクリックします。
検索ボックスに static web apps を入力していくと、Static Web Appが絞り込みで表示されてきますので、選択します。
Static Web App の作成画面が表示されます。作成をクリックします。
情報を入力します。
- リソースグループは新規で作成します。(既存のグループを使ってもいいですが)今回はstaticwebtestという名前にしました。
- 静的 Webアプリの名前を適当に付けます。今回はmystaticwebにしました。
- 地域は選択します。今回は East Asiaにしました。2020/12現在、日本リージョンはまだ使用できません。
「GitHubアカウントでサインイン」をクリックすると、画面がポップアップします。「Authorize Azure-App-Service-Static-Web-Apps」をクリックします。
パスワードを入力し、「Confirm password」をクリックします。
GitHubアカウントから、デプロイに使用するリポジトリとブランチ(分岐)を選択します。今回はmainブランチを選択します。
「ビルドの詳細」では、まずビルドのプロセットを選択します。今回はReactを選びます。すると、自動的に
- アプリの場所
- APIの場所
- アプリの成果物の場所
の3つに値が入力されます。ここでいうアプリ、とはReactアプリのことを指します。次のように自動的に値が入ります。
アプリの場所 | / |
---|---|
APIの場所 | api |
アプリの成果物の場所 | build |
左下の「確認及び作成」をクリックします。
作成をクリックします。デプロイが開始されます。デプロイが完了すると「リソースへ移動」が表示されますのでクリックします。
GitHubへソースを push して deploy する
いよいよ Azure Static Web App にデプロイするわけですが、それにはソースを GitHub へ Push することが相当します。
最初に GitHub のリポジトリに空のコミットを行いました。以降は何もコミットしていませんが、実はさきほどAzure Static Web App を作成したときにファイルが1つ追加されてコミットされています。そのため、今の時点ではリモートリポジトリ(GitHub のリポジトリ)の方が先に進んでしまっているので、まずはリモートリポジトリと同期することから始めます。
React アプリと Azure Functions のデバッグ実行を停止したら、次のコマンドを叩きます。(私は普段 git コマンドを使いますのでコマンドを紹介しますが、せっかくVSCodeを使っているのでGUIを使って作業しても構いません)
git pull
成功したら、すべてのソースをコミットしてから push します。
git add .
git commit -m "first deploy"
git push
git push に成功すると、自動的にGitHub Actionsはソースのビルドを行い、デプロイ用にZipファイルを作成し、アップロードし、デプロイ先がそのZipを展開します。そんなGitHub Actionsでのデプロイ状況を見る場合は GitHub の Actions を開いて、履歴を参照します。
「Build And Deploy」をクリックして開くと、デプロイ処理の詳細を見ることができます。
Nodeのインストールから始まり、yarn install でパッケージ復元をして・・・という一連の流れを見ることできます。一度は見ておいたほういいでしょう。
確認
Azure Static Web Appの概要を開くと、右側にURLが表示されています。クリックします。
Azure Static Web AppでReactアプリがホスティングされました。
途中のセットアップで気づかれたかと思いますが、APIの場所は別に api フォルダじゃなくてもいいし、Reactアプリをビルドした結果をまとめる先がbuildフォルダでなくても問題ありません。Azure Static Web App作成時に指定した場所を変更したい場合は GitHub Actions のワークフローを修正します。
いかがだったでしょうか。実は一番ややこしいのは git の操作なのではないか、と思います。慣れていないと難しいですね。
まだ日本リージョンではホスティングすることができませんが、近い将来には日本リージョンでも動かせる日がきっと来ると思います。
是非、React アプリを Azure Static Web App で動かしてみてください。とても便利ですよ。