enyo
enyo

Reputation: 16696

I get "Function called outside component initialization" when using an npm library

I have written and published a svelte library that makes the form validation library vest easy to use with svelte. I have thoroughly tested it, and it works great, also with a local path dependency. But as soon as I import the library from npm I get this error:

Function called outside component initialization

I'm pretty sure the function in question is setContext(). The thing is... I'm sure it's not called outside component initialization, and if I just copy the source of the .ts file into my project it works again.

I assume that somehow they have access to different svelte versions, and that's what's causing the mixup. But I don't see how it's possible, because I don't have svelte as a dependency, only as a peer dependency (I also tried removing it from peerDependencies but that didn't change anything).

Here is the repo: https://github.com/enyo/use-vest

Here is repo that can replicate the issue: https://github.com/enyo/use-vest-repro

Upvotes: 3

Views: 5263

Answers (2)

Odilf
Odilf

Reputation: 1846

UPDATE: All of this is wrong


The problem is that you can't do a setContext() outside of a Svelte component, you need to call it explicitly in the <script> tag. The reason it works when you copy and paste it into the component is that the Svelte compiler can associate the component with the given context.

In short, you can't use setContext() outside a .svelte file.

Hence, a way to solve this problem is to export an actual .svelte file (e.g. a <VestForm> component). However, there might be another way of going about it better suited to your specific use case, but I'm not sure since I'm not familiar with Vest.

I think the version of Svelte has nothing to do with your issue.

Hope this helps.

Upvotes: 0

Bob Fanger
Bob Fanger

Reputation: 29897

After some debugging I found that error: Function called outside component initialization only happens on the dev server, on the client and production build the library works as expected.

This is because on the server the setContext is imported from different runtimes.

On the server the setContext inside the Form.svelte is included from "svelte/index.js" but in "use-vest/dist/index.js" the setContext is included from "svelte/index.mjs"

.js vs .mjs

For H.B. the call stacks:

Trace: js
    at Object.<anonymous> (/Volumes/Sites/use-vest-repro/node_modules/svelte/internal/index.js:987:9)
    at Module._compile (node:internal/modules/cjs/loader:1105:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Module._load (node:internal/modules/cjs/loader:827:12)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:170:29)
    at ModuleJob.run (node:internal/modules/esm/module_job:198:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:409:24)
    at async importModuleDynamicallyWrapper (node:internal/vm/module:435:15)
Trace: mjs
    at file:///Volumes/Sites/use-vest-repro/node_modules/svelte/internal/index.mjs:984:9
    at ModuleJob.run (node:internal/modules/esm/module_job:198:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:409:24)
    at async importModuleDynamicallyWrapper (node:internal/vm/module:435:15)
    at async nodeImport (/Volumes/Sites/use-vest-repro/node_modules/vite/dist/node/chunks/dep-59dc6e00.js:59403:21)
    at async eval (/src/lib/components/Form.svelte:7:31)
    at async instantiateModule (/Volumes/Sites/use-vest-repro/node_modules/vite/dist/node/chunks/dep-59dc6e00.js:59333:9)

I'm not sure how to solve this...
Let me know if you find a solution.

Upvotes: 1

Related Questions