Three.jsのWebGPURendererをVite環境で使えない問題を解決する

## 環境について
Vite 5.4.0
Three.js r167
（↑`three.webgpu.js` と `three.webgpu.min.js` のビルドが追加されたバージョン）
https://github.com/mrdoob/three.js/releases

## 遭遇した問題
Vite環境にて、Three.jsで `WebGPURenderer` を使用した際に、以下のエラー文に遭遇しました。

![スクリーンショット 2024-08-12 17.51.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331211/a5d182d2-2088-bf45-5d04-a4e261afc83b.png)

```
 [ERROR] Top-level await is not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides)

    node_modules/three/build/three.webgpu.js:36252:15:
      36252 │   isAvailable = await navigator.gpu.requestAdapter();
```

`WebGPURenderer` のインスタンスを生成した際のコードを以下に抜粋します。

```javascript
import * as THREE from "three";
import { WebGPURenderer } from "three/webgpu";

const renderer = new WebGPURenderer({
  canvas: document.querySelector('#myCanvas')
});
```

WebGPUを実際にガッツリ活用する際には `WebGPURenderer` のみをインポートすることはないだろうけど、サンプルということでご容赦を。

## 解決した方法

`vite.config.js` に以下を記述することで解決しました。

```javascript
import { defineConfig } from 'vite'

export default defineConfig({
    build: {
        target: 'esnext',
    },
    optimizeDeps: {
        esbuildOptions: {
            target: 'esnext',
        },
    },
});
```

TypeScript環境の方は、他にもランタイムやビルド時にエラーが起きるそうです。
以下を参照。
https://scrapbox.io/0b5vr/Vite%E3%81%A7Three.js%E3%81%AEWebGPURenderer%E3%81%8C%E4%BD%BF%E3%81%88%E3%81%AA%E3%81%84

本題はここまで。

## （補足1） Top-level await について

![スクリーンショット 2024-08-12 17.51.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331211/a5d182d2-2088-bf45-5d04-a4e261afc83b.png)

エラー文に出現していた `Top-level await` についての解説です。

`Top-level await` は新しい機能（ES2022 で導入）であり、await 式が async 関数の外側で使えるようになる機能です。
詳しくは以下のリンクを参照。
https://www.tohoho-web.com/ex/es2022.html#top-level-await

`WebGPURenderer` の実装に、`Top-level await` が使われていましたが、Viteのデフォルト設定だと、ビルドターゲット環境がES2022に対応したものではありませんでした。

そこで、 `vite.config.js` を編集して、ビルドターゲットを変更してあげる必要があったわけです。

## （補足2） Vite の defineConfig について

```javascript
import { defineConfig } from 'vite'

export default defineConfig({
    build: {
        target: 'esnext',
    },
    optimizeDeps: {
        esbuildOptions: {
            target: 'esnext',
        },
    },
});
```

`defineConfig` はIDEに自動補完を提供してくれます。
以下にVSCode環境における、自動補完表示の例を示します。

![スクリーンショット 2024-08-12 18.53.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331211/6ffc4b4c-088f-d855-35df-d664b7e7eb0a.png)
↑こちらは `defineConfig` を使わない場合に、 `build.target` のところをマウスホバーした際の表示。型表示のみ。

![スクリーンショット 2024-08-12 18.53.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331211/1a104651-c9c7-99d9-6970-1701d4e0b3bb.png)
↑こちらは `defineConfig` を使った場合に、 `build.target` のところをマウスホバーした際の表示。プロパティに関する詳細情報が記述される。


TypeScript環境の場合は、別の方法で自動補完を利用することが可能なので、詳しくはViteの公式ドキュメントを参照。
https://ja.vitejs.dev/config/

## （補足3） Vite のビルドオプションについて

https://ja.vitejs.dev/config/build-options#build-target

`build.target` のプロパティには、 `esnext` という値があります。
これはネイディブの動的インポートをサポートしていることを前提としており、トランスパイルが可能な限り少なくなります。
具体的には、ミニフィケーションの互換性を担保するトランスパイルのみを実行するようです。
デフォルトは `modules` という値が設定されており、 `ES2022` を想定しないブラウザでの利用を想定したトランスパイルになります。

なぜ `esnext` に設定しているのが、 `build.target` だけではなく、 `optimizeDeps.esbuildOptions.target` にもあるのかは、こちらのViteのIssueを参照。

https://github.com/vitejs/vite/issues/13756

## （補足4） Vite のビルドターゲットを変えずに Top-level await をサポートする方法

このプラグインを使いましょう。
READMEを参照。

https://github.com/Menci/vite-plugin-top-level-await