11ty / webc

Single File Web Components
MIT License
1.3k stars 36 forks source link

Adding a webc:setup block to the top of a layout breaks it without reporting any errors #172

Open CanIGetaPR opened 1 year ago

CanIGetaPR commented 1 year ago

Affects: webc 0.11.0, 11ty 2.0.1

If a setup block is added at the top of the layout in the example here, the result is the html and head tags disappear.

broken-layout.webc

<script webc:setup>
console.log("Don't tell the ferrets but I broke it!");
</script>

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>WebC Example</title>
    </head>
    <body @raw="content"></body>
</html>

setup-breaks-layout.webc

---
layout: broken-layout.webc
---

This doesn't work as expected.

Result:


        <meta charset="utf-8">
        <title>WebC Example</title>

    This doesn't work as expected.

Expected: (or a build error if webc setup is for components and not layouts)

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>WebC Example</title>
</head>
<body>This doesn't work as expected.
</body>
</html>

View live result: view-source:https://6441d17e28ed0650935d4ab9--11ty-sandbox-webc.netlify.app/setup-breaks-layout Make sure you view webpage source because browsers automatically insert missing html and head elements when viewing in inspector. View result source code: https://gitlab.com/CanIGetAnMR/11ty-sandbox/-/tree/af67dd936a29b105acbb7b598cbed3500e50b29e

CanIGetaPR commented 1 year ago

A work-around for now is using js front matter data. For example,

<script webc:setup>
function getUrl(ctx) {
return "https://example.com" + ctx.page.url;
</script>

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <link rel="canonical" :href="getUrl(this)" />
    </head>
    <body @raw="content"></body>
</html>

Can instead be expressed with js front matter data like so:

---js
{
  getUrl: function (ctx) {
    return "https://example.com" + ctx.page.url;
  }
}
---

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <link rel="canonical" :href="getUrl(this)" />
    </head>
    <body @raw="content"></body>
</html>
darthmall commented 1 year ago

I suspect this may not actually be a problem with WebC, but it is the HTML parser that’s doing this because you can’t have a <script> tag outside of the <html> element. Similar to how custom elements will get evicted and placed in the <body> if you try to put them in <head>.

I’ve been able to get this working by putting the setup script in the <head> like this:

<!doctype html>
<html lang="en">
    <head>
                <script webc:setup>
                console.log("Don't tell the ferrets but I broke it!");
                </script>
        <meta charset="utf-8">
        <title>WebC Example</title>
    </head>
    <body @raw="content"></body>
</html>

As long as the <script> is in a valid location inside the <html> element, this should work. Also, if you have a setup script in a layout that doesn’t have an <html> element because it’s part of a layout chain, there are no issues either.

CanIGetaPR commented 1 year ago

Thanks for your discovery @darthmall .

I just moved it around a couple more places to test it, and found it actually only vanishes if it's the first thing in the file.

It works if it's below the js front matter data, or just below the closing html tag.

Additionally there's a strange behaviour with elements, if I have a style block anywhere below the element with the @raw="content" attribute, the bundler does not see this css.

CanIGetaPR commented 1 year ago

Oh I see. What I discovered is actually a separate issue. So if the webc setup with a console log is the first thing in the layout, that console log never gets executed. If it's not at the very top, anywhere else, the console log executes.

Last but not least as per your discovery if the webc setup is not within the html element, it does something strange and makes most of the markup disappear.