К основному содержанию
правило

google-maps-js — правило для Cursor: карты Google Maps

Правило задаёт рекомендации по работе с Google Maps JavaScript API в файлах JavaScript и JSX. Пригодится для настройки карты, загрузки библиотек и обработки событий.

Установить в Cursor · Вручную: положить файлы Все способы и платформы ↓
.cursor/rules/google-maps-js.mdc
Открыть на GitHub

Что делает google-maps-js

Правило применяется к файлам **/*.{js,jsx}. Оно советует выносить логику карты из React-компонентов в отдельный хук, загружать библиотеки через @googlemaps/js-api-loader по мере необходимости и использовать Map ID. Для маркеров и сервисов Places показан отдельный динамический импорт.

Ключ API предлагается хранить в переменной окружения, а в Google Cloud Console ограничивать его по HTTP referrer или приложению. Обработчики карты нужно удалять при размонтировании компонента или смене зависимостей; при большом числе маркеров правило предлагает кластеризацию через @googlemaps/markerclusterer. Без доступного ключа API пример хука не инициализирует карту.

Какие задачи решает

  • вынести инициализацию карты из React-компонента
  • загружать библиотеки Maps по запросу
  • хранить ключ API вне исходного кода
  • удалять обработчики событий при размонтировании
  • кластеризовать большое число маркеров

Примеры запросов агенту

  • Переработай компонент карты по правилу google-maps-js: вынеси инициализацию в хук.
  • Загружай библиотеки Google Maps динамически и оставь ключ API в переменной окружения.
  • Проверь обработчики карты и добавь их удаление при размонтировании компонента.

Как установить google-maps-js

Вручную: положить файлы

.cursor/rules/google-maps-js.mdc

Во frontmatter: description, globs, alwaysApply

По шагам, с командами для каждой платформы: Cursor rules: файлы .mdc, четыре режима и замена .cursorrules

Вопросы о google-maps-js

Как установить google-maps-js в Cursor?

Добавь файл правила по пути .cursor/rules/google-maps-js.mdc. Правило охватывает файлы JavaScript и JSX.

Что делает google-maps-js?

Задаёт рекомендации по интеграции Google Maps JavaScript API: организации логики карты, загрузке библиотек, защите ключа и очистке обработчиков.

Как хранить ключ Google Maps API по этому правилу?

Правило предлагает хранить ключ в переменной окружения и ограничивать его в Google Cloud Console по HTTP referrer или приложению. Пример хука не создаёт карту, если ключ недоступен.

Исходный текст

google-maps-js.mdc · CC0-1.0
---
description: This guide provides definitive best practices for integrating and managing the Google Maps JavaScript API in modern web applications, focusing on security, performance, and maintainability.
globs: **/*.{js,jsx}
---
# google-maps-js Best Practices

This document outlines the definitive guidelines for working with the Google Maps JavaScript API. Adhering to these practices ensures secure, performant, and maintainable map-centric applications.

## 1. Code Organization and Structure

Encapsulate map logic to keep components clean and reusable. Avoid direct global `google.maps` object manipulation within React components.

### ✅ GOOD: Custom Hooks for Map Logic (React)

Abstract map initialization and interactions into custom hooks.

