vite-plugin-svelte
vite-plugin-svelte copied to clipboard
get/set/hasContext doesn't work in production code outside a component
Describe the bug
I'm trying to use the context functions in library code. They work when using both vite dev and vite preview when linking to the library directly. But when publishing to npm and including the library from there, an exception is thrown (see the logs).
Reproduction
- Create a new sveltekit todo app
- Add this code to +layout.svelte:
import { Flash } from "sveltekit-flash-message/client"
import { page } from '$app/stores'
const flash = new Flash(page)
const message = flash.message
Explanation
new Flash(page) calls hasContext in its constructor, throwing the error since hasContext cannot find current_component at that point. Code:
https://github.com/ciscoheat/sveltekit-flash-message/blob/c5198a35b724d53e0eab780e16d09c7c5c1499fb/src/lib/client.ts#L61-L66
Stackblitz reproduction
https://stackblitz.com/edit/sveltejs-kit-template-default-ask2u7?file=src%2Froutes%2F%2Blayout.svelte&terminal=dev
Logs
Error: Function called outside component initialization
at get_current_component (file:///E:/Projects/TEST/svelte-next/node_modules/.pnpm/[email protected]/node_modules/svelte/internal/index.mjs:953:15)
at hasContext (file:///E:/Projects/TEST/svelte-next/node_modules/.pnpm/[email protected]/node_modules/svelte/internal/index.mjs:995:12)
at debugflash (file:///E:/Projects/TEST/svelte-next/node_modules/.pnpm/[email protected]/node_modules/sveltekit-flash-message/client.js:52:7)
at file:///E:/Projects/TEST/svelte-next/.svelte-kit/output/server/entries/pages/_layout.svelte.js:16:3
at Object.$$render (file:///E:/Projects/TEST/svelte-next/.svelte-kit/output/server/chunks/index.js:89:18)
at file:///E:/Projects/TEST/svelte-next/.svelte-kit/output/server/index.js:36:97
at $$render (file:///E:/Projects/TEST/svelte-next/.svelte-kit/output/server/chunks/index.js:89:18)
at Object.render (file:///E:/Projects/TEST/svelte-next/.svelte-kit/output/server/chunks/index.js:97:20)
at render_response (file:///E:/Projects/TEST/svelte-next/.svelte-kit/output/server/index.js:938:29)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
System Info
System:
OS: Windows 10 10.0.19043
CPU: (16) x64 Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz
Memory: 43.25 GB / 63.93 GB
Binaries:
Node: 16.16.0 - C:\Program Files\nodejs\node.EXE
npm: 8.11.0 - C:\Program Files\nodejs\npm.CMD
Browsers:
Edge: Spartan (44.19041.1266.0), Chromium (104.0.1293.70)
Internet Explorer: 11.0.19041.1566
npmPackages:
@sveltejs/adapter-auto: next => 1.0.0-next.71
@sveltejs/kit: next => 1.0.0-next.460
svelte: ^3.49.0 => 3.49.0
vite: ^3.1.0-beta.1 => 3.1.0-beta.1
Severity
blocking all usage of SvelteKit
Additional Information
No response
This sounds like Vite does somehow create a separate Svelte runtime instance for the library. Your package is using @sveltejs/package which rules one source of errors out, which is good. I wonder if it's because your package doesn't contain Svelte components, yet it uses functions from it, so vite-plugin-svelte doesn't detect it's related to Svelte and doesn't handle it specifically or something. cc @dominikg @bluwy
If you need more information, or can point me in some direction for testing this in more depth, let me know!
I thought this was already fixed via https://github.com/sveltejs/vite-plugin-svelte/issues/360. A workaround for now is to add this in vite.config.js:
ssr: {
noExternal: ['sveltekit-flash-message']
}
Tested right away, confirmed that it works with that addition! Can this be fixed (added automatically/programatically?), so I don't have to ask library users to add this to their config, thereby increasing the friction?
It should be added automatically but it's not, which sounds like a bug. I'll transfer this over to vite-plugin-svelte to track there onwards.
When I run your example I don't see the log message you provided. Can you provide an actual reproduction of this issue?
Strange, I got it immediately using the latest sveltekit, both locally and on stackblitz. Here it is on stackblitz again: https://stackblitz.com/edit/sveltejs-kit-template-default-qwph8i?file=vite.config.js,src%2Froutes%2FHeader.svelte&terminal=dev
Having the same issue and the only way to resolve it is to add the package in noExternal. I remember external libraries being able to use contexts in July/August, not sure which version though.
Are you using the latest SvelteKit? What happens if you set vitePlugin.prebundleSvelteLibraries to false in svelte.config.js? I have a hunch this is related to prebundleSvelteLibraries being true by default now (PR: https://github.com/sveltejs/kit/pull/7388).
Is this correct?
const config = {
kit: {
adapter: adapter(),
},
vitePlugin: {
prebundleSvelteLibraries: false
}
};
It's still causing errors. Something interesting is that my package works inside a monorepo (imported via "lucia-auth": "workspace:*") when using pnpm, but breaks when using a published version using npm.
unfortunately prebundleSvelteLibraries is forced true in sveltekit right now as it is passed as an inline option. these have precedence over options specified in the config file.
https://github.com/sveltejs/kit/blob/edd815ed7bba7ab88461f9291f924c05a01d1328/packages/kit/src/exports/vite/index.js#L64 introduced here: https://github.com/sveltejs/kit/commit/e25074cfedd4147cf3091442cd7687828c6282a9#diff-beef34c36ed87d7835d0166655010910fba9949a6ef95042cb468d7d73423816R64
The only workaround for that i see is using something like pnpm patch to change the value provided inline in svelte-kit.
cc @benmccann
@pilcrowOnPaper can you provide a repository with a reproduction?.
vite-plugin-svelte 1.2.0 improved how prebundleSvelteLibraries works and i cannot reproduce the stacktrace from the original post with that. Unfortunately i'm not sure what is supposed to happen instead of that error so i would appreciate if @ciscoheat could confirm it works now.
And @pilcrowOnPaper if you still find issues with 1.2.0 and prebundleSvelteLibraries, a reproduction would be greatly appreciated. thanks (:
@dominikg I just tested it with the latest sveltekit, but still the same "Function called outside component initialization" problem. It works immediately when I add this to vite.config.js:
ssr: {
noExternal: ['sveltekit-flash-message']
}
@ciscoheat looking at https://publint.bjornlu.com/[email protected] , there is no peerDependency on svelte. This completely relies on the users project setup having deduplication for svelte and pulling it in anyways, potentially causing problems after svelte-4 release if the apis differ there. You should declare the peerDependency and vite-plugin-svelte is going to add the noExternal entry automatically.
This peerDependency declaration is not needed for ui libraries the only distribute .svelte source code, but it is needed if you make use of svelte apis in the library itself.
If that still doesn't help, please create an updated reproduction with step-by-step instructions on how to produce the error message (preferably from scratch with the sveltekit skeleton or vite+svelte template, not the sveltekit demo app)
update, seems you're using sveltekit directly too, so that also needs to be a peerDependency https://github.com/ciscoheat/sveltekit-flash-message/blob/master/src/lib/server.ts#L2
Thank you, the peer dependency fixes solved the issue. It's quite intricate, so I appreciate your help!
@dominikg
Just updated my library and can confirm the issue has been resolved by adding svelte to peerDependencies. Thanks!