Skip to content

Maps Core Migration Plan

niryuu edited this page Jun 2, 2026 · 1 revision

Maps-Core 置き換え可行性調査 (Migration Plan)

@geolonia/maps-core (別リポジトリ) を embed の embed-core 相当として使えるか、また embed.js 自体を thin wrapper に書き直せるかを評価する feasibility 調査の結果。

調査日: 2026-06-03 対象バージョン: embed 5.2.2, maps-core 0.4.1

参照: Codebase-Documentation / Core-vs-Wrapper / Module-Embed-Entry / URL-Rewrite-Spec / Hidden-Spec / Suspicious-Logic / Constants / E2E-for-Embed-Only-Features

1. 目的と前提

  • 目的: embed-core (lib 部分) を @geolonia/maps-core で置き換え、embed.ts (wrapper) は HTML 統合層として残す
  • 理由: lib の責務を独立リポジトリに切り出し、React wrapper など他プロジェクトと共有
  • スコープ: embed-core 相当の機能を maps-core で代替可能か。Wrapper 機能 (DOM 走査・auto-render・プラグイン) は embed 側に残す
  • 判断材料: 既存仕様 (Hidden-Spec / Suspicious-Logic / Constants) を maps-core が同等に保持しているか

2. 結論 (Executive Summary)

観点 評価
lib コア機能の互換性 高い (約 90%) — hidden-spec / constants / transformRequest はほぼ identical
wrapper 機能 (DOM / plugin) maps-core に存在しない (設計通り)。embed 側で実装維持必須
依存パッケージ gesture-handling は別パッケージ・別メジャーバージョン — Significant change
GeoloniaMap コンストラクタ シグネチャ非互換 (string CSS selector を受け付けない) — wrapper で adapter
stage 機構 build-time → runtime<script> ユーザの stage 指定運用に影響
ビルド webpack → tsup/vite — embed-core.js (UMD) 配信形態の変更検討

最終評価: 置換可能。ただし wrapper レイヤと依存解決に Significant な変更が必要。Drop-in 置換は不可で、段階移行 / adapter 必須。

3. API 表面の比較

maps-core (/tmp/maps-core/src/index.ts) の export

Export 種別 シグネチャ概要
GeoloniaMap (default) class extends maplibregl.Map { constructor(options: GeoloniaMapOptions) }
GeoloniaMarker (default) class extends maplibregl.Marker { constructor(options?: MarkerOptions) }
SimpleStyle named class constructor(geojson: string | FeatureCollection, options?)
SimpleStyleVector (default) class constructor(url: string)
keyring singleton setApiKey / setStage / reset / isGeoloniaStyleCheck (parse なし)
CustomAttributionControl (default) class (embed 側は default のみ。maps-core では named でも公開)
GeoloniaControl named class implements IControl
getLang, getStyle, isGeoloniaTilesHost functions utility (embed では util.ts に内部、maps-core は public)
GeoloniaMapOptions type extends MapOptions + apiKey, stage, style, lang, ...
coreVersion const "0.1.0"

embed-core (src/embed-core.ts) の export

Export maps-core 対応 判定
GeoloniaMap (default) GeoloniaMap API 差あり: constructor シグネチャ非互換
GeoloniaMarker (default) GeoloniaMarker △ embed は legacyOptions 引数を受ける後方互換あり
SimpleStyle (named) SimpleStyle ✓ ほぼ同等
SimpleStyleVector (default) SimpleStyleVector ✓ 同等
keyring keyring △ embed の keyring.parse(doc) が maps-core にない
registerPlugin (不在) ✗ wrapper 領域
EmbedAttributes (不在) ✗ wrapper 領域 (DOM data-* モデル)
EmbedPlugin (不在) ✗ wrapper 領域
embedVersion coreVersion △ 名前違い
GeoloniaMapOptions GeoloniaMapOptions △ 構造は近いが拡張プロパティ (apiKey, stage, lang 等) の扱いが異なる

GeoloniaMap constructor 差分 (最重要)

embed-core (src/lib/geolonia-map.ts:71):

constructor(params: string | GeoloniaMapOptions)
  • string を CSS selector として扱い、getContainer() で要素解決
  • parseAtts(container)data-* 属性を読み取って options に組み込み
  • DOM 連携の前処理を内部で完結

maps-core (/tmp/maps-core/src/lib/geolonia-map.ts):

constructor(options: GeoloniaMapOptions)
  • container は options の必須プロパティ (HTMLElement | string)
  • DOM 属性 parse なし (apiKey / stage / style 等は options で渡す)
  • pure programmatic API

→ embed 側の <div class="geolonia"> 自動 render は wrapper 層で parseAtts → options 構築 → new MapsCore.GeoloniaMap(options) の adapter が必要。

