xkjyeah / vue-google-maps

Google maps component for vue with 2-way data binding
https://xkjyeah.github.io/vue-google-maps/
1.88k stars 475 forks source link

GMaps script tag issues when prerendering #430

Open beaulac opened 6 years ago

beaulac commented 6 years ago

When prerendering, the rendered html contains the appended Gmaps script tag. This causes two issues:

  1. When the page is initially loaded, the script tries to execute callback vueGoogleMapsInit, which possibly doesn't exist yet since the script could be loaded before Vue, producing an error.
  2. After vue-google-map loads, it adds a second GMaps script tag, producing warnings about doubly-including GMaps.

The typeof document === 'undefined' check for server-side rendering doesn't apply for prerendering. It would be nice to be able to optionally pass a function skipLoad in options to determine if loading should be skipped, with the default implementation remaining a check for the presence of document to maintain backwards compatibility.

This would also require a slight change in building the scripts' query params, since currently all options keys are included as-is, and this option should be excluded.

nachomozo commented 4 years ago

I have exactly the same issue when prerendering. Any update on this or at least any workaround?

beaulac commented 4 years ago

Using Puppeteer as the renderer, the workaround I used was to inject a property into the window when prerendering, and checking for its presence when initializing VGM:

// In prerendering config, configure the renderer:
new PuppeteerRenderer({ injectProperty: '__PRERENDER_INJECT',  inject: {} })

// In app, check for the injected property:
import * as VueGoogleMaps from "vue2-google-maps";
Vue.use(VueGoogleMaps, {
  load: window['__PRERENDER_INJECT']
    ? null
    : { key: /* ... */ }
});

This relies on the (undocumented?) fact that VGM doesn't load the API if load is falsy in options

Pretty ugly, but it works. Hope this helps!

nachomozo commented 4 years ago

It seems like a good solution. I will try it. Thank you @beaulac!

nachomozo commented 4 years ago

I confirm that this workaround works.

For future readers, I use vue-cli-plugin-prerender-spa. I have adapted the @beaulac solution. In my case the configuration is as follows.

// vue.config.js

...
prerenderSpa: {
      ...
      customRendererConfig: {
        injectProperty: "__PRERENDER_INJECTED",
        inject: {}
      }
      ...
}
...

And as @beaulac says:

// src/main.js

import * as VueGoogleMaps from "vue2-google-maps";
Vue.use(VueGoogleMaps, {
  load: window['__PRERENDER_INJECTED']
    ? null
    : { key: /* ... */ }
});