T

TyphonJS

typhonjs-runtime

Join Server

Svelte error when instantiating a component that wasn't bundled in the same module

FFaey2/28/2023
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.
FFaey2/28/2023
Okay after some more investigation I have figured out what exactly is going on
FFaey2/28/2023
In the code generated by svelte, the init method relies on a module scope variable while creating the component tree.
So it goes:
set component as current component
make all child components
set parent as current component
FFaey2/28/2023
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
FFaey2/28/2023
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
MMLeahy2/28/2023
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.
FFaey2/28/2023
Well, the idea is to allow other modules to register components to obs-utils specifically
FFaey2/28/2023
I feel like you'd run into this problem with the library version of TRL too, though
FFaey2/28/2023
Because the code I'm shipping here is created by the svelte compiler
FFaey2/28/2023
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.
FFaey2/28/2023
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
FFaey2/28/2023
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
FFaey2/28/2023
This is... less then elegant, but it does work
MMLeahy2/28/2023
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.
FFaey2/28/2023
Ah no, I'm not
FFaey2/28/2023
It's just that from the perspective of obs-utils, any component registered via the API is "precompiled"
FFaey2/28/2023
I have found another, even dirtier hack in a github issue earlier. Which instead exposes the entire svelte runtime library on window
FFaey2/28/2023
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
FFaey2/28/2023
I might forgo $$props in favor of usecase specific instantiation
FFaey2/28/2023
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
MMLeahy2/28/2023
You can do that, but probably not the end of the world using $$props.
FFaey2/28/2023
Yeah, it also shouldn't matter too much
FFaey2/28/2023
This code is only ever executed once, unless you are actively editing the overlays
FFaey2/28/2023
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