```jsx
// hooks/useGoogleMap.js
import { useEffect, useRef, useState } from 'react';
import { Loader } from '@googlemaps/js-api-loader';

const API_KEY = process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY; // Securely load API key

export function useGoogleMap(mapContainerRef, options) {
  const [map, setMap] = useState(null);
  const loaderRef = useRef(null);

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

    if (!loaderRef.current) {
      loaderRef.current = new Loader({
        apiKey: API_KEY,
        version: 'weekly', // Use 'weekly' for latest features, 'quarterly' for stability
        // Do NOT specify 'libraries' here unless absolutely necessary for caching.
        // Prefer dynamic importLibrary() calls.
      });
    }

    const initMap = async () => {
      try {
        const { Map } = await loaderRef.current.importLibrary('maps');
        const newMap = new Map(mapContainerRef.current, {
          center: { lat: -34.397, lng: 150.644 },
          zoom: 8,
          mapId: 'YOUR_MAP_ID', // Always use a Map ID
          ...options,
        });
        setMap(newMap);
      } catch (error) {
        console.error('Error loading Google Maps:', error);
        // Implement user-facing error message, e.g., show a fallback UI
      }
    };

    initMap();

    // Cleanup: Google Maps API doesn't have a direct 'destroy' method for Map instances
    // but unmounting the container and nulling the map reference helps.
    return () => {
      setMap(null); // Clear map instance on unmount
    };
  }, [mapContainerRef, options]);

  return map;
}

// components/MyMapComponent.jsx
import React, { useRef, useEffect } from 'react';
import { useGoogleMap } from '../hooks/useGoogleMap';

export function MyMapComponent() {
  const mapRef = useRef(null);
  const map = useGoogleMap(mapRef, { zoom: 10, center: { lat: 34.0522, lng: -118.2437 } });

  useEffect(() => {
    if (map) {
      // Map is loaded, add markers, listeners, etc.
      console.log('Map loaded:', map);
      const marker = new google.maps.marker.AdvancedMarkerElement({
        map,
        position: map.getCenter(),
        title: 'Hello World',
      });
      // Remember to clean up markers/overlays if they are not managed by the map itself
    }
  }, [map]);

  return <div ref={mapRef} style={{ height: '500px', width: '100%' }} />;
}
```

## 2. Security

API key security is paramount. Never expose your API keys directly in client-side code.

### ❌ BAD: Hardcoding API Keys

```javascript
// In a client-side JS file
const API_KEY = "YOUR_HARDCODED_API_KEY_HERE"; // EXPOSED!
const loader = new Loader({ apiKey: API_KEY });
```

### ✅ GOOD: Secure API Key Management

Store API keys as environment variables and restrict them in the Google Cloud Console.

```javascript
// .env.local (for Next.js/Vite, etc.)
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=AIzaSy...

// In your application code (e.g., useGoogleMap.js)
const API_KEY = process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY;

// Google Cloud Console: Always restrict API keys by HTTP referrer (your domain)
// or by application (Android/iOS package names).
// Use separate keys for different projects/environments to isolate failures.
```

## 3. Loading the API

Always use modern, performant methods for loading the Maps JavaScript API.

### ❌ BAD: Synchronous Script Tag

```html
<!-- Loads all libraries upfront, blocks rendering -->
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"></script>
```

### ✅ GOOD: Dynamic Library Import with `js-api-loader`

This allows lazy loading of specific libraries as needed, reducing initial bundle size and improving page load performance.

```javascript
import { Loader } from '@googlemaps/js-api-loader';

const loader = new Loader({
  apiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY,
  version: 'weekly',
});

async function initializeMapAndPlaces() {
  try {
    const { Map } = await loader.importLibrary('maps');
    const { AdvancedMarkerElement } = await loader.importLibrary('marker');
    const { AutocompleteService } = await loader.importLibrary('places');

    const map = new Map(document.getElementById('map'), { /* ... */ });
    const marker = new AdvancedMarkerElement({ map, /* ... */ });
    const autocompleteService = new AutocompleteService();
    // ... use services
  } catch (error) {
    console.error('Failed to load Google Maps libraries:', error);
  }
}

initializeMapAndPlaces();
```

## 4. Event Handling

Manage event listeners carefully to prevent memory leaks and ensure proper cleanup.

### ❌ BAD: Unmanaged Event Listeners

```javascript
// In a React component, without cleanup
useEffect(() => {
  if (map) {
    map.addListener('click', (e) => {
      console.log('Map clicked at:', e.latLng.toString());
    });
    // This listener will persist even if the component unmounts
  }
}, [map]);
```

### ✅ GOOD: Managed Event Listeners with Cleanup

Use `google.maps.event.addListener` and store the listener handle for later removal with `google.maps.event.removeListener`. In React, this is handled in `useEffect`'s cleanup function.

