SvelteKit + Leaflet で preview したらちゃんと動かなかったので修正した話

# はじめに

以下の投稿では [SvelteKit] と [Leaflet] を使った地図アプリを作成しました。

https://qiita.com/fsd-tetsu/items/a2c0fc3ec2b228fab621

本番配備バージョンでちゃんと動くか確認してみました。
まずは、ビルドしてから `preview` を実行します。
```:ターミナル
npm run build
npm run preview -- --host 127.0.0.1
```

そしてブラウザでアクセスしてみると、こんなエラーが表示されます。

```:ターミナル
/～～～/node_modules/leaflet/dist/leaflet-src.js:230
  var requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer;
                  ^

ReferenceError: window is not defined
    at /workspaces/relics-map-svelte/node_modules/leaflet/dist/leaflet-src.js:230:19
    at /workspaces/relics-map-svelte/node_modules/leaflet/dist/leaflet-src.js:7:66
    at Object.<anonymous> (/workspaces/relics-map-svelte/node_modules/leaflet/dist/leaflet-src.js:10:3)
    at Module._compile (node:internal/modules/cjs/loader:1275:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1329:10)
    at Module.load (node:internal/modules/cjs/loader:1133:32)
    at Module._load (node:internal/modules/cjs/loader:972:12)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:168:29)
    at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
```

# 何が原因か？

`window` というオブジェクが存在しないってことですね。どうやら [Leaflet] の対象箇所がサーバーサイドで実行されているみたいです。

# 解決方法

SSR(Server Side Rendering)を強制的にOFFにすることでエラーが発生しなくなりました。
参考:https://kit.svelte.dev/docs/page-options#ssr

以下のファイルを作成します。

```js:src/routes/+page.js
export const ssr = false;
```

これで地図が表示されるようになりました。

# 別の問題

マーカーのアイコンが表示されなくなってしまいました。:disappointed_relieved:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2773745/67983af6-5467-af33-1be7-d11de0c00d1f.png)

# 別の問題の原因

マーカーのHTML要素はこのようになっていました。
```html
<img src="marker-icon.png"/>
```

`marker-icon.png` という存在していないファイルを参照しているのが原因です。

# 別の問題の解決方法

いろいろ調べましたが、[Leaflet] の画像ファイルを `static` ディレクトリ内にコピーするのが簡単でした。(ChatGPT に教えてもらいました:sweat_smile:)

1. `node_modules` ディレクトリ内の `leaflet` ディレクトリから以下のファイルをコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2773745/c66ad01a-ba32-cbc0-8427-50d0246dfa87.png)

2. コピーしたファイルを `static/images/leaflet` ディレクトリ内に張り付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2773745/fcd64df1-c449-b864-abe6-5c9cd0492717.png)

3. `src/routes/+Map.svelte` で画像ファイルのパスを修正します。
```diff_html:src/routes/+Map.svelte
<script>
  import { onMount } from 'svelte';
  import L from 'leaflet';
  import artifacts from './artifacts.json';
  import css from 'leaflet/dist/leaflet.css';

  let map;

  onMount(() => {
+    L.Icon.Default.imagePath = '/images/leaflet/';
    map = L.map('map').setView([35.658068, 139.751599], 13);
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors',
      maxZoom: 18,
    }).addTo(map);

    artifacts.forEach(artifact => {
      const { name, description, lat, lng } = artifact;
      const marker = L.marker([lat, lng]).addTo(map);
      marker.bindPopup(`<h3>${name}</h3><p>${description}</p>`);
    });
  });
</script>

<div id="map" style="height: 100vh;"></div>
```


`npm run build` と `npm run preview -- --host 127.0.0.1` を実行しブラウザで表示したところ、マーカーのアイコンが表示されました。

# まとめ

[SvelteKit] は便利ではありますが、本番環境で稼働させようとするといろいろ対応が必要になることが分かりました。おそらく [Leaflet]に限った話ではないと思われます。

[SvelteKit] で開発する際は、コミットする前に `npm run preview` で軽く動作確認すると良いと思います。:smiley:

[SvelteKit]:https://kit.svelte.dev/
[Leaflet]:https://leafletjs.com/