Skip to content
niryuu edited this page May 25, 2026 · 1 revision

embed-core 分離方針 — lib (maps-core) と wrapper (embed) の境界

このドキュメントは embed-core を独立ライブラリ maps-core として分離し、embed 本体を thin wrapper として書き直す前提で、現状の責務をどう分解するかを記録する。

前提と方針

  • maps-core は React wrapper や他のプロジェクトからも利用される汎用 lib になる
  • embed (フル版) は HTML 宣言的利用 (<div class="geolonia">) と後方互換のためのグローバル登録を担う
  • 分離後も現状の挙動を完全に再現する。new code でも全 hidden-spec / suspicious-logic 項目を意識する

現状の境界 (2 エントリポイント)

src/embed.ts (フル) が import するもの

import * as maplibregl from 'maplibre-gl';
import GeoloniaMap from './lib/geolonia-map';
import GeoloniaMarker from './lib/geolonia-marker';
import { SimpleStyle } from './lib/simplestyle';
import { VERSION as embedVersion } from './version';
import { registerPlugin, renderGeoloniaMap } from './lib/render';
import type { EmbedPlugin } from './types';

embed.ts のみが行う処理:

  1. window.geolonia = Object.assign(...) でグローバル登録 (maplibregl + 拡張)
  2. window.maplibregl = window.mapboxgl = window.geolonia 後方互換
  3. renderGeoloniaMap() 呼び出し
  4. Geolonia 型エクスポート

src/embed-core.ts (副作用なし) が import するもの

import maplibregl from 'maplibre-gl';
import { Protocol } from 'pmtiles';
export { default as GeoloniaMap } from './lib/geolonia-map';
export { default as GeoloniaMarker } from './lib/geolonia-marker';
export { SimpleStyle } from './lib/simplestyle';
export { default as SimpleStyleVector } from './lib/simplestyle-vector';
export { keyring } from './lib/keyring';
export { registerPlugin } from './lib/render';
export { VERSION as embedVersion } from './version';

embed-core.ts のみが行う処理:

  1. import 時 (module top-level) に maplibregl.addProtocol('pmtiles', protocol.tile) 実行

両者の差: embed.ts は window.* 設定と auto-render を伴う、embed-core.ts はそれを伴わない (pmtiles 登録のみ自動)。

共通 export

  • GeoloniaMap, GeoloniaMarker, SimpleStyle, registerPlugin, embedVersion
  • 型: EmbedAttributes, EmbedPlugin, GeoloniaMapOptions

embed-core にしか無い export

  • SimpleStyleVector (named export)
  • keyring (シングルトン)

これらは embed.ts でも export 可能だが、現状の embed.ts が忘れている可能性が高い (SimpleStyleVector は意図的に隠している? 詳細不明)。

embed.ts にしか無い export

  • geolonia (シングルトンインスタンス)
  • Geolonia
  • Popup 型 alias

書き直し後の境界 (想定)

maps-core (lib) 側に置くもの

シンボル / モジュール 現在の場所 移行先での扱い
GeoloniaMap クラス lib/geolonia-map.ts そのまま maps-core に
GeoloniaMarker クラス lib/geolonia-marker.ts そのまま maps-core に
SimpleStyle クラス lib/simplestyle.ts そのまま maps-core に
SimpleStyleVector クラス lib/simplestyle-vector.ts そのまま maps-core に。remove() 追加検討
GeoloniaControl lib/controls/geolonia-control.ts maps-core に
CustomAttributionControl lib/CustomAttributionControl.ts maps-core に
keyring シングルトン lib/keyring.ts maps-core に (parse 関数の引数化を検討)
util の pure 関数 (isURL, getStyle, isGeoloniaTilesHost, parseControlOption, parseSimpleVector) lib/util.ts maps-core に分割
getSessionId lib/util.ts maps-core に (グローバルキャッシュの扱い要検討)
EmbedAttributes, EmbedPlugin, GeoloniaMapOptions types.ts, lib/geolonia-map.ts maps-core に
pmtiles プロトコル登録 embed-core.ts:11-12 (import 時)、render.ts:13-14 (renderGeoloniaMap 内) maps-core の init() 等で明示的に行う or import 時の副作用維持

embed (wrapper) 側に残すもの

