mcpField
M
mapbox-web-integration-patterns

mapbox-web-integration-patterns

github.com/mapbox開発832.6k 回インストール4 週間前に更新
リポジトリ

mapbox-web-integration-patterns について

mapbox-web-integration-patternsは、ウェブアプリへのMapbox GL JSとMapbox Search JSの組み込み方を示すエージェントスキルです。複数のフロントエンドフレームワークを対象に、ライフサイクル管理、トークン処理、クリーンアップ、よくある統合ミスを扱います。

主な機能

  1. 01React、Vue、Svelte、Angularの統合パターン
  2. 02Vanilla JavaScriptとNext.jsのガイド
  3. 03Mapbox Search JSの統合
  4. 04マップのライフサイクルとクリーンアップ
  5. 05トークン管理とよくあるエラーの確認

活用シーン

  1. 01ウェブアプリへのMapbox GL JS導入
  2. 02フロントエンド向けマップコンポーネントの作成
  3. 03Mapbox Search JSの統合
  4. 04マップのライフサイクルやスタイル切替の問題調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mapbox/mapbox-agent-skills --skill mapbox-web-integration-patterns

インストール後、Claude Code で/mapbox-web-integration-patternsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

AGENTS.md
evals/
evals.json
references/
angular.md
common-mistakes.md
nextjs.md
svelte.md
token-management.md
vanilla.md
vue.md
web-components.md

詳細

Mapbox 統合パターンのスキル

このスキルでは、React、Vue、Svelte、Angular、バニラ JavaScript を使って Web アプリケーションに Mapbox GL JS を統合するための公式パターンを紹介します。これらのパターンは、Mapbox の create-web-app スキャフォールディングツールに基づいており、本番環境ですぐに使えるベストプラクティスを示しています。

バージョン要件

Mapbox GL JS

推奨: v3.x(最新)

  • 最小バージョン: v3.0.0
  • v3.x の理由: モダンな API、パフォーマンスの向上、活発な開発
  • v2.x: レガシー版。現在は積極的に開発されていません(下記の移行に関する注意事項を参照)

npm でのインストール(本番環境に推奨):

npm install mapbox-gl@^3.0.0    # Installs latest v3.x

CDN(プロトタイピング専用):


<script src="https://api.mapbox.com/mapbox-gl-js/vVERSION/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/vVERSION/mapbox-gl.css" rel="stylesheet" />
フレームワーク要件

React: GL JS は React 16.8 以降で動作します(フックが必要です)。create-web-app は React 19.x を使ってスキャフォールディングします。 Vue: GL JS は Vue 2.x 以降で動作します(Vue 3 Composition API を推奨)。 Svelte: GL JS はすべての Svelte バージョンで動作します。create-web-app は Svelte 5.x を使ってスキャフォールディングします。 Angular: GL JS は Angular 2 以降で動作します。create-web-app は Angular 19.x を使ってスキャフォールディングします。 Next.js: 最小バージョンは 13.x(App Router)、Pages Router の場合は 12.x 以降です。

Mapbox Search JS
npm install @mapbox/search-js-react@^1.0.0      # React
npm install @mapbox/search-js-web@^1.0.0        # Other frameworks
バージョン移行に関する注意事項(v2.x から v3.x)
  • WebGL 2 が必須になりました
  • optimizeForTerrain オプションが削除されました
  • TypeScript の型が改善され、ツリーシェイキングのサポートが向上しました
  • コアの初期化パターンに破壊的変更はありません

トークンのパターン(v2.x と v3.x の両方で動作):

const token = import.meta.env.VITE_MAPBOX_ACCESS_TOKEN; // Use env vars in production

// Global token (works since v1.x)
mapboxgl.accessToken = token;
const map = new mapboxgl.Map({ container: '...' });

// Per-map token (preferred for multi-map setups)
const map = new mapboxgl.Map({
  accessToken: token,
  container: '...'
});

基本原則

Mapbox GL JS の統合では、必ず以下を行ってください。

  1. 適切なライフサイクルフックでマップを初期化する
  2. マップインスタンスをコンポーネントの状態に保存する(レンダーごとに再作成しない)
  3. メモリリークを防ぐため、クリーンアップ時に必ず map.remove() を呼び出す
  4. トークンを安全に管理する(環境変数を使用)
  5. CSS をインポートする:import 'mapbox-gl/dist/mapbox-gl.css'

React 統合(主要パターン)

パターン:useRef + useEffect とクリーンアップ

注: これらの例では、create-web-app で使用されているバンドラーである Vite を使用しています。Create React App を使用する場合は、import.meta.env.VITE_MAPBOX_ACCESS_TOKEN を process.env.REACT_APP_MAPBOX_TOKEN に置き換えてください。その他のバンドラーについては、トークン管理パターンを参照してください。

import { useRef, useEffect } from 'react';
import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';

