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..434609cb 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, @@ -511,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 @@ -552,7 +553,17 @@ 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