シンボル / モジュール 現在の場所 移行先での扱い
renderGeoloniaMap (DOM 走査) lib/render.ts wrapper 側
registerPlugin & plugins 配列 lib/render.ts wrapper 側
MutationObserver / IntersectionObserver の lifecycle 管理 lib/render.ts wrapper 側
checkPermission (iframe 許可) lib/util.ts wrapper 側 (DOM/window 依存)
parseAtts の DOM 走査部分 lib/parse-atts.ts wrapper 側 (data-* スプレッドのみ wrapper、残りは lib に分離可)
window.geolonia / window.maplibregl / window.mapboxgl 登録 embed.ts:47 wrapper 側
Geolonia 型 (window.geolonia 型) embed.ts:20-28 wrapper 側
handleErrorMode / handleRestrictedMode の DOM 操作 lib/util.ts wrapper 側 (DOM 依存だが、map と一体なので議論余地)

議論が必要なもの

項目 議論点
container.geoloniaMap シングルトンキャッシュ maps-core 側で持つと React 等で扱いづらい (DOM 要素にプロパティ生やすため)。WeakMap で外部管理する案
keyring シングルトン lib 側だが、自動 parse (parse() 引数なし呼び出し) は document 依存 → wrapper 側で parse して結果を渡す形が望ましい
sessionId のモジュールスコープキャッシュ lib 側に置くとマルチインスタンス (e.g. micro-frontend) で問題。pure 関数化 + 呼び出し側でキャッシュ管理する案
MAP_PLATFORM_STAGE の build-time 定数 lib として複数環境対応するならランタイム可変化が必要
pmtiles プロトコル登録のタイミング import 時 (現状 embed-core.ts) か明示的 init 呼び出し時か
parseAtts の責務分解 「DOM スキャン」と「データ整形」を分離。前者は wrapper、後者は lib
GestureHandling の組み込み maps-core に置くか、wrapper 側で GeoloniaMap に外付けするか
後方互換 window.maplibregl / window.mapboxgl 代入 削除可能か (公開期間長い API なので慎重に)
simpleStyle (小文字始まり) の後方互換 削除可能か

依存方向の確認

書き直し後の依存グラフ:

maps-core (lib)
  ├─ maplibre-gl
  ├─ pmtiles
  ├─ tinycolor2
  ├─ sanitize-html
  ├─ @turf/center
  ├─ @mapbox/geojson-extent
  ├─ @geolonia/mbgl-gesture-handling
  └─ (DOM API: document, HTMLElement)
                   ↑
                   │ depends on
                   │
embed (wrapper)
  ├─ maps-core
  ├─ (window, document の DOM ハンドリング)
  └─ (lifecycle: Mutation/Intersection Observer)

maps-core から wrapper を import する方向はない (一方向)。

ステージ環境変数の扱い

現状は webpack DefinePlugin で process.env.MAP_PLATFORM_STAGE を静的置換 (webpack.config.js:7):

  • npm scripts では 'v1' 固定
  • 直接 webpack コマンドだと 'dev' (デフォルト)

書き直し後の選択肢:

  1. 現状維持 (build-time 定数): maps-core ビルドで stage を埋め込む → 利用側は固定。シンプル
  2. ランタイム引数: new GeoloniaMap({ stage: 'v1', ... }) で渡せる → React wrapper 等で動的選択可能
  3. キーパース時に決定: API key URL に stage 情報を含める → script tag 経由でないと無理。後方互換でない

おすすめ: 2 (ランタイム引数)。デフォルトは 'v1' (現行 production と同じ)。

移植チェックリスト (全項目を維持)

書き直し時に現状の挙動再現を保証するためのチェックリスト。詳細仕様は対応する docs を参照。

