作成済のAzure Static Web Apps に Azure DevOps からデプロイしたメモ

## 概要
クイックスタートだとgithub actionsでのデプロイだった。
同等のことをAzure DevOpsで行う。

## デプロイ対象の準備
[クイックスタート: Azure Static Web Apps を使用して静的サイトを初めて構築する](https://learn.microsoft.com/ja-jp/azure/static-web-apps/getting-started?tabs=vanilla-javascript)で使用されている[React Starter](https://github.com/new?template_name=react-basic&template_owner=staticwebdev)をデプロイすることとする。

Cloneしてきたコードを、AzureDevOpsのリポジトリとして登録する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/29344012-d7a8-55e3-67c3-86ec2b393b67.png)

なお、この手順で紹介されている[Azure Static Web Apps for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurestaticwebapps)は手順通りのGitHubではうまく行ったが、DevOpsで同様のことをやろうとしたら`URL parsing failed`といわれてしまった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/36813673-519f-747a-bad7-2a1c41c27209.png)

## Azure Static Web Appsの作成
[クイック スタート: 静的 Web アプリを初めてビルドする](https://learn.microsoft.com/ja-jp/azure/static-web-apps/get-started-portal?tabs=vanilla-javascript&pivots=azure-devops)で「コードホスティング プラットフォームを選択する」のDevOpsを選択

「静的 Web アプリを作成する」の`[Review + create](レビュー + 作成) を選択します。`の直前まで作業を進める。デプロイはパイプラインからやりたいので。

### デプロイトークンの取得
作成されたAzure Static Web Appsをポータルから開き、
パイプラインの環境変数に設定するためのトークンを取得する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/79de9556-f1e3-47ee-a846-74aed74c33f1.png)


## パイプラインからのデプロイ
### パイプライン用ファイルの作成
デプロイ用のファイルを作成する。
コミットしてプッシュしておく。

```yml:azure-pipelines.yaml
trigger:
  - main
pool:
  vmImage: ubuntu-latest
steps:
  - task: AzureStaticWebApp@0
    name: DeployStaticWebApp
    displayName: Deploy Static Web App
    inputs:
      app_location: /
      output_location: build
    env:
      azure_static_web_apps_api_token: $(deployment_token)
```

### パイプラインの設定

Azure Dev Opsのパイプラインを新規作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/0f53ecda-9899-d495-e09f-ffe660279b48.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/3524042b-34b1-62b2-a272-d689f3943f8c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/65cc5d37-5b6e-76c2-06f8-ffaabf7bd821.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/6be45524-1654-c65a-8fbc-9acb39d9a623.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/a0279680-8fe9-2a5b-751b-2c8b5abbcc3e.png)

#### 環境変数の設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/38cf6852-9179-7fd7-8b34-faa70856c464.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/1a7cac05-542f-7faa-591a-4bc073c05e84.png)

`deployment_token`にAzure Static Web Appsから取得したデプロイトークンを設定する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/acc3f316-91b2-bdf6-8acc-fd0d5031005b.png)

#### パイプラインの実行

以上で設定は完了。パイプラインからデプロイができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/f423e509-a2dc-a0b6-2b83-aeb341866c7a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/c5c65a4a-25cc-74f2-bf0e-9c9fbdfc7fc3.png)

## Unsupported engineのWARNが出る件への対応

```
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: 'rollup@4.14.0',
npm WARN EBADENGINE   required: { node: '>=18.0.0', npm: '>=8.0.0' },
npm WARN EBADENGINE   current: { node: 'v16.20.2', npm: '8.19.4' }
npm WARN EBADENGINE }

```

[Node.js環境で発生する”npm WARN EBADENGINE Unsupported engine”を解決したい](https://dev.classmethod.jp/articles/resolve-npm-warn-ebadengine-unsupported-engine-that-occurs-in-npm-environment/)によると、Nodeのバージョンの問題の模様。

> Eslint周りのモジュールが要求するNodeバージョンを現在の環境が満たしていないようです。

package.jsonにenginesの設定をすることでNodeのバージョンを設定できる。
[Azure Static Web Apps でサポートされている言語とランタイム > フロントエンド](https://learn.microsoft.com/ja-jp/azure/static-web-apps/languages-runtimes#front-end)

```diff:package.json
{
  "version": "0.0.1",
+  "engines": {
+    "node": ">=18.x"
+  },
```
## APIのデプロイ

```ts:api/src/functions/httpTrigger1.ts
import {
  app,
  HttpRequest,
  HttpResponseInit,
  InvocationContext,
} from '@azure/functions';
import { format } from 'date-fns';

export async function httpTrigger1(
  request: HttpRequest,
  context: InvocationContext,
): Promise<HttpResponseInit> {
  context.log(`Http function processed request for url "${request.url}"`);

  const name = request.query.get('name') || (await request.text()) || 'world';
  const time = format(new Date(), 'yyyy-MM-dd: HH:mm:ss');
  return { body: JSON.stringify({ msg: `Hello, ${name}!`, time }) };
}

app.http('httpTrigger1', {
  methods: ['GET', 'POST'],
  authLevel: 'anonymous',
  handler: httpTrigger1,
});

```

```json:api/package.json
{
  "name": "api",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "clean": "rimraf dist",
    "prestart": "npm run clean && npm run build",
    "start": "func start",
    "test": "echo \"No tests yet...\""
  },
  "dependencies": {
    "@azure/functions": "^4.4.0",
    "date-fns": "^3.6.0"
  },
  "devDependencies": {
    "@types/node": "^20.x",
    "rimraf": "^5.0.5",
    "typescript": "^5.4.4"
  },
  "main": "dist/src/functions/*.js"
}
```

```diff:azure-pipelines.yaml
trigger:
  - main
pool:
  vmImage: ubuntu-latest
steps:
  - task: AzureStaticWebApp@0
    name: DeployStaticWebApp
    displayName: Deploy Static Web App
    inputs:
      app_location: /
      output_location: build
+      api_location: api
    env:
      azure_static_web_apps_api_token: $(deployment_token)
```

## 2024.05.05 追記

[パイプラインを使わない方法](https://qiita.com/hibohiboo/items/6b88b12f032e9d9f5307)


## 参考

[Azure Static Web Apps が Azure DevOps からデプロイできるようになった](https://qiita.com/miyake/items/6ed1abe46fcd6d62fc17)
[AzureStaticWebApp@0 - Azure Static Web App v0 タスクをデプロイする](https://learn.microsoft.com/ja-jp/azure/devops/pipelines/tasks/reference/azure-static-web-app-v0?view=azure-pipelines)
[Azure Static Web Apps のビルド構成](https://learn.microsoft.com/ja-jp/azure/static-web-apps/build-configuration?tabs=github-actions)