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
}
}
})