From 5dd8d0880c0ec3229df13758131f1e7b088fdb0f Mon Sep 17 00:00:00 2001 From: "Chris J. Shull" Date: Fri, 2 Jun 2023 17:26:45 -0700 Subject: [PATCH 1/5] update examples and minimize URLs --- README.md | 16 +++++++++++++++- examples/index.html | 14 +++++++++++--- src/index.ts | 29 ++++++++++++++++++----------- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 2e239c80..6d1b27ff 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ npm i @googlemaps/js-api-loader Alternatively you may add the umd package directly to the html document using the unpkg link. ```html - + ``` When adding via unpkg, the loader can be accessed at `google.maps.plugins.loader.Loader`. @@ -61,6 +61,20 @@ const mapOptions = { ``` +Using a promise for a specific library. + +```javascript +// Promise for a specific library +loader + .importLibrary('maps') + .then(({Map}) => { + new Map(document.getElementById("map"), mapOptions); + }) + .catch((e) => { + // do something + }); +``` + Using a promise for when the script has loaded. ```javascript diff --git a/examples/index.html b/examples/index.html index a5468f98..9d24ee39 100644 --- a/examples/index.html +++ b/examples/index.html @@ -35,7 +35,6 @@ @@ -55,14 +54,23 @@ apiKey: "", version: "weekly", libraries: ["places"], - nonce: "caffe67d7b989af3a1c7f4a1a6c79bd9fb2b4eb0", }); + // Promise for a specific library + loader + .importLibrary('maps') + .then(({Map}) => { + new Map(document.getElementById("map"), mapOptions); + }) + .catch((e) => { + // do something + }); + // Promise loader .load() .then((google) => { - new google.maps.Map(document.getElementById("map"), mapOptions); + // new google.maps.Map(document.getElementById("map"), mapOptions); }) .catch((e) => { // do something diff --git a/src/index.ts b/src/index.ts index 42fe9093..b0d486ae 100644 --- a/src/index.ts +++ b/src/index.ts @@ -492,6 +492,23 @@ export class Loader { return; } + const params = { + key: this.apiKey, + channel: this.channel, + client: this.client, + libraries: this.libraries, + v: this.version, + mapIds: this.mapIds, + language: this.language, + region: this.region, + authReferrerPolicy: this.authReferrerPolicy, + }; + // keep the URL minimal: + Object.keys(params).forEach( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (key) => !(params as any)[key] && delete (params as any)[key] + ); + if (!window?.google?.maps?.importLibrary) { // tweaked copy of https://developers.google.com/maps/documentation/javascript/load-maps-js-api#dynamic-library-import // which also sets the url, the id, and the nonce @@ -531,17 +548,7 @@ export class Loader { })); // @ts-ignore d[l] ? console.warn(p + " only loads once. Ignoring:", g) : (d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n))); - })({ - key: this.apiKey, - channel: this.channel, - client: this.client, - libraries: this.libraries, - v: this.version, - mapIds: this.mapIds, - language: this.language, - region: this.region, - authReferrerPolicy: this.authReferrerPolicy, - }); + })(params); /* eslint-enable */ } From cbca1ec7d7fe9564e4efc901f5da04c9aa4e5a58 Mon Sep 17 00:00:00 2001 From: "Chris J. Shull" Date: Tue, 6 Jun 2023 09:05:52 -0700 Subject: [PATCH 2/5] fix: add unit test for valid URL generation --- src/index.test.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/index.test.ts b/src/index.test.ts index 75f03a49..496d615e 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -98,6 +98,19 @@ test("setScript does not add second script with same id", async () => { expect(document.head.childNodes.length).toBe(1); }); +test("setScript adds a script to head with valid src", async () => { + const loader = new Loader({ apiKey: "foo" }); + + loader["setScript"](); + await 0; + + const script = document.head.childNodes[0] as HTMLScriptElement; + + expect(script.src).toEqual( + "https://maps.googleapis.com/maps/api/js?libraries=&key=foo&callback=google.maps.__ib__" + ); +}); + test("load should return a promise that resolves even if called twice", () => { const loader = new Loader({ apiKey: "foo" }); loader.importLibrary = (() => Promise.resolve()) as any; From d663511a639925463861f1e4cfecb55f94ab7973 Mon Sep 17 00:00:00 2001 From: "Chris J. Shull" Date: Mon, 12 Jun 2023 22:49:20 -0700 Subject: [PATCH 3/5] Fix: Support for Advanced markers (AdvancedMarkerView) #802 --- examples/index.html | 7 +++++-- src/index.test.ts | 45 ++++++++++++++++++++++++++++++++++++++++++++- src/index.ts | 14 ++++++++++++-- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/examples/index.html b/examples/index.html index 9d24ee39..522496c8 100644 --- a/examples/index.html +++ b/examples/index.html @@ -48,6 +48,7 @@ lng: 0, }, zoom: 4, + mapId: "DEMO_MAP_ID" }; const loader = new google.maps.plugins.loader.Loader({ @@ -59,8 +60,10 @@ // Promise for a specific library loader .importLibrary('maps') - .then(({Map}) => { - new Map(document.getElementById("map"), mapOptions); + .then(async ({Map}) => { + const map = new Map(document.getElementById("map"), mapOptions); + const {AdvancedMarkerElement} = await loader.importLibrary('marker'); + new AdvancedMarkerElement({map, position: mapOptions.center}); }) .catch((e) => { // do something diff --git a/src/index.test.ts b/src/index.test.ts index 496d615e..1e4618dd 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -107,7 +107,20 @@ test("setScript adds a script to head with valid src", async () => { const script = document.head.childNodes[0] as HTMLScriptElement; expect(script.src).toEqual( - "https://maps.googleapis.com/maps/api/js?libraries=&key=foo&callback=google.maps.__ib__" + "https://maps.googleapis.com/maps/api/js?libraries=core&key=foo&callback=google.maps.__ib__" + ); +}); + +test("setScript adds a script to head with valid src with libraries", async () => { + const loader = new Loader({ apiKey: "foo", libraries: ["marker", "places"] }); + + loader["setScript"](); + await 0; + + const script = document.head.childNodes[0] as HTMLScriptElement; + + expect(script.src).toEqual( + "https://maps.googleapis.com/maps/api/js?libraries=marker%2Cplaces&key=foo&callback=google.maps.__ib__" ); }); @@ -184,6 +197,7 @@ test("script onerror should retry", async () => { // wait for the first failure await 0; + await 0; expect(loader["errors"].length).toBe(1); // trigger the retry delay: jest.runAllTimers(); @@ -207,6 +221,7 @@ test("script onerror should reset retry mechanism with next loader", async () => let rejection = expect(loader.load()).rejects.toBeInstanceOf(Error); // wait for the first first failure await 0; + await 0; expect(loader["errors"].length).toBe(1); // trigger the retry delay: jest.runAllTimers(); @@ -221,6 +236,7 @@ test("script onerror should reset retry mechanism with next loader", async () => // wait for the second first failure await 0; + await 0; expect(loader["errors"].length).toBe(1); // trigger the retry delay: jest.runAllTimers(); @@ -241,6 +257,7 @@ test("script onerror should not reset retry mechanism with parallel loaders", as const rejection2 = expect(loader.load()).rejects.toBeInstanceOf(Error); // wait for the first first failure await 0; + await 0; jest.runAllTimers(); await Promise.all([rejection1, rejection2]); @@ -404,3 +421,29 @@ test("importLibrary resolves correctly", async () => { const core = await corePromise; expect(core).toEqual({ core: "fake" }); }); + +test("importLibrary can also set up bootstrap libraries (if bootstrap libraries empty)", async () => { + const loader = new Loader({ apiKey: "foo" }); + loader.importLibrary("marker"); + loader.importLibrary("places"); + + await 0; + + const script = document.head.childNodes[0] as HTMLScriptElement; + + expect(script.src).toEqual( + "https://maps.googleapis.com/maps/api/js?libraries=core%2Cmarker%2Cplaces&key=foo&callback=google.maps.__ib__" + ); +}); + +test("importLibrary resolves correctly even with different bootstrap libraries", async () => { + window.google = { maps: {} } as any; + google.maps.importLibrary = async (name) => ({ [name]: "fake" } as any); + + const loader = new Loader({ apiKey: "foo", libraries: ["places"] }); + const corePromise = loader.importLibrary("core"); + + const core = await corePromise; + expect(core).toEqual({ core: "fake" }); + expect(await loader.importLibrary("places")).toEqual({ places: "fake" }); +}); diff --git a/src/index.ts b/src/index.ts index b0d486ae..c7fee65c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -468,6 +468,7 @@ export class Loader { public importLibrary( name: "visualization" ): Promise; + public importLibrary(name: Library): Promise; public importLibrary(name: Library): Promise { this.execute(); return google.maps.importLibrary(name); @@ -496,7 +497,7 @@ export class Loader { key: this.apiKey, channel: this.channel, client: this.client, - libraries: this.libraries, + libraries: this.libraries.length && this.libraries, v: this.version, mapIds: this.mapIds, language: this.language, @@ -552,7 +553,16 @@ export class Loader { /* eslint-enable */ } - this.importLibrary("core").then( + // While most libraries populate the global namespace when loaded via bootstrap params, + // this is not the case for "marker" when used with the inline bootstrap loader + // (and maybe others in the future). So ensure there is an importLibrary for each: + const libraryPromises = this.libraries.map((library) => + this.importLibrary(library) + ); + // ensure at least one library, to kick off loading... + if (!libraryPromises.length) + libraryPromises.push(this.importLibrary("core")); + Promise.all(libraryPromises).then( () => this.callback(), (error) => { const event = new ErrorEvent("error", { error }); // for backwards compat From 5c1af2767ce588ab11f9d8ff076dac9678fe9cfa Mon Sep 17 00:00:00 2001 From: "Chris J. Shull" Date: Mon, 12 Jun 2023 22:51:21 -0700 Subject: [PATCH 4/5] formatting fix --- src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index c7fee65c..ac8aa6ed 100644 --- a/src/index.ts +++ b/src/index.ts @@ -560,8 +560,9 @@ export class Loader { this.importLibrary(library) ); // ensure at least one library, to kick off loading... - if (!libraryPromises.length) + if (!libraryPromises.length) { libraryPromises.push(this.importLibrary("core")); + } Promise.all(libraryPromises).then( () => this.callback(), (error) => { From 97f33c89f201aa35735fa765ccb393dcfe88c4fa Mon Sep 17 00:00:00 2001 From: "Chris J. Shull" Date: Tue, 13 Jun 2023 15:54:14 -0700 Subject: [PATCH 5/5] clarify comment --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index ac8aa6ed..434609cb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -512,7 +512,7 @@ export class Loader { if (!window?.google?.maps?.importLibrary) { // tweaked copy of https://developers.google.com/maps/documentation/javascript/load-maps-js-api#dynamic-library-import - // which also sets the url, the id, and the nonce + // which also sets the base url, the id, and the nonce /* eslint-disable */ ((g) => { // @ts-ignore