How to load Google API client library with SvelteKit
Asked Answered
T

2

5

I'm new to SvelteKit and trying to find out how to load the Google client library for Javascript.

Google tells me to do it like this:

<head>
    <script src="https://apis.google.com/js/api.js"></script>
    <script>
      function start() {
        // Initializes the client with the API key and the Translate API.
        gapi.client.init({
          'apiKey': 'YOUR_API_KEY',
          'discoveryDocs': ['https://www.googleapis.com/discovery/v1/apis/translate/v2/rest'],
        }).then(function() {
          // Executes an API request, and returns a Promise.
          // The method name `language.translations.list` comes from the API discovery.
          return gapi.client.language.translations.list({
            q: 'hello world',
            source: 'en',
            target: 'de',
          });
        }).then(function(response) {
          console.log(response.result.data.translations[0].translatedText);
        }, function(reason) {
          console.log('Error: ' + reason.result.error.message);
        });
      };

      // Loads the JavaScript client library and invokes `start` afterwards.
      gapi.load('client', start);
    </script>
  </head>

The problem is that SvelteKit doesn't allow 2 or more script tags on a page (I don't want it to be the layout page).

<script src="https://apis.google.com/js/api.js"></script>
<script>
    import { onMount } from 'svelte';
    
    gapi.client.init({...
</script>  

This results in follwing error message:

A component can only have one instance-level <script> element

As my intention is to create a progressive web app (PWA) using Workbox I don't want to import the Google library as described here because the package containing this library would become too heavy.

Any ideas how to load the Google client library? Maybe there's a Workbox way to do it? Couldn't find a SvelteKit example on Google or YouTube.

Thanks in advance

Tradeswoman answered 3/1, 2022 at 18:56 Comment(0)
B
6

The svelte:head tag allows you to add resources to the document head when a component is loaded. This example should work:

<script>
  const start = async () => {
    // Initializes the client with the API key and the Translate API.
    // @ts-ignore
    gapi.client.init({
      'apiKey': 'YOUR_API_KEY',
      'discoveryDocs': ['https://www.googleapis.com/discovery/v1/apis/translate/v2/rest'],
    }).then(function() {
      // Executes an API request, and returns a Promise.
      // The method name `language.translations.list` comes from the API discovery.
      return gapi.client.language.translations.list({
        q: 'hello world',
        source: 'en',
        target: 'de',
      });
    }).then(function(response) {
      console.log(response.result.data.translations[0].translatedText);
    }, function(reason) {
      console.log('Error: ' + reason.result.error.message);
    });
  };

  const initializeGapi = async () => {
    gapi.load('client', start);
  }
</script>

<svelte:head>
  <script src="https://apis.google.com/js/api.js" on:load={initializeGapi}></script>
</svelte:head>
Bola answered 3/1, 2022 at 19:14 Comment(4)
Thanks for your reply! When doing a build I get following error: "'initializeGapi' is not defined". The on:load part can't reference to the const initializeGapiTradeswoman
I am not sure what you copied. But if you insert this into your index.svelte it runs fine. At least it does on my PC.Bola
Strange. Have to figure out what the problem is on my side. I don't have the code on index.svelte but on another page but that shouldn't make a difference imhoTradeswoman
I got it working by adding this at the top of the .svelte file <script context="module"> export const ssr = false </script>Boyt
B
2

I've made something like this. Save it as GoogleMap.svelte to your lib folder. and use it like this;

<GoogleMap
 {map}
 globally
 on:load={() => {
  console.log('MAP SAYS IM LOADED');
 }}
/>
  • Map is a reference object
  • globally defines it to window.map
    <script>
        import { onMount } from 'svelte';
        import { createEventDispatcher } from 'svelte';
        const dispatch = createEventDispatcher();
    
        //import mapStyles from './map-styles'; // optional
    
        export let globally = false;
        export let map;

        let src = '';
        const key = ''; 
    
        // @ts-ignore
        let container;
        let zoom = 8;
        let center = { lat: 37.5742776, lng: 43.7260158 };
    
        onMount(() => {
            Object.assign(window, {
                mapLoaded: () => {
                    // @ts-ignore
                    map = new google.maps.Map(container, {
                        zoom,
                        center
                        // styles: mapStyles
                    });
                    dispatch('load', true);
                    if (globally) {
                        Object.assign(window, { map });
                    }
                }
            });

            //Assign
            src = `https://maps.googleapis.com/maps/api/js?key=${key}&callback=mapLoaded`;
        });
    </script>
    
<!-- This is tailwind css class change with whatever fits to your case. -->
    <div class="w-full h-full" bind:this={container} />
    <svelte:head>
        {#if src}
            <script {src}></script>
        {/if}
    </svelte:head>
Bahadur answered 13/2, 2023 at 1:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.