```javascript
useEffect(() => {
  if (map) {
    const clickListener = map.addListener('click', (e) => {
      console.log('Map clicked at:', e.latLng.toString());
    });

    const dragEndListener = map.addListener('dragend', () => {
      console.log('Map dragged to:', map.getCenter().toString());
    });

    // Cleanup function: remove listeners when component unmounts or dependencies change
    return () => {
      google.maps.event.removeListener(clickListener);
      google.maps.event.removeListener(dragEndListener);
    };
  }
}, [map]);
```

## 5. Performance Considerations

Optimize map rendering and API requests to ensure a smooth user experience.

### 5.1 Marker Management

For applications with many markers, implement clustering or only render visible markers.

### ✅ GOOD: Marker Clustering

Use a helper library like `@googlemaps/markerclusterer` for efficient marker management.

```javascript
import { MarkerClusterer } from '@googlemaps/markerclusterer';

async function addClusteredMarkers(map, locations) {
  const { AdvancedMarkerElement } = await loader.importLibrary('marker');
  const markers = locations.map(loc => new AdvancedMarkerElement({ position: loc }));

  new MarkerClusterer({ map, markers });
}
```

### 5.2 Debouncing/Throttling Map Events

Avoid excessive re-renders or API calls on continuous events like `mousemove` or `drag`.

### ✅ GOOD: Debouncing `idle` Event

```javascript
import { debounce } from 'lodash'; // Or implement your own debounce utility

useEffect(() => {
  if (map) {
    const handleMapIdle = debounce(() => {
      const center = map.getCenter();
      const zoom = map.getZoom();
      console.log(`Map idle. Center: ${center.toString()}, Zoom: ${zoom}`);
      // Trigger API calls or state updates here (e.g., fetch new data for current viewport)
    }, 500); // Wait 500ms after map stops moving

    const idleListener = map.addListener('idle', handleMapIdle);

    return () => {
      google.maps.event.removeListener(idleListener);
      handleMapIdle.cancel(); // Cancel any pending debounced calls
    };
  }
}, [map]);
```

## 6. Request/Response Patterns & Rate Limiting

All web service requests must be asynchronous, use HTTPS, and implement robust error handling with exponential backoff.

### ❌ BAD: Synchronous Requests & No Backoff

```javascript
// This is a conceptual BAD example, as browser JS typically prevents synchronous XHR to external domains.
// The core issue is making repeated, unmanaged requests to web services.
function getGeolocation(location) {
  // ... make direct fetch call without retry logic ...
  // This will fail on transient errors and could hit rate limits quickly.
}
```

### ✅ GOOD: Asynchronous Requests with Exponential Backoff

For server-side or client-side web service calls (e.g., Geocoding, Places API *web services*), implement exponential backoff.

```javascript
async function fetchWithExponentialBackoff(url, maxRetries = 5, initialDelay = 100) {
  let delay = initialDelay;
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url);
      if (!response.ok) {
        // Handle 4XX/5XX errors
        if (response.status >= 400 && response.status < 500 && response.status !== 429) {
          // Client errors (e.g., bad request, unauthorized) should not be retried
          throw new Error(`API Error: ${response.status} ${response.statusText}`);
        }
        // Server errors or rate limits (429) should be retried
        throw new Error(`Transient API Error: ${response.status} ${response.statusText}`);
      }
      return await response.json();
    } catch (error) {
      console.warn(`Attempt ${i + 1} failed: ${error.message}. Retrying in ${delay / 1000}s...`);
      if (i === maxRetries - 1) throw error; // Re-throw after last retry
      await new Promise(resolve => setTimeout(resolve, delay));
      delay *= 2; // Exponential increase
    }
  }
}

// Example usage for a Geocoding API call (server-side recommended for API keys)
async function geocodeAddress(address) {
  const encodedAddress = encodeURIComponent(address);
  const url = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodedAddress}&key=${process.env.GOOGLE_MAPS_SERVER_API_KEY}`;
  try {
    const data = await fetchWithExponentialBackoff(url);
    if (data.status === 'OK') {
      return data.results[0].geometry.location;
    } else {
      throw new Error(`Geocoding failed: ${data.status} - ${data.error_message || 'Unknown error'}`);
    }
  } catch (error) {
    console.error('Final Geocoding error:', error);
    // Notify user or log for investigation
  }
}
```

### 6.1 URL Encoding

Always URL-encode parameters for web service requests, especially before signing if applicable.

```javascript
// ❌ BAD: Unencoded parameters can break requests or lead to incorrect results
const address = "5th&Main St.";
const url = `https://maps.googleapis.com/maps/api/geocode/json?address=${address}&key=...`;

