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 setContext or getContext
  • Make sure that repo does not have svelte as a direct dependency but only as peerDependency (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)

Most upvoted comments

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.1 and vite@3.0.2 and 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 .mjs variant via import.meta.resolve('svelte/internal'). So Vite is inconsistent here, and the reason is because Svelte (for some reason) has a package.json at svelte/internal/package.json. Vite reads that package.json, and because it imitates Node’s resolution, doesn’t read the module exports, so it reads main instead.

So how does Node still get the .mjs version, 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.

If pjson is not null and pjson.exports is not null or undefined, then Return the result of PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions).

svelte/internal/package.json’s exports is undefined, it should continue to search for package.json up 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