Vue-meta: Head script is added multiple times on navigation

Created on 5 Dec 2019  路  19Comments  路  Source: nuxt/vue-meta

I am opening a new issue, since https://github.com/nuxt/vue-meta/issues/381 is closed, but I am still finding that there is a problem.

Nuxt version

2.10.2

Vue-meta version

2.3.1

Reproduction link

https://github.com/simonbrent/nuxt-vue-meta-bug

Steps to reproduce

$ [email protected]:simonbrent/nuxt-vue-meta-bug.git
$ cd nuxt-vue-meta-bug
$ npm install
$ npx nuxt
  • Open the site in Chrome, with dev tools open to the navigation tab
  • Click on the link to "foo" - see that "head-script.js" is downloaded
  • Click on the link to "index"
  • Click on the link to "foo" - see that "head-script.js" is downloaded again

What is expected?

"head-script.js" is downloaded once, the first time you navigate to /foo

What is actually happening?

"head-script.js" is downloaded every time you navigate to /foo

pending question

All 19 comments

The behaviour you are describing is expected, page specific meta info is completely removed when you move away from that page. If its really downloaded again by your browser, you should make sure that head-script.js is cachable and/or maybe explicitly add a link prefetch for that file.

Please check the docs for once for a workaround

Wait, I only noticed now you are using vmid in your project as identifier. But as you are using Nuxt you should be using hid

@pimlie I have updated the repo to use hid and once, so that the code is now:

    head: () => ({
      script: [{
        hid  : 'head-script',
        src  : '/head-script.js',
        once : true,
      }],
    }),

Neither change made any difference to the behaviour.
I have also tried using once with a stylesheet, as shown in the docs you linked to:

    head: () => ({
      script: [{
        hid  : 'head-script',
        src  : '/head-script.js',
        once : true,
      }],
      link: [{
        hid  : 'head-style',
        rel  : 'stylesheet',
        href : '/head-style.css',
        once : true,
      }],
    }),

This also did not have the effect that I expected. head-style.css sets the body background to red. Given the docs, I expected that the first time I navigated to /foo, the body background would change to red, and stay that way on all subsequent navigations. This does not happen - going to / after /foo turns the background white again, going back to /foo downloads the css file again and turns the background red.

You can see this behaviour in the latest commit to the repo.

Thanks for your contribution to vue-meta! This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you would like this issue to remain open:

  1. Verify that you can still reproduce the issue in the latest version of vue-meta
  2. Comment the steps to reproduce it
    Issues that are labeled as pending will not be automatically marked as stale.

There have been no new releases since I reported this issue so it is not fixed and not stale

Could you create a working repro on codesandbox please?

Thanks, seems like once isnt working as it should indeed.

Not ideal, but this could maybe be a workaround for now? So just make sure to return the script once by using a custom var. For the css you could maybe try to remove the hid prop, it could be that the existence of a hid has the tag removed

```js
let headJsAdded = false
...
export default {
...
head () {
const meta = {
script: headJsAdded ? [] : [{
hid : 'head-script',
src : '/head-script.js',
once : true,
}],
link: [{
hid : 'head-style',
rel : 'stylesheet',
href : '/head-style.css',
once : true,
}]
}
headJsAdded = true
return meta
}),

I have a workaround already - my use case is only javascript, and the scripts I'm importing all add a value to window, so i'm doing:

head: function () {
  return (
    global.foo
      ? {}
      : {
        script: [{
          vmid: 'foo',
          src: '/foo.js',
        }],
      }
  );
},

Thanks for your contribution to vue-meta! This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you would like this issue to remain open:

  1. Verify that you can still reproduce the issue in the latest version of vue-meta
  2. Comment the steps to reproduce it
    Issues that are labeled as pending will not be automatically marked as stale.

This is still reproducible with nuxt 2.11.0 and vue-meta 2.3.2 - see https://codesandbox.io/s/github/simonbrent/nuxt-vue-meta-bug

Thanks, have added the pending label so stale bot doesnt close it as I wont expect to have time to fix this soon

This should be possble in the upcoming release by combining once & skip. (Just once wont work.)

let haveAddedTheJs = false // <-- outside the component scope

export default {
  ...
  head() {
    const skip = haveAddedTheJs
    haveAddedTheJs = true

    return {
      script: [
        { once: true, skip, src: '/file.js' }
      ]
    }
  }
}

Is that going to be the permanent solution then? It still seems pretty hacky.

Trying to fix this in vue-meta is even more hackier. With once we need to track the state whether the tag has been added or not. If you use head as a function then it returns a new object on every meta update, so we cant use the object itself.

This means if we want to support this in vue-meta itself then we need keep track of all head elements that have been added with once, and then on every metadata update render all elements with once again but only add them if we dont track them yet.

I feel keeping this tracking state (if a once: true tag has already been added or not) in userland as above is a nicer/cleaner solution. But if a lot of people think we should do this in vue-meta anyway then im happy to do so

Fair enough

Hi there, I'm encountering almost exactly same issue but with Google Maps API. Happens with navigating across pages as well. Tried the above fix with once and skip but doesn't work for my case.

You have included the Google Maps JavaScript API multiple times on this page. This may cause unexpected errors.

Same here with the Google Adsense Script

Hello, we have similar behavior with other Ad scripts. It works well if we put in nuxt.config.js, but if we want to only add to some pages, it seems to rerun the script on navigation, which it shouldn't. It's creating new, duplicatate Ad Managers each route change and getting silly. Is there a way to get the desired behavior without loading globally?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

iMomen picture iMomen  路  5Comments

hvalcourtSerdy picture hvalcourtSerdy  路  3Comments

nathanchase picture nathanchase  路  3Comments

achen224 picture achen224  路  9Comments

hurradieweltgehtunter picture hurradieweltgehtunter  路  4Comments