Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using the context API in standalone components loaded at runtime returns undefined #3615

Closed
ghost opened this issue Sep 24, 2019 · 5 comments

Comments

@ghost
Copy link

ghost commented Sep 24, 2019

Edit: I've found this issue too, which I think looks like the same problem I'm describing here: #3422

Describe the bug
I'm trying to build a system that loads external standalone components at runtime, and I want to use the getContext and setContext functions to share a store between all of the components.

I'm using webpack to build the main application which contains an App component that serves as the root of the application, and then I'm using a completely separate project to build another external standalone component (both an SSR version and a DOM versions), which I then load in at runtime using require on the Node server-side, and a <script> tag on the client-side within the main App component.

The external standalone component does load and render correctly, however within the component any calls to getContext return undefined.

I'm not familiar with the Svelte codebase, but I assume this is due to the standalone component being built as a separate project and getting its own versions of the context related variables/functions at build time, rather than sharing the same variables etc. from the parent.

I assume this is a bug, but if I'm just doing something wrong please let me know.

Logs
No logs other than getContext printing undefined in the child standalone component.

To Reproduce

  • Build a simple Svelte application (doesn't matter if it uses SSR or not)
  • Load a standalone component built from another project (using a <script> tag or something)
  • Render the component inside a component from the main application using <svelte:component this={MyStandaloneComponent} />
  • See getContext in the standalone component return undefined because it (I think) doesn't have the same context

Expected behavior
I expect to see getContext in the standalone component return data from the same context as the parent component from the main application.

Information about your Svelte project:

  • This happens in all browsers
  • This happens in all OSes
  • Svelte version is 3.12.1
  • Webpack using svelte-loader 2.13.6

Severity
I can get around this issue by passing the store I want to share as a prop to the child standalone component, but it's not ideal, especially in large projects where the same store may need to be shared amonst hundreds of standalone components.

This problem is more one of code maintenance/tech debt in my specific case, so I'd much prefer to have getContext work correctly where the standalone child component should inherit the context from the parent component in the main application.

Although in my specifc case I can easily work around the issue using props instead, I can imagine that for applications sharing much more than a simple store this could be prohibitive, so I'd say it's a fairly severe issue.

Additional context
I've tried various build options using Webpack, such as changing libraryTarget, or changing Svelte build flags, like changing customElements to true or false.

No matter the build options this problem always seems to occur.

@Conduitry
Copy link
Member

Yeah, this is because things are being built with different copies of Svelte's internal runtime. The parent-child relationship isn't correctly maintained between components that are compiled and bundled separately, and so the context is seen as undefined.

The proper way to go about this would be to use the svelte key in the child components' package.json files to point to the original .svelte source and specify 'svelte' in your mainFields webpack config (see https://github.com/sveltejs/svelte-loader). This way all of the components are compiled and bundled together, with a single copy of the internals.

It's probably be possible to make this work even when bundling against different copies of the internals (by making the internals use special global variables to store this, rather than variables local to the module), but I don't think this is a use we want to cater to. There are a number of reasons to just have one copy of the Svelte internals. (Both bundle size concerns, and several features that simply won't work otherwise.) So I would consider this more of a gap in the docs (Questions related to this have come up several times.) than a bug in the code.

@Conduitry Conduitry added the docs label Sep 24, 2019
@ghost
Copy link
Author

ghost commented Sep 24, 2019

That makes sense, and thank you for the explanation. I had a feeling this would be the issue.

Unfortunately in my use case I can't bundle all components up at the same time because I don't always know which components will exist on the site, so I will look for other ways around this if the props route becomes too unmaintainable.

In the case of the browser it's simple, because I can just attach the store to the window instead of using the context API. My only reason for trying to use the context API was because I needed a way to share a new store for each new request on the server-side for SSR.

At first I though that maybe there would be a way to explicitly pass a context to a child component, but if this is a use case you may not want to cater to then I suppose there would be no reason to allow for that to happen in the first place.

@ghost
Copy link
Author

ghost commented Oct 13, 2019

This is solved by #3671 (comment)

I'll leave this issue open since it's got the docs tag, but I just wanted to point out the comment that solved the problem for me as that's likely the best thing to document.

@stale
Copy link

stale bot commented Dec 24, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale-bot label Dec 24, 2021
@Rich-Harris
Copy link
Member

Closing — as noted, the solution here is to avoid prebundling Svelte (not just svelte/internal, which no longer exists in Svelte 5, but all svelte/* imports)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants