withastro / compiler

The Astro compiler. Written in Go. Distributed as WASM.
Other
502 stars 59 forks source link

🐛 BUG: Line break between component and style tag is rendered as a space #1003

Open ArmandPhilippot opened 7 months ago

ArmandPhilippot commented 7 months ago

What version of @astrojs/compiler are you using?

2.7.1

What package manager are you using?

npm, pnpm

What operating system are you using?

Linux

Describe the Bug

First of all I wasn't sure if it was a bug or the expected behavior so I went to Discord to check support questions. I found a related discussion without proper answer but Erika thought it was related to the compiler. I also found a similar closed issue #422 on this repo so I think this is a compiler bug.

The bug:

A line break (or an empty line) between the component and its styles is rendered as a space in the HTML output.

For example if I declare a link.astro component this way:

---
const {class: className, href, ...attrs} = Astro.props;
---

<a
  {...attrs}
  class:list={['link', className]}
  href={href}><slot /></a
>

<style>
  .link {
    color: red;
  }
</style>

When I use it like this:

---
import Link from "../components/link.astro";
---

<p>This is a <Link href="#">link</Link>, with a comma to see the extra space after.</p>

The component is rendered as follow:

astro-extra-space

You can see a whitespace between the link and the comma.

This is not caused by the <a /> declaration but by the empty line between <a /> and <style />. A single line break (no empty line) does the same thing.

What I expect:

I understand that a newline can't exist for the <slot /> because it is the normal HTML behavior for inline elements.

However, I think a new line or an empty line between the component wrapper and the <style /> tag should not be rendered as a space since this is related to the Astro template syntax.

The workarounds:

  1. Inverse the component and the style tag in the template:
---
const {class: className, href, ...attrs} = Astro.props;
---

<style>
  .link {
    color: red;
  }
</style>

<a
  {...attrs}
  class:list={['link', className]}
  href={href}><slot /></a
>

It works but if the other components are declared like the first example it is annoying for code consistency.

Note that the empty line between <style /> and <a /> is not rendered. Same for the empty line between the frontmatter and the <a /> tag with the first example. I put an example where the link is at the beginning of the paragraph in the Stackblitz reproduction so you can check this behavior.

  1. Like <slot /> we can put the <style /> tag on the same line:
---
const {class: className, href, ...attrs} = Astro.props;
---

<a
  {...attrs}
  class:list={['link', className]}
  href={href}><slot /></a
><style>
  .link {
    color: red;
  }
</style>

It works but this affects readability I think.

Reproduction:

The important files in the Stackblitz reproduction are:

Link to Minimal Reproducible Example

https://stackblitz.com/edit/astro-extra-space-component-styles