Skip to content

Commit 966de43

Browse files
authored
refactor(google-maps)!: rename googleMaps expose to mapsApi (#695)
1 parent bf560fd commit 966de43

File tree

6 files changed

+251
-10
lines changed

6 files changed

+251
-10
lines changed

docs/content/docs/4.migration-guide/1.v0-to-v1.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,28 @@ The top-level `center` and `zoom` props on `<ScriptGoogleMaps>`{lang="html"} are
392392
+<ScriptGoogleMaps :map-options="{ center: { lat, lng }, zoom: 12 }" />
393393
```
394394

395+
#### Template Ref `googleMaps` Renamed to `mapsApi`
396+
397+
The `googleMaps` template-ref key on `<ScriptGoogleMaps>`{lang="html"} has been renamed to `mapsApi` to better reflect what it holds (the `google.maps` API namespace, not the component itself). The old key still works as a deprecated alias and emits a one-shot dev-mode warning when read.
398+
399+
```diff
400+
const mapRef = ref()
401+
onMounted(() => {
402+
- console.log(mapRef.value?.googleMaps)
403+
+ console.log(mapRef.value?.mapsApi)
404+
})
405+
```
406+
407+
The same rename applies to `<ScriptGoogleMapsOverlayView>`{lang="html"}: its exposed `overlay` key is now `overlayView`, with `overlay` kept as a deprecated alias.
408+
409+
```diff
410+
const overlayRef = ref()
411+
onMounted(() => {
412+
- console.log(overlayRef.value?.overlay)
413+
+ console.log(overlayRef.value?.overlayView)
414+
})
415+
```
416+
395417
### Google Maps Static Placeholder ([#673](https://github.com/nuxt/scripts/pull/673))
396418

397419
v1 extracts the built-in static map placeholder into a standalone [`<ScriptGoogleMapsStaticMap>`{lang="html"}](/scripts/google-maps/api/static-map) component. This removes the following props from `<ScriptGoogleMaps>`{lang="html"}:

docs/content/scripts/google-maps/2.api/1.script-google-maps.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ Access the basic Google Maps instances via a template ref. The exposed object co
3535

3636
| Property | Type | Description |
3737
|----------|------|-------------|
38-
| `googleMaps` | `Ref<typeof google.maps \| undefined>`{lang="html"} | The core Maps API library. |
38+
| `mapsApi` | `ShallowRef<typeof google.maps \| undefined>`{lang="html"} | The core Maps API namespace (`google.maps`). |
39+
| `googleMaps` | `ShallowRef<typeof google.maps \| undefined>`{lang="html"} | **Deprecated.** Alias for `mapsApi`; emits a dev-mode warning. Slated for removal in a future major version. |
3940
| `map` | `ShallowRef<google.maps.Map>`{lang="html"} | The map instance. |
4041
| `resolveQueryToLatLng` | `(query) => Promise<LatLngLiteral>`{lang="html"} | Geocode an address to coordinates. |
4142
| `importLibrary` | `(name) => Promise<Library>`{lang="html"} | Load additional Google Maps libraries at runtime. |

packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMaps.vue

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,17 @@ export interface ScriptGoogleMapsProps {
7878
7979
export interface ScriptGoogleMapsExpose {
8080
/**
81-
* A reference to the loaded Google Maps API, or `undefined` if not yet loaded.
81+
* A reference to the loaded Google Maps API namespace (`google.maps`), or
82+
* `undefined` if not yet loaded.
83+
*/
84+
mapsApi: ShallowRef<typeof google.maps | undefined>
85+
/**
86+
* A reference to the loaded Google Maps API namespace, or `undefined` if not
87+
* yet loaded.
88+
*
89+
* @deprecated Use `mapsApi` instead. The `googleMaps` alias will be removed
90+
* in a future major version.
91+
* @see https://scripts.nuxt.com/docs/migration-guide/v0-to-v1
8292
*/
8393
googleMaps: ShallowRef<typeof google.maps | undefined>
8494
/**
@@ -147,7 +157,7 @@ import { defu } from 'defu'
147157
import { tryUseNuxtApp, useHead, useRuntimeConfig } from 'nuxt/app'
148158
import { computed, onBeforeUnmount, onMounted, provide, ref, shallowRef, toRaw, useAttrs, useTemplateRef, watch } from 'vue'
149159
import ScriptAriaLoadingIndicator from '../ScriptAriaLoadingIndicator.vue'
150-
import { MAP_INJECTION_KEY, waitForMapsReady, warnDeprecatedTopLevelMapProps } from './useGoogleMapsResource'
160+
import { defineDeprecatedAlias, MAP_INJECTION_KEY, waitForMapsReady, warnDeprecatedTopLevelMapProps } from './useGoogleMapsResource'
151161
152162
const props = withDefaults(defineProps<ScriptGoogleMapsProps>(), {
153163
// @ts-expect-error untyped
@@ -315,14 +325,27 @@ function importLibrary<T>(key: string): Promise<T> {
315325
return cached as Promise<T>
316326
}
317327
318-
const googleMaps: ScriptGoogleMapsExpose = {
328+
const exposed: ScriptGoogleMapsExpose = {
329+
mapsApi,
330+
// Plain alias for production. In dev, replaced below with a getter that
331+
// emits a one-shot deprecation warning. Both forms return the same
332+
// shallow ref as `mapsApi`.
319333
googleMaps: mapsApi,
320334
map,
321335
resolveQueryToLatLng,
322336
importLibrary,
323337
}
324338
325-
defineExpose<ScriptGoogleMapsExpose>(googleMaps)
339+
if (import.meta.dev) {
340+
defineDeprecatedAlias(
341+
exposed,
342+
'googleMaps',
343+
'mapsApi',
344+
'[nuxt-scripts] <ScriptGoogleMaps> expose key "googleMaps" is deprecated; use "mapsApi" instead. See https://scripts.nuxt.com/docs/migration-guide/v0-to-v1',
345+
)
346+
}
347+
348+
defineExpose<ScriptGoogleMapsExpose>(exposed)
326349
327350
// Shared InfoWindow group: only one InfoWindow open at a time within this map
328351
let activeInfoWindow: google.maps.InfoWindow | undefined
@@ -340,7 +363,7 @@ provide(MAP_INJECTION_KEY, {
340363
onMounted(() => {
341364
watch(isMapReady, (v) => {
342365
if (v) {
343-
emits('ready', googleMaps)
366+
emits('ready', exposed)
344367
}
345368
})
346369
watch(status, (v) => {

packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ export interface ScriptGoogleMapsOverlayViewSlots {
6363
6464
export interface ScriptGoogleMapsOverlayViewExpose {
6565
/** The underlying `OverlayView` instance. */
66+
overlayView: ShallowRef<google.maps.OverlayView | undefined>
67+
/**
68+
* The underlying `OverlayView` instance.
69+
*
70+
* @deprecated Use `overlayView` instead. The `overlay` alias will be
71+
* removed in a future major version.
72+
* @see https://scripts.nuxt.com/docs/migration-guide/v0-to-v1
73+
*/
6674
overlay: ShallowRef<google.maps.OverlayView | undefined>
6775
/** The current data-state of the overlay, either 'open' or 'closed'. */
6876
dataState: Readonly<ShallowRef<'open' | 'closed'>>
@@ -72,7 +80,7 @@ export interface ScriptGoogleMapsOverlayViewExpose {
7280
<script setup lang="ts">
7381
import { computed, inject, ref, useTemplateRef, watch } from 'vue'
7482
import { MARKER_CLUSTERER_INJECTION_KEY } from './types'
75-
import { MARKER_INJECTION_KEY, useGoogleMapsResource } from './useGoogleMapsResource'
83+
import { defineDeprecatedAlias, MARKER_INJECTION_KEY, useGoogleMapsResource } from './useGoogleMapsResource'
7684
7785
defineOptions({
7886
inheritAttrs: false,
@@ -327,7 +335,25 @@ if (markerClustererContext && markerContext) {
327335
)
328336
}
329337
330-
defineExpose<ScriptGoogleMapsOverlayViewExpose>({ overlay, dataState })
338+
const exposed: ScriptGoogleMapsOverlayViewExpose = {
339+
overlayView: overlay,
340+
// Plain alias for production. In dev, replaced below with a getter that
341+
// emits a one-shot deprecation warning. Both forms return the same
342+
// shallow ref as `overlayView`.
343+
overlay,
344+
dataState,
345+
}
346+
347+
if (import.meta.dev) {
348+
defineDeprecatedAlias(
349+
exposed,
350+
'overlay',
351+
'overlayView',
352+
'[nuxt-scripts] <ScriptGoogleMapsOverlayView> expose key "overlay" is deprecated; use "overlayView" instead. See https://scripts.nuxt.com/docs/migration-guide/v0-to-v1',
353+
)
354+
}
355+
356+
defineExpose<ScriptGoogleMapsOverlayViewExpose>(exposed)
331357
</script>
332358

333359
<template>

packages/script/src/runtime/components/GoogleMaps/useGoogleMapsResource.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,37 @@ export interface GoogleMapsResourceContext {
4141
mapsApi: typeof google.maps
4242
}
4343

44+
/**
45+
* Defines a deprecated property alias on an exposed object. Reading the alias
46+
* returns the value of the canonical key and emits a one-shot
47+
* `console.warn` (so repeated reads don't spam the console).
48+
*
49+
* Used to provide backward-compatible renames on `defineExpose` payloads
50+
* without breaking existing template-ref consumers. Call sites should wrap
51+
* this in `if (import.meta.dev)` so production builds skip the getter
52+
* entirely and the alias stays a plain data property.
53+
*/
54+
export function defineDeprecatedAlias<T extends object, K extends keyof T>(
55+
target: T,
56+
alias: string,
57+
canonicalKey: K,
58+
message: string,
59+
): T {
60+
let warned = false
61+
Object.defineProperty(target, alias, {
62+
get() {
63+
if (!warned) {
64+
warned = true
65+
console.warn(message)
66+
}
67+
return target[canonicalKey]
68+
},
69+
enumerable: true,
70+
configurable: true,
71+
})
72+
return target
73+
}
74+
4475
/**
4576
* Emits dev-mode deprecation warnings for the legacy top-level `center` and
4677
* `zoom` props on `<ScriptGoogleMaps>`. Both props still work, but new code

test/unit/google-maps-components.test.ts

Lines changed: 140 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import type { MocksType } from './__helpers__/google-maps-test-utils'
44
*/
55
import { defu } from 'defu'
66
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
7-
import { ref } from 'vue'
8-
import { warnDeprecatedTopLevelMapProps } from '../../packages/script/src/runtime/components/GoogleMaps/useGoogleMapsResource'
7+
import { ref, shallowRef } from 'vue'
8+
import { defineDeprecatedAlias, warnDeprecatedTopLevelMapProps } from '../../packages/script/src/runtime/components/GoogleMaps/useGoogleMapsResource'
99
import {
1010

1111
simulateAdvancedMarkerLifecycle,
@@ -507,3 +507,141 @@ describe('scriptGoogleMaps top-level center/zoom deprecation', () => {
507507
})
508508
})
509509
})
510+
511+
describe('defineDeprecatedAlias', () => {
512+
// Backs the `googleMaps` → `mapsApi` and `overlay` → `overlayView` renames
513+
// on the exposed objects of `<ScriptGoogleMaps>` and
514+
// `<ScriptGoogleMapsOverlayView>`. Reading the alias must:
515+
// - return the same value as the canonical key (so existing call sites
516+
// keep working)
517+
// - emit a one-shot dev-mode console.warn (no spam on repeated reads)
518+
519+
let warnSpy: ReturnType<typeof vi.spyOn>
520+
521+
beforeEach(() => {
522+
warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
523+
})
524+
525+
afterEach(() => {
526+
warnSpy.mockRestore()
527+
})
528+
529+
describe('googleMaps alias for mapsApi', () => {
530+
function createMapExposed() {
531+
const mapsApi = shallowRef<any>({ Marker: class {} })
532+
const exposed: any = {
533+
mapsApi,
534+
googleMaps: mapsApi,
535+
}
536+
defineDeprecatedAlias(
537+
exposed,
538+
'googleMaps',
539+
'mapsApi',
540+
'[nuxt-scripts] <ScriptGoogleMaps> expose key "googleMaps" is deprecated; use "mapsApi" instead. See https://scripts.nuxt.com/docs/migration-guide/v0-to-v1',
541+
)
542+
return { exposed, mapsApi }
543+
}
544+
545+
it('returns the same shallow ref as mapsApi', () => {
546+
const { exposed, mapsApi } = createMapExposed()
547+
548+
expect(exposed.googleMaps).toBe(mapsApi)
549+
expect(exposed.googleMaps).toBe(exposed.mapsApi)
550+
})
551+
552+
it('fires a dev warning on first read', () => {
553+
const { exposed } = createMapExposed()
554+
555+
// Touch the alias
556+
void exposed.googleMaps
557+
558+
expect(warnSpy).toHaveBeenCalledTimes(1)
559+
expect(warnSpy.mock.calls[0]![0]).toContain('"googleMaps" is deprecated')
560+
expect(warnSpy.mock.calls[0]![0]).toContain('mapsApi')
561+
expect(warnSpy.mock.calls[0]![0]).toContain('migration-guide/v0-to-v1')
562+
})
563+
564+
it('does not spam the warning on repeated reads', () => {
565+
const { exposed } = createMapExposed()
566+
567+
void exposed.googleMaps
568+
void exposed.googleMaps
569+
void exposed.googleMaps
570+
571+
expect(warnSpy).toHaveBeenCalledTimes(1)
572+
})
573+
574+
it('reading the canonical mapsApi key does not warn', () => {
575+
const { exposed } = createMapExposed()
576+
577+
void exposed.mapsApi
578+
void exposed.mapsApi
579+
580+
expect(warnSpy).not.toHaveBeenCalled()
581+
})
582+
583+
it('alias points to live ref (updates with mapsApi changes)', () => {
584+
const { exposed, mapsApi } = createMapExposed()
585+
586+
// Both keys should reflect the new value via the underlying ShallowRef
587+
mapsApi.value = { newValue: true }
588+
589+
expect(exposed.mapsApi.value).toEqual({ newValue: true })
590+
expect(exposed.googleMaps.value).toEqual({ newValue: true })
591+
})
592+
})
593+
594+
describe('overlay alias for overlayView', () => {
595+
function createOverlayExposed() {
596+
const overlayView = shallowRef<any>({ setMap: vi.fn() })
597+
const exposed: any = {
598+
overlayView,
599+
overlay: overlayView,
600+
dataState: shallowRef<'open' | 'closed'>('closed'),
601+
}
602+
defineDeprecatedAlias(
603+
exposed,
604+
'overlay',
605+
'overlayView',
606+
'[nuxt-scripts] <ScriptGoogleMapsOverlayView> expose key "overlay" is deprecated; use "overlayView" instead. See https://scripts.nuxt.com/docs/migration-guide/v0-to-v1',
607+
)
608+
return { exposed, overlayView }
609+
}
610+
611+
it('returns the same shallow ref as overlayView', () => {
612+
const { exposed, overlayView } = createOverlayExposed()
613+
614+
expect(exposed.overlay).toBe(overlayView)
615+
expect(exposed.overlay).toBe(exposed.overlayView)
616+
})
617+
618+
it('fires a dev warning on first read', () => {
619+
const { exposed } = createOverlayExposed()
620+
621+
void exposed.overlay
622+
623+
expect(warnSpy).toHaveBeenCalledTimes(1)
624+
expect(warnSpy.mock.calls[0]![0]).toContain('"overlay" is deprecated')
625+
expect(warnSpy.mock.calls[0]![0]).toContain('overlayView')
626+
})
627+
628+
it('does not spam the warning on repeated reads', () => {
629+
const { exposed } = createOverlayExposed()
630+
631+
void exposed.overlay
632+
void exposed.overlay
633+
void exposed.overlay
634+
635+
expect(warnSpy).toHaveBeenCalledTimes(1)
636+
})
637+
638+
it('reading the canonical overlayView key does not warn', () => {
639+
const { exposed } = createOverlayExposed()
640+
641+
void exposed.overlayView
642+
void exposed.dataState
643+
644+
expect(warnSpy).not.toHaveBeenCalled()
645+
})
646+
})
647+
})

0 commit comments

Comments
 (0)