#How to make SolidJS tags not return HTML elements for a custom renderer?

11 messages · Page 1 of 1 (latest)

scenic chasm
#

I have created a custom SolidJS renderer that returns JSON but the JSX tags that are being called always return HTML elements.


export const renderer = createRenderer<ElementComponent>({
  createElement(type) {
    console.log('createElement');
    return { type: type as ElementComponent['type'], children: [] };
  },

  createTextNode(children: string) {
    console.log('createTextNode');
    return { type: 'text', children };
  },

  replaceText(textNode: ElementText, value: string) {
    console.log('replaceText');

    textNode.children = value;
  },

  isTextNode(node) {
    console.log('isTextNode');
    return node.type === 'text';
  },

  setProperty<T>(
    node: ElementComponent,
    name: keyof ElementComponent,
    value: T,
  ) {
    console.log('setProp', node, value);

    // node[name] = value;
  },

  insertNode(parent, node): void {
    if (parent.type !== 'text') {
      parent.children?.push(node);
    }
    console.log('insertNode', node);
  },

  removeNode(parent, node): void {
    if (parent.type !== 'text') {
      const index = parent.children.indexOf(node);
      parent.children?.splice(index, 1);
    }
  },

  getParentNode(node: unknown): unknown {
    throw new Error('Function not implemented.');
  },

  getFirstChild(node): unknown {
    throw new Error('Function not implemented.');
  },

  getNextSibling(node: unknown): unknown {
    throw new Error('Function not implemented.');
  },
});

const view: ElementView = { type: 'view', children: [] };

const MyComponent = () => {
  return <myview><mytext>Hello world</mytext></myview>
}

renderer.render(MyComponent, view);
console.log(view);

When I console log the view, the myview and mytext are returned as HTML elements instead of JSON objects. How can I make it so that these elements are returned as plain JSON objects, not HTML elements.

scenic chasm
#

My suspicion is that it has something to do with the way JSX is transformed since the root element's children is filled propertly and createElement of the renderer is not called.

vestal thistle
#

Are you using the universal mode for compilation?

scenic chasm
#

I am using Vite directly with solid plugin

#

How do I pass the universal renderer to vite. I see that it has renderers option and generate option but I want to have both the default renderer and the custom renderer.

scenic chasm
#

I could not get this working. I tried the following solid Vite:

plugins: [solid({
  solid: {
    moduleName: '@myapp/renderer',
    generate: 'universal'
  }
})]

However, doing so modifies all solid inclusions to use @myapp/renderer and if I am using a solid based library (e.g @thisbeyond/solid-dnd), I cannot use the library because it fails in the browser. Is there a way to define that only specific components should use @myapp/renderer? I want to use solid DOM but with custom renderer.

worthy remnant
#

i would also maybe consider writing your renderer to extend solid/web's interface, maybe? eg. if the input tag is the name of an existing dom object, forward to html, otherwise forward to your custom logic

crystal abyss
#
  • it's undocumented (and typescript will yell at you), but

const Obj = () => ({ key: 'value' })

const Parent = (props) => {
  console.log('children', props.children) // {key: 'value'}
  return <></>
}

render(() => <Parent><Obj/></Parent>, ...)

is valid solid.

scenic chasm
scenic chasm
#

After playing a lot with it, I finally got it working with universal renderer by create separate solid plugins depending on directory and everything works as I expect it. The only issue that I have right now is about Typescript. How can I make typescript work with universal renderer and default renderer