Flutter Web、Vercelにもデプロイできたことを最近知った

# 概要
2025年に入ってからFlutterに取り組む日を増やしています。

現在、Androidのアプリケーション作成を行っています。
並行して、Androidアプリケーションの一部機能作成のために、Web用のプロジェクトを別途作成して作業を進めています。


久しぶりにNext.jsを触ろうかと思いもしましたが、Flutter Webでどこまでできるか確かめてみる目的もあり、Webサイト側もFlutterで作成を進めています。
デプロイ先について少し考えるタイミングがあり、Next.jsを使って作成するというのも候補にあったため、
Next.jsであれば、Vercelにデプロイしているけど、Flutterはできるのかな？？と思ったときがあったので、調べてみました。
また、ただ記事に沿ってデプロイだけではもったいないので、
ついでにVercelの設定ファイルを作成して、デプロイ構成する方法も併せて学習してみました。

## 対象の読者
以下の方々に向けた内容ではありますが、難しい話はしていないので、気軽に読んでいただければと思っています。
- FlutterのWebプロジェクトを開発されている方
- FlutterのWebプロジェクトをVercelにデプロイしてみたい方
- Vercelへのデプロイ設定をファイルベースで行いたい方

## Firebase Hosting
Flutter WEbで何か作成をしてみて、どこかにデプロイするために、
「Flutter Web デプロイ」とネットで検索をすると思います。

やっていただくと分かりますが、デプロイ先として、`Firebase Hosting`を上げている記事が大半です。
開発元がGoogleさんですから、当然公式ページでもそのように記載されています。

https://docs.flutter.dev/deployment/web

## Vercelでデプロイ
今回の本題です。Vercelについては、フロントエンドの開発経験がある方はご存知かと思います。

https://vercel.com/enoconans-projects

Vercel上にデプロイすることですが、
**私が認知していなかっただけで2年以上前の記事もありました。**

https://itnext.io/deploy-flutter-web-app-on-vercel-in-120-seconds-flutter-bytes-6e95a6e52b62

上記記事を参考にして、コマンドを設定しました。
今回の私の場合は、デフォルトのプロジェクトからいくつか修正を加えています。
- `supabase_flutter`の利用
- `envied`と`envied_generator`、`build_runner`による環境変数情報の生成

参考記事の通りに設定を行いデプロイしました。すると、エラーで失敗に終わりました。
ライブラリがインストールされていない、ということですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/345414/383575a4-5c41-41f5-b353-2b1313016d57.png)

記事のコマンドですが
`flutter clean`後に、`flutter pub get`をしていません。
なぜこれで成功するのか気になりました。（他の記事もいくつか確認しましたが、同じでした。）

とりあえず、`flutter pub get`を追加しました。
また、`build_runner`を用いたファイル生成のコマンドも必要なので、追加しました。

最終的には、それぞれ以下の通りです。

##### Build command
```shell
flutter/bin/flutter pub get && flutter/bin/dart run build_runner build --delete-conflicting-outputs && flutter/bin/flutter build web --release --wasm
```
##### Output directory
```shell
build/web
```
##### Install command
```shell
if cd flutter; then git pull && cd .. ; else git clone -b stable https://github.com/flutter/flutter.git; fi && ls && flutter/bin/flutter doctor && flutter/bin/flutter clean && flutter/bin/flutter config --enable-web
```

最初、`flutter/bin/flutter pub get`を**Install command**コマンド側に記載してましたが、
保存しようとすると、以下エラーが表示されました。

> If defined, the Install Command must have a maximum length of 256 characters.

`git clone`の処理から記載している関係で、最低限必要な処理を記述するだけでも、ある程度の文字数は使っているので、こういう事象も起こるんですね。
（React,Nextのときは見たことがなかったため。）

#### デプロイ完了
Vercelのコンソールを確認しました。
軽いプロジェクトであれば、5分前後で完了しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/345414/53f17f6c-a6ed-4585-a987-e059a0a15751.png)

ブラウザ上でアクセスしてみると、表示できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/345414/2177f646-b9b1-4e24-8a12-5b1debe58f2b.png)

## ビルド方法
`Build command`の最後に記載した、実際にビルドを行うコマンドについて、最後に`--wasm`と記載しています。
そこまで最近ではないですが、Flutter`3.24`以降で利用できるようになったビルド方法です。
```
flutter/bin/flutter build web --release --wasm
```

**現在はベータ版**、の扱いのようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/345414/1655a64c-87df-4c2d-8270-0ee276815b82.png)

#### WebAssembly

https://docs.flutter.dev/platform-integration/web/wasm

https://webassembly.org/

WebAssemblyの記事でもないので、サラッと記載しますが、以下4つをトップページで掲げています。
- Efficient and fast
- Safe
- Open and debuggable
- Part of the open web platform

