Search code examples
javascriptdomnuxt.jssingle-page-applicationpageload

Re-run external JavaScript with NuxtLink


I´m using multiple external JavaScript-Files for the client- /frontend-Design of my Nuxt Application ( Nuxt Universal Mode, server-side rendering + client-side navigation ), putting them in the nuxt.config.js-file.

nuxt.config.js

<script>
export default {
  head () {
    return {
      script: [
        { src: '/scripts/jquery.min.js', body: true },
        { src: '/scripts/jquery.dropotron.min.js', body: true },
        { src: '/scripts/browser.min.js', body: true },
        { src: '/scripts/breakpoints.min.js', body: true },
        { src: '/scripts/util.js', body: true },
        { src: '/scripts/main.js', body: true },
        { src: '/scripts/owa.js', body: true }
      ]
    }
  }
}
</script>

Everything´s working well on initial pageview, but unfortunately when using NuxtLink, to navigate to another page, the EventListeners vanish. I conclude from this, that the Virtual DOM is re-rerendered but once it´s finished, the JavaScript functions doesn´t run again.

Of course I could use a-Tags instead of NuxtLink, so the whole site will load again, so will do the scripts, but that´s bad practice and has nothing to do with SPA.

I´ve already tried Nuxt Middleware, but removing the Scripts ( seen in the example code ) in the Head doesn´t work.

middleware/rerunJs.js

  const scripts = context.app.head.script
  context.app.head.script = undefined
  context.app.head.script = scripts

Any ideas would be much appreciated!

Update

Client Console Output - Initial page load

Logging: rerunJs.js in middleware directory
Server based middleware
Print context.app.head.script:
[
  { src: '/scripts/jquery.min.js', body: true, defer: true },
  { src: '/scripts/jquery.dropotron.min.js', body: true, defer: true },
  { src: '/scripts/browser.min.js', body: true, defer: true },
  { src: '/scripts/breakpoints.min.js', body: true, defer: true },
  { src: '/scripts/util.js', body: true, defer: true },
  { src: '/scripts/main.js', body: true, defer: true },
  { src: '/scripts/owa.js', body: true }
]
Logging: index.vue in Nuxt pages directory
Logging: jquery.dropotron.min.js in static/scripts directory
Logging: main.js in static/scripts directory

Client Console Output - Navigating to Route '/' with NuxtLink

Logging: rerunJs.js in middleware directory
Client based middleware
Print context.app.head.script:
Array(7) [ {…}, {…}, {…}, {…}, {…}, {…}, {…} ]

Solution

  • Solution

    To re-run external JavaScript (i.e. jQuery) when navigating to another page using NuxtLink with Nuxt setted up to Universal Mode, two lifecycle hooks are to be used.

    First, middleware should remove the scripts from head. Be sure, that only client will remove the scripts. On initial pageload, middleware is server based and scripts run, even without triggering them.

    middleware/rerunJs.js
    
    ...
      if (process.client) {
        context.app.head.script = undefined
      }
    ...
    

    Afterwards the mounted-Hook of the desired page should append the scripts to head and end of body.

    pages/index.vue
    
    ...
      mounted () {
        (function LoadMyJs () {
          const docHeadObj = document.getElementsByTagName('head')[0]
          const jqueryScript = document.createElement('script')
          jqueryScript.outerHTML = '<scr' + 'ipt data-n-head="ssr" src="/scripts/jquery.min.js" data-body="true">' + ' </scr' + 'ipt>'
          jqueryScript.src = '/scripts/jquery.min.js'
          jqueryScript.defer = true
    
          docHeadObj.appendChild(jqueryScript)
    
          document.body.innerHTML = document.body.innerHTML + queryScript.outerHTML 
        }())
      }
    ...