4. Hidden-Spec 同性

Hidden-Spec の 10 項目すべてについて maps-core でも実装ありを確認。

# 仕様 maps-core での場所 状態
1 3D layer metadata (visible-on-3d / hide-on-3d) src/lib/geolonia-map.ts:372-377 ✓ 同等
2 SimpleStyle GeoJSON properties 規約 src/lib/simplestyle.ts:54, simplestyle-vector.ts:120-226 ✓ 同等 (small/large radius 7/13/9 含めて identical)
3 geolonia:// protocol src/lib/util.ts:128-132, geolonia-map.ts:124-130 ✓ 同等
4 container.geoloniaMap シングルトン geolonia-map.ts:96-98, 390, 413 ✓ 同等
5 __styleExtensionLoadRequired フラグ geolonia-map.ts:55, 224, 344-347, 404 ✓ 同等
6 sanitize-html 設定 (defaults + img、全要素 class) src/lib/util.ts:168-175 ✓ 同等
7 cluster 閾値 (clusterMaxZoom: 14, clusterRadius: 50) simplestyle.ts:118-119 ✓ 同等
8 デフォルト色 (#E4402F, #ff0000) geolonia-marker.ts:10, simplestyle.ts:54 ✓ 同等
9 HTTP 402 → restricted mode geolonia-map.ts:385, util.ts:135-147 ✓ 同等
10 localIdeographFontFamily: 'sans-serif' geolonia-map.ts:184-185 ✓ 同等

判定: lib レベルの "秘伝のタレ" は完全に移植されている。

5. Suspicious-Logic 比較

Suspicious-Logic の主要項目を maps-core 側で確認。embed 側で意図不明だったロジックが maps-core でどう扱われているかの判定:

# 項目 maps-core 側 判定
1 dev stage hostname 置換 (tileserver のみ) geolonia-map.ts:138-141 ✓ 現状維持
2 isGeoloniaTilesHost whitelist util.ts:28-38 ✓ 現状維持
3 iframe permission 特例 (Codepen/JSFiddle/CodeSandbox) 不在 廃止 (wrapper 領域に移譲)
4 isGeoloniaStyleCheck 5-way 分岐 keyring.ts:39-69 ✓ 現状維持
5 IntersectionObserver / MutationObserver 不在 廃止 (wrapper 領域)
6 SimpleStyleVector の remove() 欠落 simplestyle-vector.ts:264 両方未実装
7 loader 削除 try-catch geolonia-map.ts:176 try-catch 無し (簡略化)
8 Number(atts.minZoom) === 0 || 冗長条件 不在 廃止 (parse-atts 不要のため)
9 sprite path pathParts[1] 置換 geolonia-map.ts:154-156 ✓ 現状維持
10 getSessionId グローバルキャッシュ util.ts:91-102 ✓ 現状維持 (resetSessionId() を提供)

観察: wrapper 領域に属する項目 (iframe permission、Observer、parse-atts 由来) は maps-core 側で適切に廃止。lib 内部の "怪しい" ロジック (URL 書き換え、SimpleStyleVector の listener leak) は維持されている。

6. Constants の照合

Constants の主要値を maps-core で grep 確認。

定数 embed 場所 maps-core 場所 一致
tileserver.geolonia.com util.ts:44, geolonia-map.ts:144,156 util.ts:32, geolonia-map.ts:129,139
*.tiles.geolonia.com util.ts:45 util.ts:33
tileserver-dev.geolonia.com geolonia-map.ts:157 geolonia-map.ts:141
cdn.geolonia.com/style/ util.ts:226,228,... util.ts:55, 72
api.geolonia.com geolonia-map.ts:131, keyring.ts:110 geolonia-map.ts:104,118, keyring.ts:46
geolonia/basic-v2 parse-atts.ts:30,55, util.ts geolonia-map.ts:75
geolonia-api-key クエリ keyring.ts:68 (不使用 — keyring が parse しないため) ✗ wrapper 領域
key, sessionId クエリ geolonia-map.ts:123,124,160,173 geolonia-map.ts:108-109
HTTP 402 geolonia-map.ts:361 geolonia-map.ts:385
#E4402F (marker default) parse-atts.ts:41, geolonia-marker.ts:40 geolonia-marker.ts:10
#ff0000 (cluster default) parse-atts.ts:54, simplestyle.ts:33 simplestyle.ts:54

判定: lib 内部で参照される全定数は maps-core で同等。差分は wrapper 領域 (geolonia-api-key クエリ抽出) のみ。

7. transformRequest 比較

URL-Rewrite-Spec の 5 行マトリクスを maps-core 側で全件再現確認。

# resourceType 入力 URL 出力 URL 追加 query 条件 embed maps-core
1 Source https://api.geolonia.com/* <apiUrl>/sources key, sessionId 常時 geolonia-map.ts:129-136 geolonia-map.ts:117-122
2 (任意) geolonia://tiles/{u}/{id} https://tileserver.geolonia.com/customtiles/{id}/tiles.json 常時 :139-146 :124-130
3 Source Geolonia tile host (host 置換可) key, sessionId isGeoloniaTilesHost :149-163 :131-145
4 (副処理) hostname === tileserver.geolonia.com && stage === dev tileserver-dev.geolonia.com dev only :156-158 :138-141
5 SpriteJSON/Image https://api.geolonia.com/(dev|v1)/sprites/* path[1] を stage に置換 key 常時 :164-177 :147-158
6 userTransformRequest chain (それ以外) :181-183 :161-163

判定: 全 6 分岐が完全に再現。Drop-in 互換 で、置換時に挙動差は発生しない。

8. 依存パッケージ差分

パッケージ embed maps-core severity 影響
maplibre-gl 5.19.0 固定 dep ^5.0.0 peer dep Drop-in 利用側で明示供給必須に
gesture-handling @geolonia/mbgl-gesture-handling@^1.0.15 @geolonia/maplibre-gesture-handling@^3.0.0 Significant パッケージ名 + メジャーバージョンが異なる
pmtiles ^3.0.6 ^4.4.0 Drop-in API 互換 (Protocol クラス)
@turf/center ^6.0.1 ^7.3.4 Drop-in 関数シグネチャ互換
@turf/bbox (不使用) ^7.3.4 新規追加 embed の @mapbox/geojson-extent を置換
sanitize-html ^2.8.0 ^2.17.4 Drop-in 設定互換
tinycolor2 ^1.4.1 ^1.4.1 Drop-in 完全一致
@mapbox/geojson-extent ^1.0.0 (削除) Significant maps-core では @turf/bbox を採用
@mapbox/point-geometry ^0.1.0 (削除) Low embed の maplibre-util.ts のみで使用、不要化可

gesture-handling の影響: パッケージ名が変わったため、embed が @geolonia/mbgl-gesture-handling v1 と直接依存している箇所 (geolonia-map.ts:17) の import を maps-core 側 (内部で v3 を使う) に委譲する必要あり。wrapper では gesture-handling を直接触らない設計が望ましい。

9. ビルド構成と stage 機構

項目 embed maps-core
ビルダー webpack 5 tsup (ESM/CJS) + vite (UMD)
エントリ embed.ts (UMD), embed-core.ts (UMD) 2 つ index.ts (ESM/CJS + UMD) 1 つ
stage 切替 DefinePlugin で process.env.MAP_PLATFORM_STAGE静的置換 runtime に keyring.setStage() または options.stage動的設定
UMD グローバル geoloniaEmbed, geoloniaEmbedCore GeoloniaMapsCore (vite.umd.config.ts)

stage 機構の影響:

  • embed の <script src="...embed-core.js"> 利用者は、ビルド時に MAP_PLATFORM_STAGE=v1 が埋め込まれた前提
  • maps-core では runtime で stage を決めるため、script 経由で読み込んだ場合の stage 指定方法が変わる
  • wrapper 層で script 経由の ?geolonia-api-key= のような stage パラメータ取得を実装する必要

10. wrapper 機能 (embed 残置部分)

E2E-for-Embed-Only-Features で挙げた wrapper 専用機能 (8 つ) は maps-core 側には存在しない (これは設計通り)。embed 側で必須:

  • window.geolonia 公開、window.maplibregl / mapboxgl 後方互換
  • renderGeoloniaMap() 自動実行 (script タグ読込で発火)
  • DOM 走査 (.geolonia クラス)
  • data-lazy-loading + IntersectionObserver
  • MutationObserver による cleanup
  • DOMContentLoaded 待ち + プラグインキュー (registerPlugin)
  • iframe 許可チェック (checkPermission)
  • EmbedAttributes 型と parseAtts (HTML data-* → options 変換)

keyring.parse(document) (script tag scan) も embed 側で実装維持する必要あり (maps-core は parse メソッドを持たない)。

11. 移行戦略 (3 案)

案 A: 完全置換 (一気に rewrite)

  • embed.ts を thin wrapper に書き直し、@geolonia/maps-core を依存に追加
  • lib/geolonia-map.ts 等を全削除、代わりに maps-core の GeoloniaMap を import
  • wrapper 機能 (render.ts, parse-atts.ts, registerPlugin) のみ残す
  • adapter: new MapsCore.GeoloniaMap({container, ...parseAtts(container)}) の形で呼び出し

利点: クリーン、長期的に保守性 ◎ リスク: 一度にすべてが壊れる可能性。E2E でカバーしきれない挙動が漏れる 前提: E2E-Plan の Phase 1〜4 すべてマージ済みであること (現状 PR0 のみ)

案 B: 段階移行 (adapter)

  • embed-core.ts の各 export を内部で maps-core に委譲する adapter に変換
  • 例: class GeoloniaMap extends MapsCore.GeoloniaMap { constructor(params) { ... parseAtts ... super(options) } }
  • 1 モジュールずつ移行、各 PR で挙動互換性を E2E で検証
  • 最後に lib/ の旧実装を削除

利点: 段階的に検証可能、ロールバックしやすい リスク: 一時的に embed と maps-core 両方のコードが並存 (保守負担) 前提: 既存テストカバレッジが必要 (E2E-Plan で拡充中)

案 C: embed-core 廃止 + embed 経由のみ

  • embed-core.js (UMD) の公開を deprecate
  • @geolonia/embed/core import path も deprecate
  • embed.js (フル wrapper) のみ提供、内部実装は maps-core
  • 既存の embed-core 利用者は直接 @geolonia/maps-core に移行を促す

利点: 維持対象が embed.ts と wrapper のみで最小 リスク: 既存 embed-core ユーザ (React wrapper 等) に breaking change 前提: embed-core の外部利用者の確認・周知

12. 推奨パス

E2E-Plan Phase 1〜2 完了後に案 B (段階移行) を推奨。

理由:

  • Phase 2 完了時点で data-* 属性、コントロール、認証、SimpleStyle の E2E が揃う → 移行時の回帰検知が可能
  • 案 A はリスク大、案 C は breaking change が大
  • 段階移行で各モジュール (Module-GeoloniaMap, Module-SimpleStyle 等) を 1 PR ずつ置換することで、レビューと検証が現実的なサイズに

具体の順序案 (各 PR は umbrella issue にぶら下げる):

  1. simplestyle-vector を maps-core に委譲 (依存が少ない、リーフモジュール)
  2. geolonia-marker を maps-core に委譲
  3. CustomAttributionControl + GeoloniaControl を maps-core に委譲
  4. keyring を maps-core に委譲 (ただし parse(document) ロジックは embed 側に新設)
  5. util.ts の utility 関数を maps-core 経由に
  6. simplestyle を maps-core に委譲
  7. geolonia-map 本体を maps-core extends に書き換え (最大の変更)
  8. embed-core.ts 全体を re-export 化、または deprecate

各 PR で:

13. 主要リスク

  1. gesture-handling パッケージ移行: v1 → v3 で API breaking change の可能性。CHANGELOG 確認必要
  2. stage 機構の runtime 化: <script src="embed.js?geolonia-api-key=..."> の URL parameter から stage を推定する仕組みを wrapper に新設する必要
  3. GeoloniaMap constructor の adapter: 既存ユーザが new geolonia.Map('#map') 形式で呼ぶケースを wrapper で吸収
  4. UMD グローバル名の差: embed.js は geoloniaEmbed を維持、内部の maps-core は別グローバル
  5. window.maplibregl / mapboxgl 後方互換: maps-core にない (embed.ts のみで定義)。維持するなら wrapper で
  6. registerPlugin の plugin 引数 atts: maps-core では options ベースなので、互換性のため EmbedAttributes 経由で渡し続ける必要
  7. SimpleStyleVector.remove() 欠落: 両方未実装。maps-core 側で先に追加する PR を出すか、wrapper でラップ

14. 検証戦略

E2E-Plan + E2E-for-Embed-Only-Features に加え、移行特有の検証:

  • 回帰テスト: 各段階で全 E2E green
  • Hidden-Spec チェックリスト: 10 項目を移植先で都度確認
  • URL-Rewrite-Spec のテーブル全行: マトリクスを E2E でカバー (E2E-Plan PR2a 認証参照)
  • stage 切替の E2E: dev / v1 両方で API key が正しく injected されるか
  • gesture-handling: scroll-handling の挙動回帰テスト

15. 関連 Wiki ページ

16. 次のアクション

  1. gesture-handling の API 差分調査 (v1 → v3 の breaking change を CHANGELOG で確認)
  2. maps-core 側の SimpleStyleVector.remove() 追加 (maps-core PR として提案)
  3. stage 機構の wrapper 側設計 (script タグの URL から stage 推定する仕組み案)
  4. E2E-Plan Phase 1 着手 (PR1a 以降を進める。移行の前提条件)
  5. 本ドキュメントを embed リポジトリの issue として起票 (議論の台に乗せる)

Clone this wiki locally