はじめに
以下の投稿では SvelteKit と Leaflet を使った地図アプリを作成しました。
本番配備バージョンでちゃんと動くか確認してみました。
まずは、ビルドしてから 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
以下のファイルを作成します。
export const ssr = false;
これで地図が表示されるようになりました。
別の問題
別の問題の原因
マーカーのHTML要素はこのようになっていました。
<img src="marker-icon.png"/>
marker-icon.png
という存在していないファイルを参照しているのが原因です。
別の問題の解決方法
いろいろ調べましたが、Leaflet の画像ファイルを static
ディレクトリ内にコピーするのが簡単でした。(ChatGPT に教えてもらいました)
-
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 © <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
で軽く動作確認すると良いと思います。