// ✅ GOOD: Properly encoded parameters
const address = "5th&Main St.";
const encodedAddress = encodeURIComponent(address); // "5th%26Main%20St."
const url = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodedAddress}&key=...`;
```

## 7. Common Pitfalls and Gotchas

### 7.1 Map ID Usage

Always use a Map ID when initializing a map. This enables cloud-based map styling and future features.

```javascript
// ❌

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Похожие правила IDE

Каталог правил IDE →
google-maps fetcher-sh Скилл даёт агенту доступ к поиску мест, деталям заведений и отзывам через API fetcher.sh. Пригодится, когда в проекте нужны данные о точках на карте без Google Cloud. CX Codex +1 3 700установок google-maps-scraper gosom Скилл для поиска компаний, контактов и отзывов на Google Картах прямо из редактора кода. Запускает локальный скрейпер через Docker, подходит для сбора лидов и данных о бизнесе без написания кода. CX Codex +1 2 900установок mapbox-google-maps-migration mapbox Скилл для перевода проекта с Google Maps Platform на Mapbox GL JS: таблицы соответствий методов, событий и маркеров, порядок миграции. CX Codex +1 1 400установок google-maps-platform googlemaps Скилл помогает внедрять сервисы Google Maps Platform в веб- и мобильные проекты. Он находит свежие инструкции и защищает от устаревших вызовов API. CX Codex +1 957установок google-maps-teneo TeneoProtocolAI Скилл подключает агента Teneo для сбора данных из Google Maps через локальный терминал. CX Codex +1 499установок Google Maps MCP Server cablate MCP-сервер даёт агенту 18 инструментов Google Maps: поиск мест, маршруты, геокодирование, погоду и локальный SEO-анализ. CX Codex +1 ★ 484звёзд репо

Из того же набора240

Весь набор →
guzzle Задаёт стандарты работы с Guzzle в PHP: фабрики клиентов с таймаутами, middleware для повторов и совместимость с PSR-18. ★ 3 580звёзд репо graphql Правило задаёт соглашения для GraphQL-схем и операций: от именования полей до пагинации, валидации и защиты запросов. Пригодится, если хотите привести API к единым требованиям. ★ 3 580звёзд репо grafana Правило задаёт команде единый стиль работы с дашбордами, алертами и источниками данных Grafana в виде кода: структура, визуальные стандарты, оптимизация запросов. ★ 3 580звёзд репо gradle Направляет ИИ на современные стандарты Gradle в проектах на Java и Android. Помогает перейти на Kotlin DSL и навести порядок в каталоге версий. ★ 3 580звёзд репо godot Правило для Cursor задаёт агенту стиль разработки на Godot 4.x: композиция сцен вместо наследования, сигналы вместо прямых вызовов, аккуратная работа с ресурсами. ★ 3 580звёзд репо go Набор стандартов разработки на Go для Cursor по мотивам руководства Google. Задаёт правила для обработки ошибок, управления памятью и структуры пакетов. ★ 3 580звёзд репо gitlab-ci Правило задаёт практики для структуры, запуска и поддержки GitLab CI/CD. Оно пригодится при настройке .gitlab-ci.yml и разборе проблем пайплайна. ★ 3 580звёзд репо github-actions Правило для Cursor задаёт жёсткие требования к workflow GitHub Actions: переиспользуемые сборки, кэш зависимостей, минимум прав у токена. ★ 3 580звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой