ほりひログ

所属組織の製品 (Azure とか) に関連する内容が多めだけど、個人の見解であって、所属組織を代表する公式情報ではないです。

GitHub Codespaces を使って、Web ブラウザーだけで Static Web Apps アプリを開発/デバッグしてみる

f:id:horihiro:20210516074018p:plain

Azure Static Web Apps

ついに、一般提供を開始しました! azure.microsoft.com

サポート エンジニア時代にいたチームはこの製品も担当していたので、割と早い段階 (パブリック プレビュー開始の前あたり) から知っている製品でした。
でも正直「静的ファイルや SPA のホスティングなんて、Web Apps でやったらいいじゃない」と思い、あまり本腰入れて試していませんでした (ごめんなさい💦)。

が、ある程度試していく中で、Web フロントエンドに特化した製品であることが理解でき、「なるほど便利だ」とひとしきり反省しております。

確かに Web Apps だけで SPA をホスティングしようとして、ハマることもあるんですよね。

uncaughtexception.hatenablog.com

今もこの問題が残っているか確認してませんが、ビルド周りの違いだけではなく、Azure Static Web Apps はグローバル サービスなので、常にクライアントに最も近いエッジ サーバーから配信される、というメリットもあります。
SPA に特化したホスティングにはオススメですね。
# Web Apps も大好きです。適材適所です。

その他の機能、日本語ではこちらの三宅さんのブログ、公式ドキュメントに網羅されているので、興味のある方はこちらをご覧ください。

k-miyake.github.io

docs.microsoft.com

本題

Static Web Apps 猛者の三宅さんのツイートを発端に疑問が。

ということで、
GitHub Codespaces/Web ブラウザーだけを使って、Azure Static Web Apps に載せる SPA と Serverless API の開発/デバッグができるか
を試してみました。

GitHub Codespaces

github.com

ざっくりいうと、

Web ブラウザー上で、VSCode 風(というかそのもの)な UI で、GitHub リポジトリーのファイルを直接?編集できる

というものです。

GiHub Codespaces を使えば、コーディングはできます。
あと GiHub Codespaces からリポジトリーに直接 git push ができるので、GitHub Actions 経由で Azure Static Web Apps へのコードのデプロイもできます。

では、デバッグはどうなのか。

結論

  • SPA の Javascript は、Web ブラウザーの開発者ツール
  • バックエンドの Serverless API は、GiHub Codespaces の Dev Container 上の Azure Functions Core Tools

を使うと、ブラウザーだけで両者のデバッグが同時に可能です。

さらに GiHub Codespaces の Dev Container 上で Static Web Apps CLI を動かして、認証関連の動きもエミュレートできるようになります。

docs.microsoft.com

tasks.json

GitHub Codespaces はデバッグ機能もほぼ VSCode なので、.vscode/tasks.json に個々の task を書いていけば VSCode 同様にデバッグ実行ができます。

SPA ビルド用 task

プロジェクト ルートで npm run build しています。vue であれば vue-cli-service build が実際のコマンドになります。

    {
      "type": "shell",
      "label": "npm run build",
      "command": "npm run build",
      "dependsOn": "npm install (for app)",
      "options": {
        "cwd": "${workspaceFolder}"
      }
    },

あと webpack でのビルド設定などで、source map を出力するようにします。
これでブラウザーの開発者ツール上で Break point が設定できます。
vue であれば、vue.config.js に下記の configureWebpack 設定を追加をしておきます。

module.exports = {
    // : 
    configureWebpack: {
        devtool: 'source-map'
    },
    // : 
}

この task はビルド結果 (バンドルされた JS ファイルなど) を ./dist などに出力して終了です。
# Webpack Dev Server を使ってない (vue-cli-service serve してない) 理由は後述

バックエンド Serverless API デバッグ開始 task

Azure Functions Core Tools でバックエンドの Serverless APIデバッグ実行します。
./api に Azure Functions のプロジェクトがあるとして、そこで func host start を実行しています。

オプション --language-worker -- \"--inspect=9229\" を追加して、GitHub Codespaces 上のデバッグ プロセスから Launguage Worker プロセスにアタッチできるようにしています。

    {
      "type": "shell",
      "label": "func start",
      "command": "func host start --language-worker -- \"--inspect=9229\"",
      "problemMatcher": {
        "owner": "custom",
        "pattern": {
          "regexp": "^$"
        },
        "background": {
          "activeOnStart": true,
          "beginsPattern": "^.*(Job host stopped|signaling restart).*$",
          "endsPattern": "^.*(Worker process started and initialized|Host lock lease acquired by instance ID).*$"
        }
      },
      "isBackground": true,
      "dependsOn": "npm install (for api)",
      "options": {
        "cwd": "${workspaceFolder}/api"
      }
    },

