Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Page script is only executed once #2455

Closed
kevinrenskers opened this issue Sep 18, 2021 · 17 comments
Closed

Page script is only executed once #2455

kevinrenskers opened this issue Sep 18, 2021 · 17 comments

Comments

@kevinrenskers
Copy link

kevinrenskers commented Sep 18, 2021

Describe the bug

When switching between different dynamic pages, it seems that their script is only ever executed twice.

Reproduction

I think the problem is kind of hard to explain, but I have a reproduction available: https://github.com/kevinrenskers/svelte-script-problem-repro. If you run this and open the console, then when switching between the different links you can see the content changing, but the console.log is only executed twice: once on the initial page load, and once on a route change, and then no more.

  1. Open http://localhost:3000/1, you will see "HELLO from 1" in the console
  2. Navigate to http://localhost:3000/2 using the links in the top, you will see "HELLO from 2" in the console
  3. Navigate to http://localhost:3000/3 using the links in the top, nothing is printed to the console

Of course this is a really simple example and you will say to use something like $: console.log("HELLO"), and yes, in that case it's run every time. But in my real world app I am fetching data in the load method and then in the script itself I want to store it in a svelte store:

<script context="module">
  export async function load({ page, fetch, session, context }) {
    // Fetch data and return as prop `fetchedLocations`
  }
</script>

<script>
  import { browser } from "$app/env";
  export let fetchedLocations;
  if (browser && fetchedLocations) {
    // Do something with the fetched locations, for example append to svelte store
  }
</script>

And that works fine.. for the first two pages that I open. Then on the third page, the code in <script> is not executed at all. I don't understand why the script code only runs on the first 2 page loads?

Logs

No response

System Info

System:
    OS: macOS 12.0
    CPU: (12) x64 Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
    Memory: 1.43 GB / 32.00 GB
    Shell: 3.3.1 - /usr/local/bin/fish
  Binaries:
    Node: 16.9.1 - /usr/local/bin/node
    Yarn: 1.22.10 - /usr/local/bin/yarn
    npm: 7.21.1 - /usr/local/bin/npm
  Browsers:
    Safari: 15.0
  npmPackages:
    @sveltejs/kit: next => 1.0.0-next.169 
    svelte: ^3.42.6 => 3.42.6

Severity

With my current knowledge: blocking all usage of SvelteKit. But maybe there's a workaround or I am doing it wrong?

Additional Information

No response

@benmccann benmccann changed the title Page script is only executed twice Page script is only executed once Sep 19, 2021
@benmccann benmccann changed the title Page script is only executed once Page script is only executed twice Sep 19, 2021
@benmccann
Copy link
Member

Hmm. I mostly see the message printed only once. I have seen it printed twice a few times as I experimented with various things, but can't reproduce

The reason it does not execute everytime with the demo repo is:

const changed_since_last_render =

@kevinrenskers
Copy link
Author

If you start from the homepage then yes, you'll only see one log. But if you start from /1 (just reload that page) then you'll see two logs.

@benmccann
Copy link
Member

Even then I'm just seeing one log. I wonder if there's some kind of race condition here.

@benmccann benmccann added this to the 1.0 milestone Sep 19, 2021
@benmccann benmccann added the bug Something isn't working label Sep 19, 2021
@kevinrenskers
Copy link
Author

Strange, but either way, I'd expect the code in the script block to run on every page view, or am I wrong in expecting that?

@Conduitry
Copy link
Member

If you're switching between two pages that are rendered by the same page component, no, that doesn't re-create the component - it just runs load again (if present) and updates the props and the $page store.

@kevinrenskers
Copy link
Author

Yeah it does indeed run the load function every time, but then when I want to do something with the props that are returned by the load function, that doesn't happen after the second page load.

If that's how it's supposed to work, then I think that's quite confusing. How would I work around it?

@Conduitry
Copy link
Member

