solid-refresh icon indicating copy to clipboard operation
solid-refresh copied to clipboard

Root component not hot reloaded when using render

Open RsMan-Dev opened this issue 1 year ago • 17 comments

I have this setup:

globalThis.allComponents = import.meta.glob('/javascripts/components/**/*.{jsx,tsx,js,ts}', {eager: true});

function getComponentByName(name: string) { /* find component by glob **/<name>.{tsx, jsx} */ }

customRender(name:string){
  const Component = getComponentByName(name)
  
  render(() => <Component/>, element)
}

this way, when i edit any child component, hot reload works as expected, but when i make any change to the root component, i have no hot reload.

RsMan-Dev avatar Apr 02 '24 10:04 RsMan-Dev

@RsMan-Dev which one is the root component?

if it's the customRender, Solid Refresh doesn't cover it.

lxsmnsyc avatar Apr 02 '24 10:04 lxsmnsyc

i am using the builtin render, the root component is Component @lxsmnsyc

RsMan-Dev avatar Apr 02 '24 12:04 RsMan-Dev

@RsMan-Dev then it should work for the components in the your glob. unless it doesn't follow the requirements

lxsmnsyc avatar Apr 02 '24 12:04 lxsmnsyc

what are the requirement to follow to have them working? @lxsmnsyc

RsMan-Dev avatar Apr 02 '24 14:04 RsMan-Dev

can you help me @lxsmnsyc ?

Basically, glob is doing this:

globalThis.allComponents = import.meta.glob('/javascripts/components/**/*.{jsx,tsx,js,ts}', {eager: true});
// code produced by vite
import * as __glob__0_0 from './components/Home.tsx'
globalThis.allComponents = {
  './components/Home.tsx': __glob__0_0,
}

When i am rendering Home, it's simply rendering it like:

const Component = allComponents['./components/Home.tsx'].default

//native solidjs's render
render(() => <Component/>, root)

So, i'm basically using native solidjs functions, what is missing to have hot reload working on this code?

RsMan-Dev avatar Apr 03 '24 08:04 RsMan-Dev

All of the code you showed are not covered by Solid Refresh.

Show me your Home component and I can give a definite answer.

lxsmnsyc avatar Apr 03 '24 08:04 lxsmnsyc

it's hello, not home on my code:

import { createSignal } from "solid-js";

export default function Hello() {
  const [count, setCount] = createSignal(0);
  return (
    <div>
      <button onClick={() => setCount(count() + 1)}>count: {count()}</button>
    </div>
  );
}

RsMan-Dev avatar Apr 03 '24 08:04 RsMan-Dev

when this code is used inside another component, it's hot reloaded like expected.

RsMan-Dev avatar Apr 03 '24 08:04 RsMan-Dev

Then that should work. There's nothing to handle in your root file.

lxsmnsyc avatar Apr 03 '24 08:04 lxsmnsyc

another simple reproduction form me:

components/Hello.tsx

import { createSignal } from "solid-js";
import Sub from "./Sub";

export default function Hello() {
  const [count, setCount] = createSignal(0);
  return (
    <div>
      <Sub/>
      <br/>
      <button onClick={() => setCount(count() + 1)}>count: {count()}</button>
    </div>
  );
}

components/Sub.tsx

import { createSignal } from "solid-js";

export default function Sub() {
  const [count, setCount] = createSignal(0);
  return (
    <div>
      <button onClick={() => setCount(count() + 1)}>count: {count()}</button>
    </div>
  );
}

root.ts

import Hello from "./components/Hello";
render(Hello, this)

Here, only Sub is hot reloaded, not Hello, the root component.

RsMan-Dev avatar Apr 03 '24 08:04 RsMan-Dev

So what behavior does Hello show when making changes?

lxsmnsyc avatar Apr 03 '24 08:04 lxsmnsyc

nothing changind

RsMan-Dev avatar Apr 03 '24 08:04 RsMan-Dev

vite is trying to hot reload, i receive something on network, but nothing happen in frontend. idk if it's changing anything, but render is called inside a custom element, on it's "connectedCallback" function.

RsMan-Dev avatar Apr 03 '24 08:04 RsMan-Dev

that's why i'm using "this" as root element

RsMan-Dev avatar Apr 03 '24 08:04 RsMan-Dev

i succeeded to make hot reloading working using this workaround:

components/Root.tsx

interface RootProps { Component: any; props: Record<string, any>;}
export default function Root({Component, props}: RootProps) {
  return <>
    <Component {...props}/>
  </>;
}

components/Hello.tsx

//normal component

root.ts

render(() => <Root Component={component} props={props}/>, this)

here, home is hot reloaded as expected, because not the root component, waiting for your potential fix, i will work using this method.

RsMan-Dev avatar Apr 03 '24 09:04 RsMan-Dev

I don't really understand the issue.

Can you perhaps just provide a repro?

lxsmnsyc avatar Apr 03 '24 14:04 lxsmnsyc

When the component is directly rendered using render(), it becomes impossible to hot reload, but when the component is rendered by another component, it becomes hot reloadable

RsMan-Dev avatar Apr 03 '24 17:04 RsMan-Dev