#### Skwasmとcanvaskit

https://docs.flutter.dev/platform-integration/web/renderers

公式ドキュメントを参照すると、以下のように記載されています。

> Flutter web offers two build modes, and two renderers. The two build modes are the default and WebAssembly, and the two renderers are canvaskit and skwasm.

> Flutter chooses the build mode when building the app, and determines which renderers are available at runtime.

> For a default build, Flutter chooses the canvaskit renderer at runtime. For a WebAssembly build, **Flutter chooses the skwasm renderer at runtime, and falls back to canvaskit if the browser doesn't support skwasm.**

太字部分の通り、
ブラウザが`skwasm`をサポートしていない場合は、`canvaskit`を採用する仕組みです。
MDNのサイトに
「ブラウザ互換性」という箇所があり、そちらに対応状況が記載されていました。

https://developer.mozilla.org/en-US/docs/WebAssembly#browser_compatibility

> **canvaskit**
> The canvaskit renderer is compatible with all modern browsers, and is the renderer that is used in the default build mode.
> It includes a copy of Skia compiled to WebAssembly, which adds about 1.5MB in download size.

> **skwasm**
> The skwasm renderer is a more compact version of Skia that is compiled to WebAssembly and supports rendering on a separate thread.

一番わかりやすい違いは、コンパイル後のサイズが`skwasm`の方が小さく抑えられる、ということでした。

#### HMTL Renderer
これまでの古いレンダリング方法について、非推奨のままであれば記載しなくていいと思っていましたが、
先日の3.29のバージョンアップで、ついに**廃止**となりました。
以下は、非推奨、という情報が記載されていた記事です。

https://docs.google.com/document/d/1DGamHsa2lz_Qtgfrfa3j3fRaEopJXc7tCFVM1TQlck8/edit?resourcekey=0-IjkqrCoo_EcRRS2bPYKI8w&tab=t.0

**Problem for end users（エンドユーザーにとっての問題）**
> End users expect that Flutter Web apps load fast, run smoothly, are of high quality, and do not have bugs.

> Apps that use the HTML renderer frequently have lower visual quality, and are inconsistent with other platforms due to HTML having to approximate/emulate certain features that other Flutter renderers can implement directly and at high quality (e.g. gradients, text layout, pixel shaders).

[和訳]
- 視覚的な品質が低くなることが多い
- 他のプラットフォームとの一貫性に欠ける
⇒ HTMLが他のFlutterレンダラーが直接高品質に実装できる特定の機能（グラデーション、テキストレイアウト、ピクセルシェーダーなど）を近似/エミュレートする必要があるためです。

## jsonファイルを通じた各コマンドの設定
Vercelのプロジェクトを削除した場合に、上記の3項目（Build command、Output directory、Install command）は消えてしまいます。
ファイル管理していれば、そういったアクシデントにも左右されませんし、
後に同じことをやりたいときに楽なので、ここで取り組んでおきます。

以下リンクが公式ドキュメントです。

https://vercel.com/docs/projects/project-configuration

やることは非常にシンプルです。
- プロジェクトのルートディレクトリに`vercel.json`を作成
- `framework`には`null`を設定
- 最初に設定したコマンドをコピペし、それぞれのキー（`buildCommand`,`outputDirectory`,`installCommand`）に対して貼り付け
```json
{
    "framework": null,
    "buildCommand": "flutter/bin/flutter pub get && flutter/bin/dart run build_runner build --delete-conflicting-outputs && flutter/bin/flutter build web --release --wasm",
    "outputDirectory": "build/web",
    "installCommand": "if cd flutter; then git pull && cd .. ; else git clone -b stable https://github.com/flutter/flutter.git; fi && ls && flutter/bin/flutter doctor && flutter/bin/flutter clean && flutter/bin/flutter config --enable-web"
  }
```

合わせて、
プロジェクトの`Build & Development Settings`を初期状態に戻します。
（ファイルの記載内容でデプロイ処理を実施していることを確認するため。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/345414/b68a5392-26cf-4929-97ff-58a8d03a864e.png)

#### 再デプロイ完了
再度デプロイが完了しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/345414/00d2f4b9-8c1d-4592-9e01-23d66d52d2d5.png)

## まとめ
Flutter WebでVercelにデプロイする方法、そしてVercelのjsonファイルを利用したデプロイ方法について記載してきました。
中盤で紹介したビルド方法について、詳しい仕組みを理解するには時間がかかりそうですが、機を見つけてやってみたいと思います。

## 参考記事
記事を書くにあたって、参考にさせていただいた記事一覧です。

https://flutter.salon/what-is-new/whats-new-in-flutter-3-29/

https://bema.jp/articles/20241025/

https://medium.com/@kashif00527/wasm-flutter-web-a-comprehensive-guide-7eb65df07021