0

The Problem:

When I reload a page with an embedded Svelte app, the app loads fine. If I follow links to other parts of the Rails app but then come back to the page that has my app in it, the app is there for a split second and then disappears. If I'm on the page with the app and I make changes to the Svelte app, the webpack-dev-server does live module loading and reloads the application just fine.

As you'll see in the code below I have to console.log calls. One just before I add the event listener and then one inside the listener for when the application should get loaded and inserted into the html. When I do a page reload both events fire but then I come back to the page only the ADDING EVENT... log shows up (and twice).

I think this has something to do with turbo-links also being used in this Rails application because I don't this the DOMContentLoaded event gets re-fired. I need the correct event listener or some way to have the application reload when I come back to the page that has it. Here are the relevant files:

app/javascript/packs/my_app.js:

import App from './my_app/App.svelte';


console.log('ADDING EVENT...');
document.addEventListener('DOMContentLoaded', () => {
  const node = document.getElementById('my_app')
  const name = node.getAttribute('name')
  const app = new App({
    target: node,
    props: {
      name: name
    }
  });
  console.log('CONTENT LOADING...')
  
  window.app = app
})

app/views/.../edit.html.slim:

= javascript_pack_tag 'my_app', 'data-turbo-track': 'reload'
h4 Edit Record
= content_tag :div, id: "my_app", name: 'Svelte' do; end

Something interesting:

This is kind of a janky solution. It does what I need HOWEVER, it takes a moment to reload the application so you can see the previous version of it for a split second and then a new version of the app is loaded. I can test this by sending Math.random() as a prop to my application:

document.addEventListener('turbolinks:load', () => {
  const node = document.getElementById('my_app')
  
  if(node) {
    // Not a great solution but not sure how else to
    // make this more persistent
    const appLoaded = node.getAttribute('app-loaded')
  
    if(node && !(appLoaded === 'true')) {
      node.setAttribute('app-loaded', true)

      const app = new App({
        target: node,
        props: {
          name: Math.random(),
        }
      });
    
      window.app = app
    }
  }
})
aarona
  • 35,986
  • 41
  • 138
  • 186

0 Answers0