vite-plugin-svelte: NPM package using getContext/setContext doesn't work during SSR dev
Describe the bug
I have distilled the issue to this:
- Create an npm package that exposes a function that uses
setContextorgetContext - Make sure that repo does not have
svelteas a direct dependency but only aspeerDependency(or not even that) - Import the package and use the function
- It crashes with: Function called outside component initialization
This only happens as npm package, using a local dependency works fine.
Reproduction
I tried reproducing in a REPL but it works fine, that’s why I assume it’s a Svelte Kit issue.
Here is the minimal reproduction repo: https://github.com/enyo/context-issue
See the issue immediately:
git clone https://github.com/enyo/context-issue.git
cd context-issue/svelte-kit-app
npm install
npm run dev
The repo contains the package, where the dist/index.js has this content:
import { setContext } from 'svelte';
const testSetContext = () => setContext('test', 'value');
export { testSetContext };
//# sourceMappingURL=index.js.map
and a svelte kit app that uses it.
Logs
No response
System Info
System:
OS: macOS 12.3.1
CPU: (10) arm64 Apple M1 Pro
Memory: 293.67 MB / 32.00 GB
Shell: 5.8 - /bin/zsh
Binaries:
Node: 17.9.0 - ~/.nvm/versions/node/v17.9.0/bin/node
Yarn: 1.22.18 - ~/.nvm/versions/node/v17.9.0/bin/yarn
npm: 8.5.5 - ~/.nvm/versions/node/v17.9.0/bin/npm
Browsers:
Chrome: 102.0.5005.61
Firefox: 100.0.2
Safari: 15.4
Safari Technology Preview: 15.4
npmPackages:
@sveltejs/adapter-auto: next => 1.0.0-next.50
@sveltejs/kit: next => 1.0.0-next.347
svelte: ^3.44.0 => 3.48.0
Severity
blocking all usage of SvelteKit
Additional Information
No response
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 18 (8 by maintainers)
I have an alternate confirmation of what @dominikg suggested above is working. I distribute a Svelte component library by NPM and while I’m still getting up to speed on Vite a consumer of my lib tried out Vite w/ slightly older versions. The same getContext / setContext issue described above popped up. In testing I upgraded their repo to
@sveltejs/vite-plugin-svelte@1.0.1andvite@3.0.2and it is fixed. Cheers!I’m been checking this bug on and off, and it seems like this is a bug that we’ve missed in our test, even though we test the context api too, but we’re not installing it locally as an npm package which hides the error.
From what I can see, in Vite SSR, your source code that imports
setContext(including when you import the package via relative path), Vite resolves the import path to/absolute /path/to/node_modules/svelte/internal/index.js.When letting Node use it’s resolve algorithm, it resolves to
/absolute /path/to/node_modules/svelte/internal/index.mjs. Notice the file extension difference, it’s the reason why the error appeared as they are two separate modules being loaded.I can re-confirm that Node uses the
.mjsvariant viaimport.meta.resolve('svelte/internal'). So Vite is inconsistent here, and the reason is because Svelte (for some reason) has apackage.jsonatsvelte/internal/package.json. Vite reads thatpackage.json, and because it imitates Node’s resolution, doesn’t read themoduleexports, so it readsmaininstead.So how does Node still get the
.mjsversion, that because Vite’s “get nearest package.json” logic isn’t compliant with Node’s. See https://nodejs.org/api/esm.html#resolver-algorithm-specification.svelte/internal/package.json’sexportsis undefined, it should continue to search forpackage.jsonup the parent directory.So I think this is a Vite issue, and not something vite-plugin-svelte can fix at the moment. Other than the workaorund of
ssr.noExternal, which should be fine to apply. I’ll hold off closing this until I get a Vite issue/pr up.One thing that still confuses me a bit is that this seems to be causing an error only with packages from npm, a local workspace package with a very similar setup is working just fine: https://github.com/sveltejs/vite-plugin-svelte/blob/main/packages/e2e-tests/kit-node/src/routes/index.svelte#L26
cc @bluwy
In the Vite-only repro, the error is because it is actually being called outside component init, moving it inside App.svelte doesn’t throw an error https://stackblitz.com/edit/vitejs-vite-fhmgtz?file=src%2FApp.svelte,src%2Fmain.js&terminal=dev
As for enyo’s SK one, adding the package to ssr.noExternal works around it but that probably has other ramifications for actual packages