function MapComponent() {
  const mapRef = useRef(null); // Store map instance
  const mapContainerRef = useRef(null); // Store DOM reference

  useEffect(() => {
    mapboxgl.accessToken = import.meta.env.VITE_MAPBOX_ACCESS_TOKEN;

    mapRef.current = new mapboxgl.Map({
      container: mapContainerRef.current,
      center: [-71.05953, 42.3629],
      zoom: 13
    });

    // CRITICAL: Cleanup to prevent memory leaks
    return () => {
      mapRef.current.remove();
    };
  }, []); // Empty dependency array = run once on mount

  return <div ref={mapContainerRef} style={{ height: '100vh' }} />;
}

要点:

  • マップインスタンスとコンテナーの両方に useRef を使用する
  • 空の依存配列 [] を指定して useEffect 内で初期化する
  • 必ず map.remove() を呼び出すクリーンアップ関数を返す
  • レンダー内でマップを初期化しない(無限ループの原因になります)
React + Search JS
import { useRef, useEffect, useState } from 'react';
import mapboxgl from 'mapbox-gl';
import { SearchBox } from '@mapbox/search-js-react';
import 'mapbox-gl/dist/mapbox-gl.css';

const accessToken = import.meta.env.VITE_MAPBOX_ACCESS_TOKEN;
const center = [-71.05953, 42.3629];

function MapWithSearch() {
  const mapRef = useRef(null);
  const mapContainerRef = useRef(null);
  const [inputValue, setInputValue] = useState('');

  useEffect(() => {
    mapboxgl.accessToken = accessToken;

    mapRef.current = new mapboxgl.Map({
      container: mapContainerRef.current,
      center: center,
      zoom: 13
    });

    return () => {
      mapRef.current.remove();
    };
  }, []);

  return (
    <>
      <div
        style={{
          margin: '10px 10px 0 0',
          width: 300,
          right: 0,
          top: 0,
          position: 'absolute',
          zIndex: 10
        }}
      >
        <SearchBox
          accessToken={accessToken}
          map={mapRef.current}
          mapboxgl={mapboxgl}
          value={inputValue}
          proximity={center}
          onChange={(d) => setInputValue(d)}
          marker
        />
      </div>
      <div ref={mapContainerRef} style={{ height: '100vh' }} />
    </>
  );
}

Search JS 統合の概要

インストール:

npm install @mapbox/search-js-react      # React
npm install @mapbox/search-js-web        # Vanilla/Vue/Svelte

どちらのパッケージにも依存関係として @mapbox/search-js-core が含まれています。カスタム検索 UI を構築する場合に限り、-core を直接インストールしてください。

主な設定オプション:

  • accessToken:Mapbox の公開トークン
  • map:マップインスタンス(先に初期化する必要があります)
  • mapboxgl:mapboxgl ライブラリへの参照
  • proximity:結果を地理的に絞り込むための [lng, lat]
  • marker:結果マーカーを表示または非表示にするブール値
  • placeholder:検索ボックスのプレースホルダーテキスト
検索ボックスの配置

絶対位置指定(オーバーレイ):

<div
  style={{
    position: 'absolute',
    top: 10,
    right: 10,
    zIndex: 10,
    width: 300
  }}
>
  <SearchBox {...props} />
</div>

一般的な配置:

  • 右上:top: 10px, right: 10px
  • 左上:top: 10px, left: 10px
  • 左下:bottom: 10px, left: 10px

よくある間違い(重要)

間違い 1:map.remove() の呼び出し忘れ
// BAD - Memory leak!
useEffect(() => {
  const map = new mapboxgl.Map({ ... })
  // No cleanup function
}, [])

// GOOD - Proper cleanup
useEffect(() => {
  const map = new mapboxgl.Map({ ... })
  return () => map.remove()  // Cleanup
}, [])

理由: マップインスタンスを作成するたびに WebGL コンテキスト、イベントリスナー、DOM ノードが作成されます。クリーンアップしないと、これらが蓄積してメモリリークを引き起こします。

間違い 2:レンダー内でマップを初期化する
// BAD - Infinite loop in React!
function MapComponent() {
  const map = new mapboxgl.Map({ ... })  // Runs on every render
  return <div />
}

// GOOD - Initialize in effect
function MapComponent() {
  useEffect(() => {
    const map = new mapboxgl.Map({ ... })
  }, [])
  return <div />
}

理由: React コンポーネントは頻繁に再レンダーされます。レンダーごとに新しいマップを作成すると、無限ループやクラッシュの原因になります。

間違い 3:マップインスタンスを適切に保存しない
// BAD - map variable lost between renders
function MapComponent() {
  useEffect(() => {
    let map = new mapboxgl.Map({ ... })
    // map variable is not accessible later
  }, [])
}

// GOOD - Store in useRef
function MapComponent() {
  const mapRef = useRef()
  useEffect(() => {
    mapRef.current = new mapboxgl.Map({ ... })
    // mapRef.current accessible throughout component
  }, [])
}

