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

Feature request: Add <!-- markup around components. #2845

Closed
LionsAd opened this issue Nov 24, 2020 · 5 comments
Closed

Feature request: Add <!-- markup around components. #2845

LionsAd opened this issue Nov 24, 2020 · 5 comments

Comments

@LionsAd
Copy link

LionsAd commented Nov 24, 2020

Thanks a lot for preact + htm, coming from a Drupal world it is a joy to integrate it as little widgets.

Would it be possible to add the component with it's properties (if they can be represented as a string) within the HTML as comments?

e.g.

const nav = html`<${NavBar} color=red orientation=${orientation} data="${complexObject}">${items}<//>`;

with NavBar being:

function NavBar () {
  return html`<div id="nav" class="text-${props.color}" orientation="${props.orientation}">${props.children}</div>`;
}

rendered normally to e.g.:

<div class="text-red orientation-left"><span>...</span></div>

instead rendered in debug mode to:

  <!-- <NavBar color="red" orientation="left" data="[object]"> -->
  <div class="text-red orientation-left"><span>...</span></div>
  <!-- </NavBar> -->

That makes it much simpler to see the components structure on a page.

I am not sure if this belongs to preact or htm (though I think it's preact) and am happy to do the implementation with some guidance of where to start.

@marvinhagemeister
Copy link
Member

That's in interesting topic. As far as I'm aware, neither htm or Preact support comments. If you just want to know which elements were rendered by which components I'd highly recommend checking out the Preact Devtools browser extension. With that you can inspect the full component tree and see which DOM nodes a component rendered by simply hovering components.

@LionsAd
Copy link
Author

LionsAd commented Nov 24, 2020

htm does support comments, parsed as MODE_COMMENT in build() and they are added as normal children.

@marvinhagemeister
Copy link
Member

Yeah, but that's just an internal thing that's skipped during parsing. It's not forwarded to the jsx constructor function.

Regardless of that I'm curios what your specific need is for rendering html comments. From the original post it seems like making use of our devtools extension is a much better developer experience. Happy to learn more about why you need comments.

@developit
Copy link
Member

developit commented Dec 16, 2020

IIRC only build() in HTM supports comments, MODE_COMMENT nodes are skipped in evaluate() and never make it to h().

@LionsAd You might find this interesting: it's a demo showing how to use HTM + Preact to render almost exactly what you outlined in your original question, just using an inert <script> tag to house the JSON props:

https://codesandbox.io/s/preact-htm-selective-hydration-v784b

The key is this bit, which injects that data around components:

function autoHydrate(Component, name) {
  if (typeof document !== 'undefined') {
    return Component;
  }

  // we place marker scripts before and after our component.
  // if there are multiple root elements, we hydrate them all
  return props => html`
    <script type="text/component">${name}<\/script>
    <${Component} ...${props} />
    <script type="text/hydration" dangerouslySetInnerHTML=${{
      __html: JSON.stringify({ props })
    }} />
  `;
}

Here's another variant that uses custom elements to do the same, and uses Preact's plugin API to automatically apply this to all components:

import { h, options } from 'preact';

if (typeof document === 'undefined') {
  let lock = false;
  let old = options.vnode;
  options.vnode = vnode => {
    const component = vnode.type;
    if (!lock && typeof component === 'function') {
      vnode.type = component.name || 'unnamed-component';
      lock = true;
      vnode.children = h(component, vnode.props);
      lock = false;
    }
    if (old) old(vnode);
  };
}

Now all server-rendered components look like:

<custom-component-name foo="bar" baz="bat">
    <div>whatever the component rendered here</div>
</custom-component-name>

I would say this is the kind of thing we recommend plugins for, since comments aren't free and JSON serialization is way too lossy of a scheme to apply to props in the general case. Happy to help you hack on this stuff though.

@JoviDeCroock
Copy link
Member

Closing as a won't do as we have a workaround here. Tangentially there's also a proposal to denote suspenseful components with comments #4442

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants