mcpField
M
mapbox-integration-patterns

mapbox-integration-patterns

github.com/mapbox開発6173 回インストール2 日前に更新
リポジトリ

mapbox-integration-patterns について

WebアプリにMapbox GL JSを組み込む開発者向けのスキルです。フレームワーク別のライフサイクル管理、トークン設定、検索連携、SSR対応のパターンを扱います。

主な機能

  1. 01React、Vue、Svelte、Angularの連携パターン
  2. 02マップインスタンスのライフサイクル管理
  3. 03環境変数によるトークン管理
  4. 04Mapbox Search JS連携
  5. 05Next.jsとSSRの注意点

活用シーン

  1. 01Reactアプリへのインタラクティブマップ追加
  2. 02各種フレームワークでのマップ初期化
  3. 03Mapboxアクセストークンの安全な設定
  4. 04Angularのサーバーサイドレンダリング時の読み込み対応

インストール

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

$npx skills add https://github.com/mapbox/mcp-devkit-server --skill mapbox-integration-patterns

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

詳細

Mapbox 統合パターンのスキル

このスキルでは、さまざまなフレームワークで 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"
/>

⚠️ 本番アプリでは CDN ではなく npm を使用してください。バージョンの一貫性とオフラインでのビルドが保証されます。

フレームワークの要件

React:

  • 最小:19+(create-web-app の現在の実装)
  • 推奨:最新の 19.x

Vue:

  • 最小:3.x(Composition API を推奨)
  • Vue 2.x:Options API パターンを使用(mounted/unmounted フック)

Svelte:

  • 最小:5+(create-web-app の現在の実装)
  • 推奨:最新の 5.x

Angular:

  • 最小:19+(create-web-app の現在の実装)
  • 推奨:最新の 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 への移行:

  • accessToken を Map コンストラクターに渡せるようになりました(推奨)
  • TypeScript の型が改善されました
  • ツリーシェイキングのサポートが向上しました
  • コアの初期化パターンに破壊的変更はありません

例:

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

// v2.x pattern (still works in v3.x)
mapboxgl.accessToken = token;
const map = new mapboxgl.Map({ container: '...' });

// v3.x pattern (preferred)
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 を使用する
  • 空の deps [] を指定して 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' }} />
    </>
  );
}

Vue の統合

パターン:mounted + unmounted のライフサイクルフック

<template>
  <div ref="mapContainer" class="map-container"></div>
</template>

<script>
import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';

mapboxgl.accessToken = import.meta.env.VITE_MAPBOX_ACCESS_TOKEN;

export default {
  mounted() {
    const map = new mapboxgl.Map({
      container: this.$refs.mapContainer,
      style: 'mapbox://styles/mapbox/standard',
      center: [-71.05953, 42.3629],
      zoom: 13
    });

    // Assign map instance to component property
    this.map = map;
  },

  // CRITICAL: Clean up when component is unmounted
  unmounted() {
    this.map.remove();
    this.map = null;
  }
};
</script>

<style>
.map-container {
  width: 100%;
  height: 100%;
}
</style>

要点:

  • mounted() フックで初期化する
  • this.$refs.mapContainer でコンテナーにアクセスする
  • 地図を this.map として保存する
  • map.remove() を呼び出す unmounted() フックを必ず実装する

Svelte の統合

パターン:onMount + onDestroy

<script>
  import { Map } from 'mapbox-gl'
  import 'mapbox-gl/dist/mapbox-gl.css'
  import { onMount, onDestroy } from 'svelte'

  let map
  let mapContainer

  onMount(() => {
    map = new Map({
      container: mapContainer,
      accessToken: import.meta.env.VITE_MAPBOX_ACCESS_TOKEN,
      center: [-71.05953, 42.36290],
      zoom: 13
    })
  })

  // CRITICAL: Clean up on component destroy
  onDestroy(() => {
    map.remove()
  })
</script>

<div class="map" bind:this={mapContainer}></div>

<style>
  .map {
    position: absolute;
    width: 100%;
    height: 100%;
  }
</style>

要点:

  • 初期化には onMount を使用する
  • bind:this={mapContainer} でコンテナーをバインドする
  • map.remove() を呼び出す onDestroy を必ず実装する
  • Svelte では accessToken を Map コンストラクターに直接渡せます

Angular の統合

パターン:SSR 対応の ngOnInit + ngOnDestroy

import {
  Component,
  ElementRef,
  OnDestroy,
  OnInit,
  ViewChild,
  inject
} from '@angular/core';
import { isPlatformBrowser, CommonModule } from '@angular/common';
import { PLATFORM_ID } from '@angular/core';
import { environment } from '../../environments/environment';

@Component({
  selector: 'app-map',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './map.component.html',
  styleUrls: ['./map.component.scss']
})
export class MapComponent implements OnInit, OnDestroy {
  @ViewChild('mapContainer', { static: false })
  mapContainer!: ElementRef<HTMLDivElement>;

  private map: any;
  private readonly platformId = inject(PLATFORM_ID);

  async ngOnInit(): Promise<void> {
    // IMPORTANT: Check if running in browser (not SSR)
    if (!isPlatformBrowser(this.platformId)) {
      return;
    }

    try {
      await this.initializeMap();
    } catch (error) {
      console.error('Failed to initialize map:', error);
    }
  }

  private async initializeMap(): Promise<void> {
    // Dynamically import to avoid SSR issues
    const mapboxgl = (await import('mapbox-gl')).default;

    this.map = new mapboxgl.Map({
      accessToken: environment.mapboxAccessToken,
      container: this.mapContainer.nativeElement,
      center: [-71.05953, 42.3629],
      zoom: 13
    });

    // Handle map errors
    this.map.on('error', (e: any) => console.error('Map error:', e.error));
  }

  // CRITICAL: Clean up on component destroy
  ngOnDestroy(): void {
    if (this.map) {
      this.map.remove();
    }
  }
}

テンプレート(map.component.html):

<div #mapContainer style="height: 100vh; width: 100%"></div>

要点:

  • @ViewChild を使って地図コンテナーを参照する
  • 初期化前に isPlatformBrowser を確認する(SSR 対応)
  • SSR の問題を避けるため、mapbox-gl を動的にインポートする
  • ngOnInit() ライフサイクルフックで初期化する
  • map.remove() を呼び出す ngOnDestroy() を必ず実装する
  • map.on('error', ...) でエラーを処理する

Vanilla JavaScript(Vite 使用)

パターン:モジュールのインポートと初期化関数

import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';
import './main.css';

// Set access token
mapboxgl.accessToken = import.meta.env.VITE_MAPBOX_ACCESS_TOKEN;

let map;

/**
 * Initialize the map
 */
function initMap() {
  map = new mapboxgl.Map({
    container: 'map-container',
    center: [-71.05953, 42.3629],
    zoom: 13
  });

  map.on('load', () => {
    console.log('Map is loaded');
  });
}

// Initialize when script runs
initMap();

HTML:

<div id="map-container" style="height: 100vh;"></div>

要点:

  • 地図をモジュールスコープの変数に保存する
  • すぐに初期化するか、DOMContentLoaded イベント時に初期化する
  • 初期化後の処理には 'load' イベントをリッスンする

Vanilla JavaScript(バンドラーなし - CDN)

パターン:インライン初期化を伴うスクリプトタグ

⚠️ 注意: このパターンはプロトタイピング専用です。本番アプリでは、バージョン管理とオフラインビルドのために npm/バンドラーを使用してください。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Mapbox GL JS - No Bundler</title>

    
    
    <link
      href="https://api.mapbox.com/mapbox-gl-js/v3.x.x/mapbox-gl.css"
      rel="stylesheet"
    />

    <style>
      body {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        margin: 0;
        padding: 0;
      }
      #map-container {
        height: 100%;
        width: 100%;
      }
    </style>
  </head>
  <body>
    <div id="map-container"></div>

    
    
    <script src="https://api.mapbox.com/mapbox-gl-js/v3.x.x/mapbox-gl.js"></script>

    <script>
      // Set access token
      mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN_HERE';

      let map;

      function initMap() {
        map = new mapboxgl.Map({
          container: 'map-container',
          center: [-71.05953, 42.3629],
          zoom: 13
        });

        map.on('load', () => {
          console.log('Map is loaded');
        });
      }

      // Initialize when page loads
      initMap();
    </script>
  </body>
</html>

主なポイント:

  • ⚠️ プロトタイピング専用 - 本番環境では推奨されません
  • Mapbox のドキュメントから特定のバージョン(例:3.7.0)を選び、3.x.xを置き換えてください
  • /latest/は使用しないでください - 一貫性を保つため、必ず特定のバージョンに固定してください
  • スクリプトの読み込み後に初期化してください(body の末尾)
  • 本番環境では、代わりに npm + バンドラーを使用してください

本番環境で CDN を使わない理由

  • ❌ ネットワークへの依存(オフラインでは動作しません)
  • ❌ バージョンを固定できない(CDN の内容が変更される可能性があります)
  • ❌ 低速(バンドラーによる最適化がありません)
  • ❌ ツリーシェイキングがありません
  • ✅ 本番環境では npm を使用してください:npm install mapbox-gl@^3.0.0

トークン管理のパターン

環境変数(推奨)

フレームワークごとに、クライアント側の環境変数に異なるプレフィックスを使用します。

フレームワーク/バンドラー環境変数アクセス方法
ViteVITE_MAPBOX_ACCESS_TOKENimport.meta.env.VITE_MAPBOX_ACCESS_TOKEN
Next.jsNEXT_PUBLIC_MAPBOX_TOKENprocess.env.NEXT_PUBLIC_MAPBOX_TOKEN
Create React AppREACT_APP_MAPBOX_TOKENprocess.env.REACT_APP_MAPBOX_TOKEN
Angularenvironment.mapboxAccessToken環境ファイル(environment.ts)

Vite の .env ファイル:

VITE_MAPBOX_ACCESS_TOKEN=pk.eyJ1...

Next.js の .env.local ファイル:

NEXT_PUBLIC_MAPBOX_TOKEN=pk.eyJ1...

重要:

  • ✅ トークンには必ず環境変数を使用してください
  • ✅ .envファイルをバージョン管理にコミットしないでください
  • ✅ クライアント側アプリには公開トークン(pk.*)を使用してください
  • ✅ .envを.gitignoreに追加してください
  • ✅ チーム用に.env.exampleのテンプレートを用意してください

.gitignore:

.env
.env.local
.env.*.local

.env.example:

VITE_MAPBOX_ACCESS_TOKEN=your_token_here

Mapbox Search JS の統合

検索ボックスコンポーネントのパターン

依存関係をインストールします:

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

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

React の検索パターン:

import { SearchBox } from '@mapbox/search-js-react';

// Inside component:
<SearchBox
  accessToken={accessToken}
  map={mapRef.current} // Pass map instance
  mapboxgl={mapboxgl} // Pass mapboxgl library
  value={inputValue}
  onChange={(value) => setInputValue(value)}
  proximity={centerCoordinates} // Bias results near center
  marker // Show marker for selected result
/>;

主な設定オプション:

  • 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
}, [])

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


❌ 間違い 2:render 内でのマップの初期化
// 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()の呼び出しなどの操作には、マップのインスタンスにアクセスする必要があります。


❌ 間違い 4:useEffect の依存配列が間違っている
// BAD - Re-creates map on every render
useEffect(() => {
  const map = new mapboxgl.Map({ ... })
  return () => map.remove()
})  // No dependency array

// BAD - Re-creates map when props change
useEffect(() => {
  const map = new mapboxgl.Map({ center: props.center, ... })
  return () => map.remove()
}, [props.center])
// GOOD - Initialize once
useEffect(() => {
  const map = new mapboxgl.Map({ ... })
  return () => map.remove()
}, [])  // Empty array = run once

// GOOD - Update map property instead
useEffect(() => {
  if (mapRef.current) {
    mapRef.current.setCenter(props.center)
  }
}, [props.center])

理由: マップの初期化にはコストがかかります。初期化は一度だけ行い、その後はマップのメソッドを使ってプロパティを更新してください。


❌ 間違い 5:ソースコードへのトークンのハードコーディング
// BAD - Token exposed in source code
mapboxgl.accessToken = 'pk.eyJ1IjoiZXhhbXBsZSIsImEiOiJjbGV4YW1wbGUifQ.example';
// GOOD - Use environment variable
mapboxgl.accessToken = import.meta.env.VITE_MAPBOX_ACCESS_TOKEN;

