39
44

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

React を Azure Static Web Appsでホスティングする開発・本番環境を作る

Last updated at Posted at 2021-01-04

Azure Static Web Apps という SPA 用の Azure リソースがあります。React や Vue.js などを実に簡単にホスティングできます。
2020/12時点でまだプレビューで、機能的にはまだこれからなところがありますが、これから間違いなく主役級リソースとなるでしょう。
本記事では React を使った ローカル開発環境の構築と、Azureへのデプロイまでの手順を記載します。

事前準備

以下の準備が必要です。

GitHub にリポジトリを準備し、ローカルリポジトリと同期

まずは GitHub にリポジトリを作りましょう。myappという名前で私は作ります。publicかprivateかはどちらでもOKです。.gitignoreファイルは作らないでおきましょう。この後の React アプリ作成時に自動的に作成されるため、重複するからです。

create repository

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

自動的にブラウザが立ち上がり、画面が表示されればOKです。

CTRL+Cを押下して、yarn を停止しましょう。今後はこのターミナルで React アプリを起動はしません。

Visual Studio Codeでフォルダを開く

yarn start したターミナルが残っている場合は、そこで次のコマンドを叩けばそのフォルダを VSCode で開くことができます。

code . -r

もしくは、エクスプローラーで右クリック→「codeで開く」とするか、 VSCode を起動してから「ファイル」→「フォルダーを開く」を選択してからgit cloneして自動作成されたフォルダを選びます。

以降の作業は VSCode のターミナルを使用します。「ターミナル」→「新しいターミナル」を選択します。

vscode terminal open

こんな画面が表示されるはずです。
image.png

powershell だったり、bash だったりと表示されるターミナルは環境によって様々のはずです。私の場合は Windows で Powershell を使用していきます。
ちなみに私の Powershell ターミナルにカラフルな情報(現在位置と Git 情報)が表示されているのは、別途そういうセットアップをしているからです。ご興味がある方はこちらをどうぞ。

Azure Functions アプリをローカルで作る

一番上の階層にapiフォルダを作ります。ここにAzure Functionsアプリを構成します。(ちなみにapiという名前じゃなくても本当は大丈夫です。後ほどAzure Static Web Apps をAzure上に新規作成するときにAzure Functionsの場所を指定するので、api以外の名前を付けた場合はそれを指定できるからです)

create api folder on the top

Azure Functions の作成はAzure Functions拡張機能を使います。Visual Studio Codeの「表示」メニューからコマンドパレットを開きます。
show command pallet

Azure Functions:Create New Projectsを一文字ずつ入力していくと選択肢が絞られていきます。選択します。

選択すると、情報入力をウィザード形式で求めてきます。最初は Azure Functions を作る場所です。apiフォルダを指定したいので、Broseを選択してから api フォルダを選択します。

select api folder

どの言語で実装するのかを選択します。今回はC#で作ります。

select lang

次はAzure Functions のトリガーを選択します。選択肢のドロップダウンが表示されるまで5秒ぐらいかかりますので少し待ちましょう。
HttpTriggerを選択します。

select httptrigger

最初に作成するメソッド名を選択します。APIのURLでもあります。デフォルトで名前を提案されますが、「GetData」変えます。
メソッド名は後から変更できます。

input function name

名前空間を決めます。これも後から変更可能です。今回はデフォルトのままにします。
input namespace

最後に、APIアクセス時の認証設定です。本番時には認証を入れるべきですが、今回は「認証なし」を意味するAnonymousを選びます。
select auth

Azure Functions が作成されるとエクスプローラーはこのようになります。

folder structure after azure functions created

エラーが大量に出ていると思いますが、パッケージをダウンロードしてないからです。気にせずデバッグ実行してみましょう。(デバッグ実行のプロセスの最中にパッケージもダウンロードします)
左のデバッグ実行メニューをクリックしてから、実行ボタンをクリックします。

image.png

もしかしたら、この時に Azure Functions Core Toolsのインストールを求めるポップアップが上がってくるかもしれません。その場合はインストールしてください。

install azure functions core tools

無事に起動すると、URLがターミナルに表示されます。ブラウザで開きましょう。(CTRL+クリックで開きます)
image.png

エラーなくメッセージが表示されればOKです。

view azure functions in browser

この後すぐにソースを修正するので、デバッグ実行は停止しておきます。

image.png

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 からデータを取ってきて、それを表示しているだけです。

App.tsx
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」というのがありませんか?それを選択します)

switch terminal

・・・ブラウザには何も表示されないですね。開発者ツールから、Consoleを開いてみます。
error.png

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 にアクセスします。このようになれば成功です。

image.png

これでローカルの開発環境作成は完成です。Azure Functions のソースにブレークポイントを置いてからブラウザを再読み込みすると、ブレークポイントで止まります。確認してください。

image.png

Azure Static Web Appsを作成する

Azureのポータル画面を開き、リソースの作成をクリックします。

create new

検索ボックスに static web apps を入力していくと、Static Web Appが絞り込みで表示されてきますので、選択します。

search static web app

Static Web App の作成画面が表示されます。作成をクリックします。

情報を入力します。

  • リソースグループは新規で作成します。(既存のグループを使ってもいいですが)今回はstaticwebtestという名前にしました。
  • 静的 Webアプリの名前を適当に付けます。今回はmystaticwebにしました。
  • 地域は選択します。今回は East Asiaにしました。2020/12現在、日本リージョンはまだ使用できません。

image.png

「GitHubアカウントでサインイン」をクリックすると、画面がポップアップします。「Authorize Azure-App-Service-Static-Web-Apps」をクリックします。

パスワードを入力し、「Confirm password」をクリックします。

confirm github password

GitHubアカウントから、デプロイに使用するリポジトリとブランチ(分岐)を選択します。今回はmainブランチを選択します。
「ビルドの詳細」では、まずビルドのプロセットを選択します。今回はReactを選びます。すると、自動的に

  • アプリの場所
  • APIの場所
  • アプリの成果物の場所

の3つに値が入力されます。ここでいうアプリ、とはReactアプリのことを指します。次のように自動的に値が入ります。

アプリの場所 /
APIの場所 api
アプリの成果物の場所 build
confirm react app settings

左下の「確認及び作成」をクリックします。

confirm to create static web app

作成をクリックします。デプロイが開始されます。デプロイが完了すると「リソースへ移動」が表示されますのでクリックします。

static web app created

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 を開いて、履歴を参照します。
image.png

image.png

「Build And Deploy」をクリックして開くと、デプロイ処理の詳細を見ることができます。
image.png

Nodeのインストールから始まり、yarn install でパッケージ復元をして・・・という一連の流れを見ることできます。一度は見ておいたほういいでしょう。
image.png

確認

Azure Static Web Appの概要を開くと、右側にURLが表示されています。クリックします。

image.png

Azure Static Web AppでReactアプリがホスティングされました。
image.png

途中のセットアップで気づかれたかと思いますが、APIの場所は別に api フォルダじゃなくてもいいし、Reactアプリをビルドした結果をまとめる先がbuildフォルダでなくても問題ありません。Azure Static Web App作成時に指定した場所を変更したい場合は GitHub Actions のワークフローを修正します。

image.png

いかがだったでしょうか。実は一番ややこしいのは git の操作なのではないか、と思います。慣れていないと難しいですね。
まだ日本リージョンではホスティングすることができませんが、近い将来には日本リージョンでも動かせる日がきっと来ると思います。

是非、React アプリを Azure Static Web App で動かしてみてください。とても便利ですよ。

39
44
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39
44

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?