Next.js 15でCesiumJSをResium経由で使用する

# Next.js 15でCesiumJSを使う
Web上で地球の3D表示や3D地図の可視化が可能なCesiumJSをNext.jsでReact Componentとして扱う方法についてまとめます．

CesiumJS

https://cesium.com/platform/cesiumjs/

本来，CesiumJSはただのJavascriptライブラリでNext.jsなどに組み込んで使用したいと思うと非常に面倒な導入をしなければならないようだが，なんとこれをReact Componentとして簡単に読み込み，編集ができるReact Wrapperを作成している方がいらっしゃった！凄過ぎます．

https://qiita.com/rot/items/ca73908d91387b11e152

今回は基本的にResiumのドキュメントをなぞってプロジェクトを作成するまでの記録です．

Resium

https://resium.reearth.io/

今回は最新のNext.js 15に導入する手順について記述します．
（初学者なため，間違っている記述があると思われます．ご指摘いただけると嬉しいです．）

# 導入手順

まずはNext.jsのプロジェクト作成から
```
$ npx create-next-app my-app
$ cd my-app
```
これからResiumを導入していくんですが，そのまま`npm install`をすると依存解決エラーが発生します．
`--legacy-peer-deps`をつけましょう．

```:ResiumCesiumの導入
$ npm install --save cesium resium --legacy-peer-deps
```

次にResiumに必要な関連ファイルを自動コピーしてくれる`symlink-dir`をインストールします．ResiumはあくまでCesiumJSのReact Wrapperなので，コピーが必要なものがあるのだと思われます．

```:関連ファイルをコピー
npm install --save-dev symlink-dir --legacy-peer-deps
```
このことを`package.json`に追記しましょう．
```
{
  "scripts": {
    "postinstall": "symlink-dir node_modules/cesium/Build/Cesium public/cesium"
  }
}
```
を追記して，以下のようになっていればOKです．

```diff_json:package.json
{
  "name": "my-app15",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "postinstall": "symlink-dir node_modules/cesium/Build/Cesium public/cesium"
  },
  "dependencies": {
    "cesium": "^1.126.0",
    "next": "15.1.7",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "resium": "^1.19.0-beta.1"
  },
  "devDependencies": {
    "postcss": "^8",
    "symlink-dir": "^6.0.4",
    "tailwindcss": "^3.4.1"
  }
}

```

その後，シンボリックリンクを作成します．
```
$ npm install
```

このとき，/public/cesium内に作られるファイルをgitの管理下から外しましょう．

```.gitignore
/public/cesium
```

ここまでで導入はおしまいです．

## Component作成と使用まで
今回はAppディレクトリの下にcomponentsディレクトリを作成し，Cesium.jsファイルに以下を貼り付けます．

```
$ cd app
$ mkdir components
$ cd components
```

```app/components/Cesium.js
import { Viewer } from 'resium'

export default function Cesium() {
  return (
    <Viewer
      full
      animation={false} // アニメーションウィジェットを非表示
      timeline={false} // タイムラインウィジェットを非表示
      navigationHelpButton={false} // ナビゲーションヘルプボタンを非表示
      fullscreenButton={false} // フルスクリーンボタンを非表示
      homeButton={false} // ホームボタンを非表示
      sceneModePicker={false} // シーンモードピッカーを非表示
      baseLayerPicker={false} // ベースレイヤーピッカーを非表示
      geocoder={false} // ジオコーダー（検索）を非表示
      infoBox={false} // インフォボックスを非表示
      selectionIndicator={false} // 選択インジケーターを非表示
    />
  )
}
```
画面の操作系は，一旦非表示にしておきました．必要になったら`true`に書き換えてください．

元々作成されているapp/page.jsは
```diff_javascript:app/page.js
"use client";

import Head from 'next/head'
import dynamic from 'next/dynamic'

const Cesium = dynamic(
  () => import('./components/Cesium'),
  { ssr: false }
)

export default function Home() {
  return (
    <>
      <Head>
        <link rel="stylesheet" href="cesium/Widgets/widgets.css" />
      </Head>
      <Cesium />
    </>
  )
}
```
とします．先頭の`"use client";`はこのpage.jsをクライアントコンポーネントとして扱いますよ．という意味です．

Next.jsにはサーバーコンポーネントとクライアントコンポーネントがありますが，CesiumJSはサーバーサイドでは動作することができないので，明示的にクライアント側でのみ動作してね．と教えています．

あとは実行してみましょう．
```
$ npm run dev
```
でlocalhost:3000にアクセスすれば，
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489569/eb28ae6b-af74-528f-40dc-e08ff629b472.png)

のように小さく表示されます．

後日，見た目を整えるところまで追記する予定です．