Svelte error when instantiating a component that wasn't bundled in the same module
as discussed in the lounge, you can find the load point here: https://github.com/FaeyUmbrea/obs-utils/blob/main/src/svelte/OverlayRenderer.svelte
Ignore the fact that window.obsutils.singleInstanceOverlays is a Set and doesn't work with #each, that is fixed in my local copy of the file.
The issue is that what ever Classes are in the singleInstanceOverlays Set implode in the init() function call.
GitHub
obs-utils/OverlayRenderer.svelte at main · FaeyUmbrea/obs-utils
For all your streaming needs! Contribute to FaeyUmbrea/obs-utils development by creating an account on GitHub.
8 Replies
Okay after some more investigation I have figured out what exactly is going on
In the code generated by svelte, the init method relies on a module scope variable while creating the component tree.
So it goes:
The problem with instantiating a svelte component from an external javascript file is, that it will have its own generated code shipped with it, and browser module isolation forces module scope variables to be module specific, even if the code was identical
So the flow goes into that other svelte runtime code module, calls THAT init function, current component is unset, there is no target to instantiate the external module with either, because it's called as a child component, and boom, crash
So
window.obsutils.singleInstanceOverlays
is something you have put in the global scope from the source module. I see that here: https://github.com/FaeyUmbrea/obs-utils/blob/main/src/utils/api.ts
In general it is recommended to use the game.modules.get('mod').api
approach to share data / public API between modules instead of "polluting" the global scope.
Yeah... I think the approach of creating separate complete bundles / Svelte runtimes is not going to play nice in this case. Something like the experimental / library hosted version of TRL / Svelte where there is one shared global Svelte runtime would solve this problem without any changes to your code. Alas that isn't available yet; it's implemented, but waiting on a good way to deploy it...
-----
Perhaps you can just create a library NPM module of your Svelte components you'd like to share across Foundry modules and import that in both modules. It would be duplicating the components in the module bundles, but you can at least create one shared component library.
In general it is not clear what you hope to achieve by having two dependent modules sharing Svelte components vs a single module.Well, the idea is to allow other modules to register components to obs-utils specifically
I feel like you'd run into this problem with the library version of TRL too, though
Because the code I'm shipping here is created by the svelte compiler
Also I'm doing it like this, because one module is not a strict dependency of the other module. And it would seem wierd to have the "library" module have the component data.
Okay, I have managed to find a workaround for this issue.
It seems like using precompiled svelte components directly is out of scope for the library at the moment
What you can do however, is create a component, bind an element to a variable and pass that variable as the target for the imported, external component
This is... less then elegant, but it does work
Here's "dirtyHack.svelte" https://github.com/FaeyUmbrea/obs-utils/blob/main/src/svelte/utilities/ExternalComponent.svelte
GitHub
obs-utils/ExternalComponent.svelte at main · FaeyUmbrea/obs-utils
For all your streaming needs! Contribute to FaeyUmbrea/obs-utils development by creating an account on GitHub.
Where there is a will there is a way! Glad you found a solution even if appears a bit of a hack. The Foundry environment w/ independently compiled Svelte apps / modules is more or less unique. It's not a common Svelte use case per se.
As an aside regarding pre-compiling Svelte components. This breaks the Vite / dev server in general, but I don't think this is what you are doing.
Ah no, I'm not
It's just that from the perspective of obs-utils, any component registered via the API is "precompiled"
I have found another, even dirtier hack in a github issue earlier. Which instead exposes the entire svelte runtime library on window
My solution looks wierd and the use if $$props does disable some of sveltes internal optimizations, but at least you are not forced to use the exact same svelte version in all projects
I might forgo $$props in favor of usecase specific instantiation
I only have three "shapes" of Svelte Components I am worried about as far as props are concerned, so I could have 3 of these importers. One for each shape
You can do that, but probably not the end of the world using $$props.
Yeah, it also shouldn't matter too much
This code is only ever executed once, unless you are actively editing the overlays
If you are in game view, which is definitely the more resource intensive view, the code will also only be loaded if you actually open the editor