11ty / webc

Single File Web Components
MIT License
1.33k stars 38 forks source link

Should webc:nokeep be required on templates that use a single render-function #135

Closed darthmall closed 1 year ago

darthmall commented 1 year ago

I don’t know if this should be considered a bug or not. It caught me by surprise, but I can understand why it happens, so maybe it’s just an education problem…

Using a single render function in a template to generate your HTML—instead of just a plain HTML template—requires the use of webc:nokeep to remove the custom element from the output.

Example

test-html-component.webc

<p>hello</p>

test-render-fn.webc

<script webc:type="js">
  "<p>hello</p>";
</script>

index.webc

<test-html-component></test-html-component>
<test-render-fn></test-render-fn>

Output

<p>hello</p>
<test-render-fn><p>hello</p></test-render-fn>

Expected (?) Output

<p>hello</p>
<p>hello</p>

Part of me thinks that since the render function is just generating HTML, it should be treated like an HTML-only template and the custom element should be automatically removed (this was my assumption at the outset). Especially since some logic requires a render function—e.g. loops and if-else blocks—so conceivably, a person would have to use a render function for an HTML-only component.

On the other hand, you could argue that the presence of a <script> tag in the template means it is not an HTML-only component, and if you want to automatically remove the custom element, you should just add webc:root=override to the <script>.

zachleat commented 1 year ago

you know what, I think this is a bug. We should ignore host component names outside of <body> by default.

darthmall commented 1 year ago

One thought that occurs to me is what should happen in the case where the render function returns HTML and CSS/JS?

test-render-fn.webc

<script webc:type="js">
  `<p>hello</p>
  <style>
    p { color: tomato }
  </style>`;
</script>

I would expect that in this case the custom element remains in the output. But this also seems like it’s making evaluation of a template like this very difficult for WebC (and also perhaps for developers to understand).

zachleat commented 1 year ago

Just for extra clarity I don’t think it’s valid in any scenarios to output custom element names outside of a <body>. You can output HTML and render HTML fine, but if it isn’t a standard HTML tag name it shouldn’t exist in <head>!

So style should work but my-custom-style would not!

darthmall commented 1 year ago

So let me make sure I understand: when using a WebC template in the head by doing something like this:

<head>
  <meta webc:is="og-meta" />
</head>

Under no circumstances would you permit <og-meta></og-meta> to be written in the output because it’s in the <head> of the document?

I think that’s handy, but the example I gave above is actually happening in the <body>. Originally when I tooted at the Eleventy account, I thought this was a bug relating to templates in <head>, but I discovered it’s reproduce-able in the <body> as well.

Are you proposing that the behavior of <test-render-fn></test-render-fn> in my example above would remain unchanged, but if I used a render function for a component that was writing out <meta> tags in the head, I would be able to omit webc:nokeep because it’s in the <head>?

That seems pretty reasonable to me. Ensuring that WebC doesn’t knowingly generate invalid HTML seems fine, I just want to be sure I understand what you’re saying. 😅

zachleat commented 1 year ago

Under no circumstances would you permit to be written in the output because it’s in the of the document?

Yes.

Are you proposing that the behavior of in my example above would remain unchanged, but if I used a render function for a component that was writing out tags in the head, I would be able to omit webc:nokeep because it’s in the ?

Independent of the other caveat mentioned above I agree with your expected output for <test-render-fn>—it should ignore the parent tag. Looks like there is a bug with the code that determines whether or not to ignore a parent tag. <script webc:type="js"> should be exempted from that as it has an implied webc:is="template" by default.

zachleat commented 1 year ago

Filed that ancillary issue here: https://github.com/11ty/webc/issues/137

zachleat commented 1 year ago

Shipping with 0.10.0