ryansolid / dom-expressions

A Fine-Grained Runtime for Performant DOM Rendering
MIT License
850 stars 122 forks source link

Question: Possible to use third-party component libraries with Tagged Template Literals? #297

Closed lukexor closed 7 months ago

lukexor commented 7 months ago

Specifically I'd like to use @suid/material in a non-compiled environment for dynamic widget/form creation. I've cross-posted a separate ESM build related issue over on that github: https://github.com/swordev/suid/issues/270 - however, it occurred to me that it might not even be possible given the constraints outlined in https://github.com/solidjs/solid/tree/main/packages/solid/html

Is it possible to build @suid/material in such a way that it can be used in this context, or would the @suid project have to provide a dedicated build-less option?

lukexor commented 7 months ago

I've been trying to debug this for awhile and I'm confused on the different code paths. When building a solid app normally using vite, you end up with a single JS file that calls render on your main entrypoint and renders @suid/material components just fine.

However, when trying to use tagged template literals - you still use render but with an extra pass through html that results in a much longer call graph, resulting in what appears to be some circular logic causing errors with node refs.

For example, rendering just TextField to document.body with a static build of solid:

image

And when trying to use tagged template literals (having built @suid/material using the vite lib build option):

image

(it goes on for several more lines)

The error is happening in onMount with inputRef not being defined.

lukexor commented 7 months ago

Oddly, this may not relate to Tagged template literals at all.

In a minimal example, I'm trying to call render(TextField, document.body) from within a <script type="module"> block and I get a similar ref error.

image

However, if I instead render directly within material.js it works fine:

function render$1(code, element, init, options = {}) {
  let disposer;
  createRoot(dispose => {
    disposer = dispose;
    element === document ? code() : insert(element, code(), element.firstChild ? null : undefined, init);
  }, options.owner);
  return () => {
    disposer();
    element.textContent = "";
  };
}

render$1(TextField, document.body);

as far as I can tell the two render functions are identical. Is there something extra going on behind the scenes when resolving imports inside of a script module tag?

lukexor commented 7 months ago

I've put up a minimal reproducible repo here: https://github.com/lukexor/minimal_suid_render

Inside index.html you can see both versions of rendering, where one works and the other throws an error with undefined ref. Maybe there's some global state not being available across modules? As far as I can tell the render/createRoot/etc methods are all the same.

lxsmnsyc commented 7 months ago

I would say there are two versions of Solid in your enviroment

lukexor commented 7 months ago

I suspected. They are both 1.7.12 but likely two instances coming about due to two different build processes.

I'm not sure how to build @suid/material and have it use the solid-js from esm.sh. I've never quite figured out how the peerDependencies works into the js build system to dedupe libraries

Maybe declaring solid-js as external in the vite build?

lukexor commented 7 months ago

And that did it!