ciscoheat / sveltekit-flash-message

Send temporary data after redirect, usually from endpoints. Works with both SSR and client.
https://www.npmjs.com/package/sveltekit-flash-message
MIT License
246 stars 5 forks source link

Error: getFlash options can only be set at the first call to getFlash. #30

Closed abishekdevendran closed 7 months ago

abishekdevendran commented 7 months ago

I'm using the getFlash component in clientside(root +layout.svelte) as such:

        import { getFlash } from 'sveltekit-flash-message/client';

    const flash = getFlash(page, {
        clearOnNavigate: true
    });

    $: if ($flash) {
        switch ($flash.type) {
            case 'success':
                toast.success($flash.message);
                break;
            case 'error':
                toast.error($flash.message);
                break;
            default:
                toast.info($flash.message);
        }
    }

The code generally works for the most part, but when I make changes to seemingly unrelated +page.svelte or deeper components during dev, this error pops up. I'm not sure if this is a user error, but the error itself is frequent enough to be disruptive(cannot proceed without dev server restart).

ciscoheat commented 7 months ago

This happens when a site has multiple branching routes (like an app route and an admin route), and you browse between them in the same session, so $page refers to the same object. I'll try to come up with a fix for that soon.

ciscoheat commented 7 months ago

Should be fixed now in 2.2.2. If you still get the error, are you using getFlash options on more than one page in the route? (clearOnNavigate is default true, so you can remove that)

CrlH commented 6 months ago

I get a similar issue, still present using sveltekit-flash-message@2.3.0 using the server-side approach as documented. Note: It does look like this is only thrown when an HTTP error page (4xx, 5xx) is rendered... TBC.

As per your last comment, @ciscoheat, no other options initializer is present.

src/routes/+layout.server.ts

import { loadFlash, flashCookieOptions } from 'sveltekit-flash-message/server';

flashCookieOptions.secure = false;

export const load = loadFlash(() => {});

Stack trace

Error: getFlash options can only be set once, at a top-level component.
    at _initFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_modules
/sveltekit-flash-message/dist/client.js:38:15)
    at Module.getFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_mo
dules/sveltekit-flash-message/dist/client.js:124:12)
    at src/routes/+layout.svelte:8:17
    at Object.$$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)  
    at .svelte-kit/generated/root.svelte:45:40
    at $$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)
    at Object.render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:164:17)    
    at Module.render_response (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte@4
.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/render.js:171:29)
    at async Module.render_page (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte
@4.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/index.js:284:10)
    at async resolve (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte@4.2.8_vite
@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/respond.js:409:18)
Error: getFlash options can only be set once, at a top-level component.
    at _initFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_modules
/sveltekit-flash-message/dist/client.js:38:15)
    at Module.getFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_mo
dules/sveltekit-flash-message/dist/client.js:124:12)
    at src/routes/+layout.svelte:8:17
    at Object.$$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)  
    at .svelte-kit/generated/root.svelte:45:40
    at $$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)
    at Object.render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:164:17)    
    at Module.render_response (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte@4
.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/render.js:171:29)
    at async Module.respond_with_error (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1
_svelte@4.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/respond_with_error.js:83:10)
    at async Module.render_page (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte
@4.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/index.js:303:10)
Error: getFlash options can only be set once, at a top-level component.
    at _initFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_modules
/sveltekit-flash-message/dist/client.js:38:15)
    at Module.getFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_mo
dules/sveltekit-flash-message/dist/client.js:124:12)
    at src/routes/+layout.svelte:8:17
    at Object.$$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)  
    at .svelte-kit/generated/root.svelte:45:40
    at $$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)
    at Object.render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:164:17)    
    at Module.render_response (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte@4
.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/render.js:171:29)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Module.render_page (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte
@4.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/index.js:284:10)
Error: getFlash options can only be set once, at a top-level component.
    at _initFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_modules
/sveltekit-flash-message/dist/client.js:38:15)
    at Module.getFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_mo
dules/sveltekit-flash-message/dist/client.js:124:12)
    at src/routes/+layout.svelte:8:17
    at Object.$$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)  
    at .svelte-kit/generated/root.svelte:45:40
    at $$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)
    at Object.render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:164:17)    
    at Module.render_response (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte@4
.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/render.js:171:29)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Module.respond_with_error (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1
_svelte@4.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/respond_with_error.js:83:10)
ciscoheat commented 6 months ago

@CrlH Are you setting the getFlash options in another layout, or none at all? If you can reproduce this in a repo, that'd be much appreciated.

CrlH commented 6 months ago

Aha - my bad: while preparing a repo, I did find a getFlash that sets clearAfterMs, like this:

<script lang="ts">
  import { getFlash } from 'sveltekit-flash-message/client';
  import { page } from '$app/stores';

  const flash = getFlash(page, {
    clearAfterMs: 10000,
  });
</script>

For me it made sense to set flashCookieOptions server-side, but this appears to be the only option you can set server-side... Meaning this behavior prevents you from setting other options on the client side, right? 😕

Might be good to add a(nother) note to the docs, or to consider other options on server side too... Though I'd have to admit that things like clearAfterMs make a lot less sense server-side. 🤓

ciscoheat commented 6 months ago

The only common option for server and client are the cookies. Maybe there can be a similar cookie option for the client as on the server, to separate them from the other options.

CrlH commented 6 months ago

Thanks! I’ll change my app to have flashCookieOptions to be handled on client-site.

But it looks like one that sets flashCookieOptions server-side can’t set other options… That’s limiting, no?

ciscoheat commented 6 months ago

What other options on the server are there?

CrlH commented 6 months ago

Actually, I meant to say - if you choose to set flashCookieOptions server-side, you can't set any other option on the client-side, because options can only be set the first time you call getFlash.

At least, that was my assumption until now. I can consistently reproduce this in my project, but I can't seem to consistently reproduce the same in an example repo (yet), so there might be a more complex cause for my output above... I can't share the entire project here, but in short:

Project Setup 1) I set flashCookieOptions server-side on the root layout server file 2) I set clearAfterMs client-side on the root layout file 3) The page that produces the output is nested and has one additional +layout.server.ts where I await the parent load 4) The nested layout file does not contain any reference to getFlash

Findings so far 1) The output above has only shown in combination with a HTTP 500 error page - for which I have no dedicated files (so sveltekit default) 2) If I remove clearAfterMs from the client-side, the error doesn't occur.

I'll try to dig into it next week and update you if I come across something. Tips are welcome, should you think of something. 😉

Happy holidays! 🎅