You can use $: reactive blocks to subscribe to props or to the $page store. There were previous discussions about this for Sapper (which also behaved this way) which I can't seem to find now.

@Conduitry
Copy link
Member

I couldn't find it because it got transferred to the SvelteKit repo. There's a lot of discussion about this in #552.

@Conduitry
Copy link
Member

@benmccann Do you still think there's a bug here? I'm looking at this issue more closely, and it just looks like another instance of the (apparently controversial and poorly-documented) decision to not force re-creation of page components when switching to another URL that's handled by the same route, and that this should be closed in favor of #552.

@kevinrenskers
Copy link
Author

It seems that this is indeed a duplicate of #552. I would like to add my vote to the "this is extremely confusing, poorly documented, and very annoying to work with" crowd. I now have to add a bunch of extra code and logic all over my SK app because I don't know how a page route will be made; it it's from within the same parent layout or not, and it behaves vastly different for those two situations.

@kevinrenskers
Copy link
Author

So my breaking example:

<script context="module">
  export async function load({ page, fetch, session, context }) {
    // Fetch data and return as prop `fetchedLocations`
  }
</script>

<script>
  import { browser } from "$app/env";
  export let fetchedLocations;
  if (browser && fetchedLocations) {
    // Do something with the fetched locations, for example append to svelte store
  }
</script>

Can indeed be fixed like this:

<script context="module">
  export async function load({ page, fetch, session, context }) {
    // Fetch data and return as prop `fetchedLocations`
  }
</script>

<script>
  import { browser } from "$app/env";
  export let fetchedLocations;
  function store(fetchedLocations) {
    if (browser && fetchedLocations) {
      // Do something with the fetched locations, for example append to svelte store
    }
  }
  $: store(fetchedLocations);
</script>

But it feels wrong that I have to know the inner working of Svelte's reusing / remounting logic to work around it 😓 Anyway, I guess this ticket can be closed because we have #552.

@benmccann
Copy link
Member

@benmccann Do you still think there's a bug here

Even if we accept the current behavior as working as intended, I do think there's another bug here. The code shouldn't sometimes be run once and sometimes run twice. I think there might be a race condition here, which is why I left this open

@rmunn
Copy link
Contributor

rmunn commented Sep 20, 2021

Even if we accept the current behavior as working as intended, I do think there's another bug here. The code shouldn't sometimes be run once and sometimes run twice. I think there might be a race condition here, which is why I left this open

I wonder if it's running twice because of SSR. The issue description mentions navigating to http://localhost:3000/1 first, which would cause an SSR render. Then going to http://localhost:3000/2 would cause client-side navigation, and it's possible that that's causing something to run for the first time client-side that previously ran during SSR. I wonder if #1214 might be related.

@kevinrenskers - If you add ssr: false to your svelte.config.js, do you still see the page script executing twice? Or does that cause it to only execute once?

@kevinrenskers
Copy link
Author

@kevinrenskers - If you add ssr: false to your svelte.config.js, do you still see the page script executing twice? Or does that cause it to only execute once?

With SSR disabled I only see one log instead of two.

@benmccann benmccann changed the title Page script is only executed twice Page script is only executed once Sep 22, 2021
@benmccann benmccann removed this from the 1.0 milestone Sep 22, 2021
@benmccann benmccann removed the bug Something isn't working label Sep 22, 2021
@benmccann
Copy link
Member

I was seeing two client logs, so what I was seeing wasn't related to SSR. But now I'm wondering if maybe one of the logs was from me updating the code and triggering HMR because I can't reproduce it

Since I can't reproduce the running twice behavior I'll close this as a duplicate of #552

@kevinrenskers
Copy link
Author

I'm very surprised that you can't reproduce it. I'll create a video showing the issue because yes it's two client side logs.

@kevinrenskers
Copy link
Author

Haha well.. turns out I can't reproduce it anymore either. Strange, I swear I was able to trigger it reliably but no idea what changed. Oh well, #552 is a fine replacement anyways :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants