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

Universal Renderer's cleanup method doesn't remove existing node #2202

Open
nyanrus opened this issue Jun 30, 2024 · 5 comments
Open

Universal Renderer's cleanup method doesn't remove existing node #2202

nyanrus opened this issue Jun 30, 2024 · 5 comments
Labels
enhancement New feature or request

Comments

@nyanrus
Copy link

nyanrus commented Jun 30, 2024

Describe the bug

Universal Renderer's cleanup method (the return value of render function) doesn't remove the existing node, which is inconvenient for using HMR.

Your Example Website or App

https://stackblitz.com/edit/solidjs-templates-ycgqgq?file=src%2Findex.tsx

Steps to Reproduce the Bug or Issue

  1. See the rendered result.

Expected behavior

I ran the cleanup method and I expected the node to be removed.

Screenshots or Videos

image

Platform

  • OS: Windows 11
  • Browser: Firefox
  • Version: 115

Additional context

I am using solid-js for Firefox XUL, non-standard HTML, for developing a custom browser.
While I making HMR using Vite, I encountered the problem.
Thank you for the good project!

@this-spring
Copy link

Universal render method is different client render method.

client render method will clean nodes element.textContent = "";

I am not sure whether universal render need add this logic.

image

@nyanrus
Copy link
Author

nyanrus commented Jul 1, 2024

Thank you for the reply.
I'll implement with overriding the render method.
Thanks!
By the way, I think it will be good if there are some docs or codes that guides/allows to implement custom cleanup method.

@this-spring
Copy link

emmm, I think cleanup is inner logic. It should not implement custom by users. Override render method is good way.

@ryansolid
Copy link
Member

Yeah I added the cleanup to web after the fact possibly.. There is no universal API currently to accomplish this I think? I'm open to suggestions on what sort of API you'd want to see to support this.

@nyanrus
Copy link
Author

nyanrus commented Aug 9, 2024

Currently, I am overriding the render function for support vite's HMR.
In Firefox codebase, I have to insert element in existing node a lot, and the dispose function seems only on render.
so I made options(third param) in render with marker and hotCtx (solid-refresh doing not expected work so I am not using).

const _render = (
  code: () => JSX.Element,
  node: JSX.Element,
  options?: { marker?: Element; hotCtx?: ViteHotContext },
) => {
  let disposer: () => void = () => {};
  createRoot((dispose) => {
    const elem = insert(node, code(), options ? options.marker : undefined);
    disposer = () => {
      dispose();
      if (elem instanceof Element) {
        elem.remove();
      } else if (
        Array.isArray(elem) &&
        elem.every((e) => e instanceof Element)
      ) {
        elem.forEach((e) => e.remove());
      }
    };
    if (options?.hotCtx) {
      hotCtxMap.set(options.hotCtx, [
        ...(hotCtxMap.get(options.hotCtx) ?? []),
        disposer,
      ]);
      console.log("register disposer to hotCtx");
      options.hotCtx.dispose(() => {
        hotCtxMap.get(options.hotCtx!)?.forEach((v) => v());
        hotCtxMap.delete(options.hotCtx!);
      });
    }
  });
  return disposer;
};

https://github.com/nyanrus/noraneko/blob/b8881a58a3a49f4fbca234a8fd9b36c61729cc80/packages/solid-xul/index.ts#L118

If the marker are as default, and custom disposer as

~~~
  mergeProps,
} = createRenderer<JSX.Element>({
  /**
   * @param elem output of insert func
   * @param options render func's third param
   * may the render func's param can be in this func's param.
   */
  cleanupRender: (elem, options) => {
    if (elem instanceof Element) {
      elem.remove();
    } else if (
      Array.isArray(elem) &&
      elem.every((e) => e instanceof Element)
    ) {
      elem.forEach((e) => e.remove());
    }
  },
  createElement: (tag: string): Element => {
    if (tag.startsWith("xul:")) {
      return document.createXULElement(tag.replace("xul:", ""));
    }
    return document.createElement(tag);
  },
~~~

original from https://github.com/nyanrus/noraneko/blob/b8881a58a3a49f4fbca234a8fd9b36c61729cc80/packages/solid-xul/index.ts#L35

, then I could make less the render func's overriding as

const _render = (
  code: () => JSX.Element,
  node: JSX.Element,
  options?: { marker?: Element; hotCtx?: ViteHotContext },
) => {
  const disposer = render(code,node,options);
  if (options?.hotCtx) {
    hotCtxMap.set(options.hotCtx, [
      ...(hotCtxMap.get(options.hotCtx) ?? []),
      disposer,
    ]);
    console.log("register disposer to hotCtx");
    options.hotCtx.dispose(() => {
      hotCtxMap.get(options.hotCtx!)?.forEach((v) => v());
      hotCtxMap.delete(options.hotCtx!);
    });
  }
  return disposer;
};

and it seems comfortable.

@ryansolid ryansolid added the enhancement New feature or request label Sep 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants