-
Notifications
You must be signed in to change notification settings - Fork 7
Core vs Wrapper
niryuu edited this page May 25, 2026
·
1 revision
このドキュメントは embed-core を独立ライブラリ maps-core として分離し、embed 本体を thin wrapper として書き直す前提で、現状の責務をどう分解するかを記録する。
-
maps-coreは React wrapper や他のプロジェクトからも利用される汎用 lib になる - embed (フル版) は HTML 宣言的利用 (
<div class="geolonia">) と後方互換のためのグローバル登録を担う - 分離後も現状の挙動を完全に再現する。new code でも全 hidden-spec / suspicious-logic 項目を意識する
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 のみが行う処理:
-
window.geolonia = Object.assign(...)でグローバル登録 (maplibregl + 拡張) -
window.maplibregl = window.mapboxgl = window.geolonia後方互換 -
renderGeoloniaMap()呼び出し -
Geolonia型エクスポート
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 のみが行う処理:
- import 時 (module top-level) に
maplibregl.addProtocol('pmtiles', protocol.tile)実行
両者の差: embed.ts は window.* 設定と auto-render を伴う、embed-core.ts はそれを伴わない (pmtiles 登録のみ自動)。
-
GeoloniaMap,GeoloniaMarker,SimpleStyle,registerPlugin,embedVersion - 型:
EmbedAttributes,EmbedPlugin,GeoloniaMapOptions
-
SimpleStyleVector(named export) -
keyring(シングルトン)
これらは embed.ts でも export 可能だが、現状の embed.ts が忘れている可能性が高い (SimpleStyleVector は意図的に隠している? 詳細不明)。
-
geolonia(シングルトンインスタンス) -
Geolonia型 -
Popup型 alias
| シンボル / モジュール | 現在の場所 | 移行先での扱い |
|---|---|---|
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 時の副作用維持 |
| シンボル / モジュール | 現在の場所 | 移行先での扱い |
|---|---|---|
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'(デフォルト)
書き直し後の選択肢:
- 現状維持 (build-time 定数): maps-core ビルドで stage を埋め込む → 利用側は固定。シンプル
-
ランタイム引数:
new GeoloniaMap({ stage: 'v1', ... })で渡せる → React wrapper 等で動的選択可能 - キーパース時に決定: API key URL に stage 情報を含める → script tag 経由でないと無理。後方互換でない
おすすめ: 2 (ランタイム引数)。デフォルトは 'v1' (現行 production と同じ)。
書き直し時に現状の挙動再現を保証するためのチェックリスト。詳細仕様は対応する docs を参照。
-
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.com→tileserver-dev.geolonia.com置換 - sprite URL の path stage 置換 (
/dev/sprites/↔/v1/sprites/) - 外部 URL は変換なし
- 空 / 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
- 全 29 属性のデフォルト値を再現 (
parse-atts.ts:33-66) -
interactive: falseで gestureHandling / navigationControl を 'off' に -
data-lazy-loading="off"のみ即時 render、それ以外は IntersectionObserver
- GeoloniaControl は常に追加 (data-geolonia-control の enabled を見ない)
- CustomAttributionControl は常に bottom-right
- その他 4 control (Fullscreen, Navigation, Geolocate, Scale) は data-* で条件付き
- addControl の順序 (GeoloniaControl → Attribution → 他 4)
- デフォルト SVG 26×34 px、
offset: [0, -15] -
.left/.rightSVG class で色適用 - tinycolor2 で
.rightを darken - customMarker 時の offset パース (
'0, 0'形式) -
geolonia-clickable-markerクラス付与
- レイヤ ID prefix
geolonia-simple-style8 種 - 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 許可)
-
visible-on-3d/hide-on-3dのロジック (4 分岐) - styledata イベントで
__styleExtensionLoadRequiredフラグ管理
- script tag URL から
geolonia-api-key抽出 -
MAP_PLATFORM_STAGEの扱い (現状 build-time) - isGeoloniaStyleCheck の 5-way 分岐
- API key 未取得時 + Geolonia style 時の throw
- 自身が iframe でない / API key あり / 同一 origin → 許可
- Codepen, JSFiddle, CodeSandbox の referrer 特例
- super() 失敗 →
handleErrorModeで日本語 div 挿入 - HTTP 402 →
handleRestrictedModeで map remove + class 追加 - 再入防止 (
map._geolonia_restricted_mode_handled)
- MutationObserver で container 削除を検知 (parentNode 監視)
- IntersectionObserver の once-only
- プラグインの DOMContentLoaded 待機 / 早期 render 時のキュー
-
container.geoloniaMapシングルトンキャッシュ
-
window.geolonia設定 -
window.maplibregl/window.mapboxgl後方互換 (削除可否は議論) -
keyringシングルトン -
sessionIdモジュールキャッシュ -
pluginsモジュール配列
書き直しの実装順:
- maps-core を新規プロジェクトとして作成 (別リポジトリ or workspace)
-
lib/*.tsを maps-core にコピー (modify せず、まずは動くものに) -
maps-core の単体テストを追加 (現状コードベースが薄いので、
URL-Rewrite-Spec等のテーブルを元に書く) -
embed-core.ts を maps-core 経由で書き換え:
import { GeoloniaMap, ... } from '@geolonia/maps-core' -
embed.ts を thin wrapper に書き換え: maps-core を import、
render.tsの DOM 処理のみ残す - 互換性確認: E2E テスト (#411 で進行中) を流して回帰なしを確認
-
必要に応じて refactor:
Suspicious-Logicの各項目を修正
- 各モジュール: 各
Module-*ページ - 全 hidden-spec (移植チェックリスト元):
Hidden-Spec - 全 suspicious-logic (移植時に判断必要):
Suspicious-Logic