URL 書き換え (URL-Rewrite-Spec)

  • https://api.geolonia.com/* Source → https://api.geolonia.com/{stage}/sources?key=...&sessionId=...
  • geolonia://tiles/{username}/{customtileId}https://tileserver.geolonia.com/customtiles/{customtileId}/tiles.json
  • Geolonia tiles host (tileserver.geolonia.com, *.tiles.geolonia.com) に ?sessionId=...&key=... 注入
  • dev stage で tileserver.geolonia.comtileserver-dev.geolonia.com 置換
  • sprite URL の path stage 置換 (/dev/sprites//v1/sprites/)
  • 外部 URL は変換なし

スタイル解決 (Module-Util / Module-Keyring)

  • 空 / null → https://cdn.geolonia.com/style/geolonia/basic-v2/{lang}.json
  • http(s)://... → そのまま (Mixed Content 警告あり)
  • 相対パス (/, ./, ../) → location.href 基準で resolve
  • *.json で終わる → location.href 基準で resolve
  • その他 → https://cdn.geolonia.com/style/{style}/{lang}.json
  • Geolonia スタイル使用時に key 未指定 → throw

data-* 属性 (Data-Attributes)

  • 全 29 属性のデフォルト値を再現 (parse-atts.ts:33-66)
  • interactive: false で gestureHandling / navigationControl を 'off' に
  • data-lazy-loading="off" のみ即時 render、それ以外は IntersectionObserver

コントロール (Module-Controls)

  • GeoloniaControl は常に追加 (data-geolonia-control の enabled を見ない)
  • CustomAttributionControl は常に bottom-right
  • その他 4 control (Fullscreen, Navigation, Geolocate, Scale) は data-* で条件付き
  • addControl の順序 (GeoloniaControl → Attribution → 他 4)

マーカー (Module-Marker)

  • デフォルト SVG 26×34 px、offset: [0, -15]
  • .left / .right SVG class で色適用
  • tinycolor2 で .right を darken
  • customMarker 時の offset パース ('0, 0' 形式)
  • geolonia-clickable-marker クラス付与

SimpleStyle (Module-SimpleStyle)

  • レイヤ ID prefix geolonia-simple-style 8 種
  • cluster clusterMaxZoom: 14, clusterRadius: 50
  • marker-size の circle-radius 7/13/9 と text-radial-offset 1/1.6/1.2
  • SimpleStyleVector: source-layer g-simplestyle-v1 固定
  • description の sanitize-html (defaults + img、全要素 class 許可)

3D layer metadata (Hidden-Spec)

  • visible-on-3d / hide-on-3d のロジック (4 分岐)
  • styledata イベントで __styleExtensionLoadRequired フラグ管理

認証 (Module-Keyring)

  • script tag URL から geolonia-api-key 抽出
  • MAP_PLATFORM_STAGE の扱い (現状 build-time)
  • isGeoloniaStyleCheck の 5-way 分岐
  • API key 未取得時 + Geolonia style 時の throw

iframe 許可 (Module-Util)

  • 自身が iframe でない / API key あり / 同一 origin → 許可
  • Codepen, JSFiddle, CodeSandbox の referrer 特例

エラー処理 (Module-Util, Module-GeoloniaMap)

  • super() 失敗 → handleErrorMode で日本語 div 挿入
  • HTTP 402 → handleRestrictedMode で map remove + class 追加
  • 再入防止 (map._geolonia_restricted_mode_handled)

ライフサイクル (Module-Render)

  • MutationObserver で container 削除を検知 (parentNode 監視)
  • IntersectionObserver の once-only
  • プラグインの DOMContentLoaded 待機 / 早期 render 時のキュー
  • container.geoloniaMap シングルトンキャッシュ

グローバル状態 (Architecture)

  • window.geolonia 設定
  • window.maplibregl / window.mapboxgl 後方互換 (削除可否は議論)
  • keyring シングルトン
  • sessionId モジュールキャッシュ
  • plugins モジュール配列

段階的移行案

書き直しの実装順:

  1. maps-core を新規プロジェクトとして作成 (別リポジトリ or workspace)
  2. lib/*.ts を maps-core にコピー (modify せず、まずは動くものに)
  3. maps-core の単体テストを追加 (現状コードベースが薄いので、URL-Rewrite-Spec 等のテーブルを元に書く)
  4. embed-core.ts を maps-core 経由で書き換え: import { GeoloniaMap, ... } from '@geolonia/maps-core'
  5. embed.ts を thin wrapper に書き換え: maps-core を import、render.ts の DOM 処理のみ残す
  6. 互換性確認: E2E テスト (#411 で進行中) を流して回帰なしを確認
  7. 必要に応じて refactor: Suspicious-Logic の各項目を修正

参照

  • 各モジュール: 各 Module-* ページ
  • 全 hidden-spec (移植チェックリスト元): Hidden-Spec
  • 全 suspicious-logic (移植時に判断必要): Suspicious-Logic

Clone this wiki locally