jeffreyguenther / vue-turbolinks

A Vue mixin to fix Turbolinks caching
MIT License
287 stars 20 forks source link

First visit doesn't load vue app #12

Closed ribanez7 closed 7 years ago

ribanez7 commented 7 years ago

Hi,

When initializing vue apps with the $mount() method, the app doesn't load on the first visit if you use turbolinks. This way, for example:

import Vue from 'vue'                                                                                                                                                                            
import TurbolinksAdapter from 'vue-turbolinks'                                                                                                                                                   
import ListRendering from './list_rendering.vue'                                                                                                                                                 

Vue.use(TurbolinksAdapter)                                                                                                                                                                       

document.addEventListener('turbolinks:load', () => {                                                                                                                                             
    const listRenderingApp = document.querySelector('list-rendering-app')                                                                                                                        
    if (listRenderingApp != null) {                                                                                                                                                              
        const app = new Vue(ListRendering).$mount(listRenderingApp)                                                                                                                              
    }                                                                                                                                                                                            
}) 

I have prepared a repo with two simple examples, each one on a different branch: https://github.com/ribanez7/rails-vue-playground

Branch "turbolinks" uses turbolinks, and you can see how, when visiting the root page and clicking any link (each link has a different vue app), on first visit you see nothing.

Branch "no-turbolinks" doesn't make use of turbolinks, and there everything loads ok.

Could you please let me know if this is actually an issue? Thanks!

excid3 commented 7 years ago

Hey @ribanez7, thanks for the issue. I haven't ever used $mount before myself so I'm not quite sure how that works. I would assume that it works pretty much the same way but it may not.

excid3 commented 7 years ago

Alright so here's what's wrong:

You're including page-specific Javascript which is generally not what you want to do with Turbolinks. Any script tags in the body will be executed by Turbolinks, which means that you do not need the turbolinks:load listener for these scripts.

import Vue from 'vue'                                                                                                                                                                            
import TurbolinksAdapter from 'vue-turbolinks'                                                                                                                                                   
import ListRendering from './list_rendering.vue'                                                                                                                                                 

Vue.use(TurbolinksAdapter)                                                                                                                                                                       

const listRenderingApp = document.querySelector('list-rendering-app')                                                                                                                        
if (listRenderingApp != null) {                                                                                                                                                              
    const app = new Vue(ListRendering).$mount(listRenderingApp)                                                                                                                              
}                                                                                                                                                                                            

You can read up on that here: https://github.com/turbolinks/turbolinks#working-with-script-elements

Normally, you don't want to do this approach with Turbolinks because now each pageview you're reloading and executing the Javascript and stylesheets each time since they're in the body.

It's better to put them in the head so they are loaded once and then turbolinks:load event triggers it to re-execute the Javascript (as shown in the examples).

None of this is related to $mount, just the way that you setup your Javascript which is good.

So you can move all your JS to the head and run them on turbolinks:load or you can use what you've got and remove vue-turbolinks and the event listeners.

ribanez7 commented 7 years ago

Hi Chris, Right, you found the issue. Many thanks! I have been using Turbolinks extensively, but didn't realised on this while playing with vue. I will move this to the head and will load it yielding with content for. Closing the issue, therefore. Thx!

excid3 commented 7 years ago

Awesome, I'm glad it was an easy fix. 🤘