理由: レイヤーやマーカーの追加、remove() の呼び出しなどの操作には、マップインスタンスにアクセスする必要があります。

Mistake 4: Vue の data() にマップインスタンスを保存する(Vue 固有)
// BAD - Vue's reactivity wraps data() objects in a Proxy, breaking mapbox-gl internals!
export default {
  data() {
    return {
      map: null  // Will be wrapped in a Proxy
    }
  },
  mounted() {
    this.map = new mapboxgl.Map({ ... })  // Proxy breaks GL internals
  }
}

// GOOD - Assign map as a plain instance property, not in data()
export default {
  mounted() {
    this.map = new mapboxgl.Map({
      container: this.$refs.mapContainer,
      center: [-71.05953, 42.3629],
      zoom: 13
    })
  },
  unmounted() {
    this.map?.remove()
  }
}

理由: Vue(特に Vue 3)では、リアクティブにするために data() のプロパティが Proxy でラップされます。Mapbox GL JS は内部でオブジェクトの同一性を確認し、プロキシでラップすると維持されないプロパティを使用します。マップを data() に保存すると、気付きにくくデバッグが困難な不具合につながります。代わりに、mounted() でマップインスタンスを this.map に直接代入してください。data() の外で代入されたプロパティはリアクティブになりません。

Mistake 5: スタイルやタイルのエラーを見逃す(エラーハンドラーがない)
// BAD — blank map when the token/style fails
const map = new mapboxgl.Map({ ... });

// GOOD — surface failures
map.on('error', (e) => {
  console.error(e.error || e);
  // optionally show an on-page error message
});
Mistake 6: jsDelivr の +esm によって deck.gl の CDN が機能しない

<script type="module">
  import { MapboxOverlay } from 'https://cdn.jsdelivr.net/npm/@deck.gl/[email protected]/+esm';
</script>


<script src="https://unpkg.com/[email protected]/dist.min.js"></script>
<script>
  const { MapboxOverlay, ScatterplotLayer } = deck;
  map.addControl(
    new MapboxOverlay({
      interleaved: false,
      layers: [
        /* ... */
      ]
    })
  );
</script>

マップコントロールとして、単独の Deck ではなく MapboxOverlay(Mapbox IControl)を使用してください。

Mistake 7: draw.create のない描画ツールバー

mapbox-gl-draw を読み込む場合は、draw.create を監視してください(また、draw.getAll() を使って UI を更新してください)。削除が不完全なハンドラーが末尾に }); を残すと、ページがクラッシュします。

Mistake 8: setStyle 後にレイヤーが失われる(style.load の再バインドがない)

map.setStyle(...) はスタイルツリーを置き換えます。それ以前に追加したカスタムソース、レイヤー、ハンドラーは、再設定しない限り消去されます。

function onStyleReady() {
  // re-add sources, layers, and interaction handlers here
}

map.on('style.load', onStyleReady);

document.querySelectorAll('[data-style]').forEach((btn) => {
  btn.addEventListener('click', () => {
    map.setStyle(btn.dataset.style);
    // do NOT only add layers on the first 'load' — wait for style.load after every switch
  });
});

エージェントのアンチパターン: setStyle を一度だけ呼び出し、style.load の再バインドを行わないスタイル切り替えボタン。最初のスタイルは機能しますが、その後の切り替えはすべて動作しないように見えます。

リファレンスファイル

フレームワーク固有のパターンや詳細については、次のファイルを読み込んでください。

  • references/vue.md — Vue との統合(mounted/unmounted のライフサイクル)
  • references/svelte.md — Svelte との統合(onMount/onDestroy)
  • references/angular.md — SSR 処理を含む Angular との統合
  • references/vanilla.md — Vanilla JS(Vite)および Vanilla JS(CDN)
  • references/web-components.md — Web Components(基本、リアクティブ、および React/Vue/Svelte での使用)
  • references/nextjs.md — Next.js App Router および Pages Router
  • references/common-mistakes.md — よくあるミス 4~7 およびテストパターン
  • references/token-management.md — バンドラーごとのトークン管理およびスタイル設定

このスキルを使用するタイミング

次の場合にこのスキルを呼び出してください。

  • 新しいプロジェクトで Mapbox GL JS をセットアップする
  • 特定のフレームワーク(React、Vue、Svelte、Angular、Next.js)に Mapbox を統合する
  • フレームワークに依存しない Web Components を構築する
  • コンポーネントライブラリ向けに再利用可能なマップコンポーネントを作成する
  • マップの初期化に関する問題をデバッグする
  • Mapbox Search の機能を追加する
  • 適切なクリーンアップとライフサイクル管理を実装する
  • フレームワーク間で変換する(例:React から Vue)
  • Mapbox 統合のベストプラクティスに沿っているかコードを確認する

関連スキル

  • mapbox-cartography:マップデザインの原則とスタイリング
  • mapbox-token-security:トークン管理とセキュリティ
  • mapbox-style-patterns:一般的なマップスタイルのパターン

リソース

コメント