理由: ソースコード内のトークンはバージョン管理にコミットされ、公開されてしまいます。必ず環境変数を使用してください。


❌ 間違い 6:Angular SSR に対応していない
// BAD - Crashes during server-side rendering
ngOnInit() {
  import('mapbox-gl').then(mapboxgl => {
    this.map = new mapboxgl.Map({ ... })
  })
}
// GOOD - Check platform first
ngOnInit() {
  if (!isPlatformBrowser(this.platformId)) {
    return  // Skip map init during SSR
  }

  import('mapbox-gl').then(mapboxgl => {
    this.map = new mapboxgl.Map({ ... })
  })
}

理由: Mapbox GL JS はブラウザー API(WebGL、Canvas)を必要とします。Angular Universal(SSR)は、プラットフォームチェックがないとクラッシュします。


❌ 間違い 7:CSS のインポートがない
// BAD - Map renders but looks broken
import mapboxgl from 'mapbox-gl';
// Missing CSS import
// GOOD - Import CSS for proper styling
import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';

理由: CSS ファイルには、マップコントロール、ポップアップ、マーカーに必要なスタイルが含まれています。これがないと、マップが正しく表示されません。


Next.js 固有のパターン

App Router(推奨)
'use client'  // Mark as client component

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

export default function Map() {
  const mapRef = useRef<mapboxgl.Map>()
  const mapContainerRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    if (!mapContainerRef.current) return

    mapboxgl.accessToken = process.env.NEXT_PUBLIC_MAPBOX_TOKEN!

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

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

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

重要なポイント:

  • 'use client' ディレクティブが必須です(マップにはブラウザー API が必要です)
  • 環境変数には process.env.NEXT_PUBLIC_* を使用します
  • TypeScript で mapRef に適切な型を指定します
Pages Router(レガシー)
import dynamic from 'next/dynamic'

// Dynamically import to disable SSR for map component
const Map = dynamic(() => import('../components/Map'), {
  ssr: false,
  loading: () => <p>Loading map...</p>
})

export default function HomePage() {
  return <Map />
}

重要なポイント:

  • ssr: false を指定して dynamic インポートを使用します
  • 読み込み状態を用意します
  • マップコンポーネント自体は標準的な React パターンに従います

スタイル設定

デフォルトの中心位置とズームのガイドライン

推奨されるデフォルト値:

  • 中心位置:[-71.05953, 42.36290](米国マサチューセッツ州ボストン)- Mapbox 本社
  • ズーム:都市レベルの表示には 13

ズームレベルの目安:

  • 0-2:世界
  • 3-5:大陸/国
  • 6-9:地域/州
  • 10-12:都市
  • 13-15:近隣地域
  • 16-18:街路
  • 19-22:建物

ユーザーの位置に合わせたカスタマイズ:

// Use browser geolocation
if (navigator.geolocation) {
  navigator.geolocation.getCurrentPosition((position) => {
    map.setCenter([position.coords.longitude, position.coords.latitude]);
    map.setZoom(13);
  });
}

テストのパターン

マップの単体テスト

mapbox-gl をモックします:

// vitest.config.js or jest.config.js
export default {
  setupFiles: ['./test/setup.js']
};
// test/setup.js
vi.mock('mapbox-gl', () => ({
  default: {
    Map: vi.fn(() => ({
      on: vi.fn(),
      remove: vi.fn(),
      setCenter: vi.fn(),
      setZoom: vi.fn()
    })),
    accessToken: ''
  }
}));

理由: Mapbox GL JS は、テスト環境には存在しない WebGL とブラウザー API を必要とします。コンポーネントのロジックをテストするには、ライブラリをモックしてください。


このスキルを使用する場面

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

  • 新しいプロジェクトで Mapbox GL JS をセットアップするとき
  • 特定のフレームワークに Mapbox を統合するとき
  • マップの初期化に関する問題をデバッグするとき
  • Mapbox Search の機能を追加するとき
  • 適切なクリーンアップとライフサイクル管理を実装するとき
  • フレームワーク間で変換するとき(例:React から Vue)
  • Mapbox 統合のベストプラクティスに沿ってコードをレビューするとき

関連するスキル

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

リソース

コメント