withastro / prettier-plugin-astro

Prettier plugin for Astro
Other
486 stars 36 forks source link

🐛 BUG: Formatter adds significant whitespace inside expressions #308

Open jyasskin opened 1 year ago

jyasskin commented 1 year ago

Describe the Bug

In JSX inside a {var.map(e=><elem>{field1}{field2}</elem>, the formatter adds newlines between the replaced fields even if they started without whitespace between them. Depending on the field content, this can be visible in the rendered output.

Steps to Reproduce

  1. npm init astro using the default options.
  2. Run npm i --save-dev prettier-plugin-astro prettier in the resulting directory.
  3. Edit src/pages/index.astro to start with:
    
    ---
    import Card from "../components/Card.astro";
    import Layout from "../layouts/Layout.astro";

const fields = [{}];

Welcome to Astro

{ fields.map((field) => (

{"To get started, o"}{"pen the directory"} {"in your project."}

)) }
jyasskin commented 1 year ago

Another example, which adds visible whitespace between a link and a following comma:

---
const val = true;
---

{
  val ? (
    <p>
      Things before the link.
      <a id="long-id-that-makes-things-wrap" data-more="even more content"
      >content of the link</a>,
      things after the link.
    </p>
  ) : null
}
Princesseuh commented 1 year ago

Arf, this one is gonna be quite hard to fix because inside expressions, we use a JavaScript (and as such, JSX) parser and the whitespace rules are different from Astro's (which are closer to HTML's)

I'm not quite sure at the moment on how to proceed with fixing this. Sorry for the inconvenience!

peerreynders commented 1 year ago

https://github.com/withastro/astro/issues/6011#issuecomment-1409046168

Astro is not like JSX. Newlines you write in your source files are preserved in the output. If you do not want newlines [or whitespace] then remove them from your source, or you can also use JSX based component libraries like React and SolidJS which will work without the whitespace.

… whitespace which prettier will put back …

Workaround:

<div class="cta__inner flow">
  {/* prettier-ignore */}
  <h2 
    class="cta__heading headline"
    data-highlight="quaternary"
  >{cta.title}</h2>
  <p class="cta__summary measure-short">{cta.summary}</p>
</div>

otherwise it ends up as

<div class="cta__inner flow">
  <h2 
    class="cta__heading headline"
    data-highlight="quaternary"
  >
    {cta.title}
  </h2>
  <p class="cta__summary measure-short">{cta.summary}</p>
</div>

which leads to undesirable results with something like

.headline::after {
  content: ".";
}

Update:

At times {\* prettier-ignore *\} itself gets formatted to irrelevancy at which point <!-- prettier-ignore --> has to be used (unfortunately).

disrae commented 10 months ago

Eeek, the ignore statements didn't work for me, are there any tips for interpolating strings, I'm inserting a link in an injected string

                 <>
                    {answer[0]}
                    <a class="underline" href={link}>
                      {answer[1]}
                    </a>
                    {answer[2]}
                 </>

For now I will just not use underline...

g-plane commented 9 months ago

What about giving a try to dprint with markup_fmt? It has Astro support and that plugin doesn't encounter this problem.

albertzarifa commented 6 months ago

Still having the same issue with Astro 4.8.2.

When using {\* prettier-ignore *\} and formatting the file after saving I keep getting React Fragments (empty tags) appended around the node that should be ignored by the ignore statement.

eikowagenknecht commented 4 months ago

This syntax worked for me to ignore it. It was the only way I could figure out to not have whitespace between the date and the closing bracket. Would be nice, if we had a better way to do this, though:

<somehtml>
{
  frontmatter.updated && (
    <>
      {/* prettier-ignore */}
      <span class="ml-6">
        (updated
        <time class="font-mono" datetime={frontmatter.published.toISOString()}>
          {frontmatter.published.toISOString().slice(0, 10)}</time>)
      </span>
    </>
  )
}
<somemorehtml>
gersomvg commented 1 month ago

I will try and see if I can get anywhere with this issue and possibly open a PR at some point. Feel free to also look at it in the meantime, but please tag me if you also get close to opening a PR so we don't spend time solving the same issue.