この task を実行すると、通常の Azure Functions プロジェクトのデバッグと同様、http://localhost:7071 動作し続けます。

Static Web Apps CLI 起動用 task

npm run build で出力した ./dist を Static サイトに、func host start で動かした http://localhost:7071 をバックエンド API に指定して、Static Web Apps CLI を実行しています。

# npm script に引数を渡すために -- が必要、ということをここで知りました。

    {
      // 
      "type": "shell",
      "label": "swa start",
      "command": "npm run swa -- start dist --api=http://localhost:7071",
      "isBackground": true,
      "problemMatcher": {
        "owner": "custom",
        "pattern": {
          "regexp": "^$"
        },
        "background": {
          "activeOnStart": true,
          "beginsPattern": "^.*Using dev server for static content .*$",
          "endsPattern": "^.*Azure Static Web Apps emulator started.*$"
        }
      },
      "dependsOn": [
        "npm run build", 
        "func start"             
      ],
      "options": {
        "cwd": "${workspaceFolder}"
      }
    },

dependsOn で上の 2 つの task を指定しているので、これらの task が完了状態になってから実行しています。

launch.json

上のタスクを実行する GitHub Codespaces のデバッグ設定は、Azure Functions 用の設定をマルっとパクります。

        {
            "name": "Launch Static Web Apps Dev Server and Backend Functions",
            "type": "node",
            "request": "attach",
            "port": 9229,
            "preLaunchTask": "swa start"
        }

これで GitHub Codespaces がバックエンド Serverless APIデバッグ プロセスにアタッチします。

その他

Dev Container で Azure Functions Core Tools を入れたり、devDendencies の一つとして Static Web Apps CLI を入れたりしてますが、まとめたものはこちらにあるので興味があれば。

github.com

動作の様子

デバッグ実行の様子はこちら。

Dev Container 内の Static Web Apps CLI のサーバー プロセスには、

https://${ユーザー名/組織名}-${リポジトリー名}-${4桁のランダム文字列}-${フォワード先のポート番号}.githubpreview.dev/

という URL でアクセスできます。

PORTS のリストに URL が出てくるので、Static Web Apps CLI は 4280 で待ち受けているので、それにフォワードしている URL を選びましょう。

f:id:horihiro:20210516141530p:plain

現時点でわかっているできないこと

実はいくつかのことが、このデバッグ構成ではできません。

ログアウト時のルーティング

この GitHub Codespaces の構成でログアウト (/.auth/logout にアクセス) すると、必ず http://localhost にリダイレクトされます。
当然、ローカルでサーバーを実行していなければエラー画面が表示されます。

どうやら、上の URL へのリクエストは Dev Container 内の Static Web Apps CLI のプロセスに届く前にリバース プロキシを通っているようで、リクエストの host ヘッダーには localhost 、本来リダイレクト先に使いたい上の URL のホスト名は x-forwarded-host ヘッダーに入ってきます。

一方で、Static Web Apps CLI の開発サーバーのログアウト時のリダイレクト先は、以下のように host ヘッダーだけを見ているので、http://localhost にリダイレクトされるようです。

  const host = req?.headers?.host;

PR は出していますが、このリバース プロキシ環境でのデバッグ、ということ自体が想定外な気がするので、マージされるか怪しいですね。

github.com

SPA の Hot reload

SPA 用の task で、npm run serve (Webpack Dev Server でのホスティング) ではなく npm run build./dist にバンドルされた JS ファイル作成していました。
なので、SPA 側のファイルを更新しても、自動でリロードしてくれません。

当然、SPA 側を npm run serve で WebPack dev server で起動し、Static Web Apps CLInpm run swa -- start http://localhost:8080 --api=http://localhost:7071 のように実行すると Hot Relaod が可能になります。
ただし、Static Web Apps CLI の現在の動作として、Dev Server を使った場合に staticwebapp.config.json をロードしないので、認証や独自のルーティングが動きません。

github.com

Static Web Apps CLI のルーティングを改善しようとしているそうなので、それと合わせて改善されるようです。

ただ、GitHub Codespaces の場合、ちょっとした変更でもファイルは自動で保存されるので、その度に Hot Relaod が動くのもどうかと思うので、Hot Relaod ではなく都度手動で npm run build を実行する方がいい気もします。
このあたりは、ファイル保存のタイミングをコントロールできるローカル環境と違いが出る部分ですね。

以上、だいぶニッチにエントリーでした。