Skip to content

Commit

Permalink
Added support for dynamic imports (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
cgalvan authored May 15, 2024
1 parent ab5c0ff commit 516580b
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 25 deletions.
37 changes: 24 additions & 13 deletions examples/autoComplete/example.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@ let placesService;
let predictionItems = [];
let markers = [];

function initMap() {
async function initMap() {
const austinCoords = { lat: 30.268193, lng: -97.7457518 }; // Austin, TX :)

map = new google.maps.Map(document.getElementById("map"), {
const { Map } = await google.maps.importLibrary("maps");
map = new Map(document.getElementById("map"), {
center: austinCoords,
zoom: 11,
mapId: "DEMO_MAP_ID",
});

placesService = new google.maps.places.PlacesService(map);
const autocompleteService = new google.maps.places.AutocompleteService();
const { AutocompleteService, PlacesService, PlacesServiceStatus } = await google.maps.importLibrary("places");
placesService = new PlacesService(map);
const autocompleteService = new AutocompleteService();

const searchInput = $("#search-input");
searchInput.autocomplete({
Expand All @@ -48,7 +51,7 @@ function initMap() {
locationBias: map.getCenter(),
},
function (predictions, status) {
if (status != google.maps.places.PlacesServiceStatus.OK || !predictions) {
if (status != PlacesServiceStatus.OK || !predictions) {
response([]);
return;
}
Expand Down Expand Up @@ -100,30 +103,35 @@ function getPredictionInfo(prediction) {
}
}

function getPlaceDetails(placeId) {
async function getPlaceDetails(placeId) {
const { PlacesServiceStatus } = await google.maps.importLibrary("places");

var request = {
placeId: placeId,
};

placesService.getDetails(request, function (result, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
if (status === PlacesServiceStatus.OK) {
createMarker(result);
map.setCenter(result.geometry.location);
map.setZoom(14);
}
});
}

function getTextSearch(query) {
async function getTextSearch(query) {
var request = {
query: query,
location: map.getCenter(),
};

const resultsBounds = new google.maps.LatLngBounds();
const { PlacesServiceStatus } = await google.maps.importLibrary("places");

const { LatLngBounds } = await google.maps.importLibrary("core");
const resultsBounds = new LatLngBounds();

placesService.textSearch(request, function (results, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
if (status === PlacesServiceStatus.OK) {
results.map((result) => {
createMarker(result);

Expand All @@ -137,18 +145,21 @@ function getTextSearch(query) {
});
}

function createMarker(place) {
async function createMarker(place) {
if (!place.geometry || !place.geometry.location) return;

const marker = new google.maps.Marker({
const { AdvancedMarkerElement } = await google.maps.importLibrary("marker");
const marker = new AdvancedMarkerElement({
map,
position: place.geometry.location,
});

markers.push(marker);

// TODO: Update this example to display an InfoWindow when clicking on the marker to display additional details (from getDetails)
marker.addListener(marker, "click", () => {
marker.addListener("click", () => {
console.log("MARKER CLICKED", place.name);
});
}

initMap();
47 changes: 41 additions & 6 deletions examples/autoComplete/google.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>

<!-- Client logic example -->
<script type="text/javascript" src="./example.js"></script>
<script type="module" src="./example.js"></script>
</head>
<body>
<!-- Search box and map elements for the example -->
Expand All @@ -19,10 +19,45 @@
<div id="map"></div>

<!-- Google Maps API import -->
<script
async
defer
src="https://maps.googleapis.com/maps/api/js?key={{GOOGLE_API_KEY}}&callback=initMap&libraries=places"
></script>
<script>
((g) => {
var h,
a,
k,
p = "The Google Maps JavaScript API",
c = "google",
l = "importLibrary",
q = "__ib__",
m = document,
b = window;
b = b[c] || (b[c] = {});
var d = b.maps || (b.maps = {}),
r = new Set(),
e = new URLSearchParams(),
u = () =>
h ||
(h = new Promise(async (f, n) => {
await (a = m.createElement("script"));
e.set("libraries", [...r] + "");
for (k in g)
e.set(
k.replace(/[A-Z]/g, (t) => "_" + t[0].toLowerCase()),
g[k],
);
e.set("callback", c + ".maps." + q);
a.src = `https://maps.${c}apis.com/maps/api/js?` + e;
d[q] = f;
a.onerror = () => (h = n(Error(p + " could not load.")));
a.nonce = m.querySelector("script[nonce]")?.nonce || "";
m.head.append(a);
}));
d[l]
? console.warn(p + " only loads once. Ignoring:", g)
: (d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)));
})({
key: "{{GOOGLE_API_KEY}}",
v: "weekly",
});
</script>
</body>
</html>
8 changes: 2 additions & 6 deletions examples/autoComplete/index.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>

<!-- Client logic example -->
<script type="text/javascript" src="./example.js"></script>
<script type="module" src="./example.js"></script>
</head>
<body>
<!-- Search box and map elements for the example -->
Expand All @@ -19,10 +19,6 @@
<div id="map"></div>

<!-- Migration script import -->
<script
async
defer
src="../../dist/amazonLocationMigrationAdapter.js?callback=initMap&region={{REGION}}&map={{MAP_NAME}}&placeIndex={{PLACE_INDEX}}&apiKey={{AMAZON_LOCATION_API_KEY}}"
></script>
<script src="../../dist/amazonLocationMigrationAdapter.js?region={{REGION}}&map={{MAP_NAME}}&placeIndex={{PLACE_INDEX}}&apiKey={{AMAZON_LOCATION_API_KEY}}"></script>
</body>
</html>
51 changes: 51 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,57 @@ const migrationInit = async function () {
PlacesService: MigrationPlacesService,
PlacesServiceStatus: PlacesServiceStatus,
},

// Handle dynamic imports, e.g. const { Map } = await google.maps.importLibrary("maps");
importLibrary: (library) => {
return new Promise((resolve) => {
switch (library) {
case "core":
resolve({
ControlPosition: MigrationControlPosition,
LatLng: MigrationLatLng,
LatLngBounds: MigrationLatLngBounds,
});
break;

case "maps":
resolve({
InfoWindow: MigrationInfoWindow,
Map: MigrationMap,
});
break;

case "places":
resolve({
AutocompleteService: MigrationAutocompleteService,
PlacesService: MigrationPlacesService,
PlacesServiceStatus: PlacesServiceStatus,
});
break;

case "routes":
resolve({
DirectionsRenderer: MigrationDirectionsRenderer,
DirectionsService: MigrationDirectionsService,
DirectionsStatus: DirectionsStatus,
TravelMode: TravelMode,
});
break;

case "marker":
resolve({
AdvancedMarkerElement: MigrationMarker,
Marker: MigrationMarker,
});
break;

default:
console.error(`Unsupported library: ${library}`);
resolve({});
break;
}
});
},
},
};

Expand Down
69 changes: 69 additions & 0 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ const mockMigrationCallback = jest.fn();
// Import the migration adapter after our mock script HTMLScriptElement has been setup
import "../src/index";

// Spy on console.error so we can verify it gets called in error cases
jest.spyOn(console, "error").mockImplementation(() => {});

afterEach(() => {
jest.clearAllMocks();
});
Expand Down Expand Up @@ -55,3 +58,69 @@ test("importing the adapter should populate google.maps namespace for direct loa
// Verify our mock callback has been invoked after loading the adapter
expect(mockMigrationCallback).toHaveBeenCalledTimes(1);
});

test("can dynamically import core classes", async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const google = (window as any).google;

const { ControlPosition, LatLng, LatLngBounds } = await google.maps.importLibrary("core");

expect(ControlPosition).toBeDefined();
expect(LatLng).toBeDefined();
expect(LatLngBounds).toBeDefined();
});

test("can dynamically import maps classes", async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const google = (window as any).google;

const { InfoWindow, Map } = await google.maps.importLibrary("maps");

expect(InfoWindow).toBeDefined();
expect(Map).toBeDefined();
});

test("can dynamically import places classes", async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const google = (window as any).google;

const { AutocompleteService, PlacesService, PlacesServiceStatus } = await google.maps.importLibrary("places");

expect(AutocompleteService).toBeDefined();
expect(PlacesService).toBeDefined();
expect(PlacesServiceStatus).toBeDefined();
});

test("can dynamically import routes classes", async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const google = (window as any).google;

const { DirectionsRenderer, DirectionsService, DirectionsStatus, TravelMode } = await google.maps.importLibrary(
"routes",
);

expect(DirectionsRenderer).toBeDefined();
expect(DirectionsService).toBeDefined();
expect(DirectionsStatus).toBeDefined();
expect(TravelMode).toBeDefined();
});

test("can dynamically import marker classes", async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const google = (window as any).google;

const { AdvancedMarkerElement, Marker } = await google.maps.importLibrary("marker");

expect(AdvancedMarkerElement).toBeDefined();
expect(Marker).toBeDefined();
});

test("should report an error if a library we don't support is requested", async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const google = (window as any).google;

const { ThisClassWontExist } = await google.maps.importLibrary("INVALID_LIBRARY");

expect(ThisClassWontExist).toBeUndefined();
expect(console.error).toHaveBeenCalledTimes(1);
});

0 comments on commit 516580b

Please sign in to comment.