templ icon indicating copy to clipboard operation
templ copied to clipboard

generator: option to disable whitespace normalization

Open diamondburned opened this issue 1 year ago • 10 comments

Currently, this templ snippet:

templ x() {
	<pre>
		package main

		func main() &#123;
			println("Hello, world!")
		&#125;
	</pre>
}

generates this HTML:

<pre>package main func main() &#123; println("Hello, world!") &#125;</pre>

Note that all the proper indentation is gone, since templ turns all of the whitespaces into a single space. This makes writing code blocks in HTML impossible.

This issue also applies to <textarea> and <p> tags with style="white-space: pre*;".

Ideally, disabling or fixing whitespace normalization would be the best fix, but adding an extra --preserve-whitespace flag is fine too.

Potentially relevant comment: https://github.com/a-h/templ/issues/87#issuecomment-1548709257

diamondburned avatar May 17 '23 23:05 diamondburned

I found a workaround in the meantime:

templ x() {
	<pre> {`
		package main

		func main() &#123;
			println("Hello, world!")
		&#125;
	`} </pre>
}

diamondburned avatar May 17 '23 23:05 diamondburned

Just thinking about this some more, now that the auto formatting, and spaces between variables are dealt with.

Options as I see it from here:

  • Accept that this workaround is acceptable and document it.
  • Decide that children of the <pre> element should not have whitespace removed.
  • Something else?

What are you thoughts?

a-h avatar Sep 30 '23 16:09 a-h

For option 2 above, the solution would probably be something like how the indentation for autoformatting now works. The element type has a field on it to set the behaviour: https://github.com/a-h/templ/blob/fa536dd2a2634247a7526ccd0de6ada7f1c98287/parser/v2/types.go#L319-L325

So in this case, adding a new PreserveWhitespace field to the element, and setting it to true if the element name is pre. Then, adding something to the generator that adds a context variable and passes that down to children. The generated code would always need to include the whitespace for elements, and optionally include it in the output based on the context value.

It could potentially slow down all rendered content, due to needing to check for the flag.

a-h avatar Sep 30 '23 16:09 a-h

I have just discovered the library, great job, thanks. I have to say I was a bit surprised when I realized the output did not have the same structure as the source. I think it would be much easier to reason about it if they were the same.

What happens in the case of putting an element inside another element like pre, I do not think a workaround works with that.

For example

<pre>
  for _, item := range items {
    <a href={ templ.URL(item.Name) }>{ item.Name }</a>   { item.ModifiedAt }    { item.Size }
  }
</pre>

Also, if this library will ever handle text formats other than HTML one day, auto line collapsing and single spacing would not be acceptable.

How about making single space, new line collapsing optional?

brlbil avatar Oct 11 '23 04:10 brlbil

Thanks for everyone's thoughts on this.

One solution might be to drop built in minification as a goal, and suggest the use of something like github.com/tdewolff/Minify which provides HTTP middleware.

This may negatively affect the performance for users that require it.

However, it would simplify the job of templ since the rendering logic would be simpler.

On the other hand, maybe it's as simple as updating the rendering logic to not strip white space from pre elements. With regards to supporting changes to block/inline driven by CSS, I note that the minfication library above doesn't support that.

Supporting formats other than HTML isn't a goal for templ.

The goal is to make Go a viable language for commercial front end web development when used with tools like HTMX.

I'll digest this thread and come up with some concrete actions.

a-h avatar Oct 11 '23 07:10 a-h

This may negatively affect the performance for users that require it.

I think this is a fair tradeoff. It should be reasonable for people to assume that templ is a templating library, not some sort of framework that tries to do everything at once.

Of course, we could always just introduce a config file, though I'm personally not a huge fan of this idea.

diamondburned avatar Oct 11 '23 10:10 diamondburned

This could do with some investigation to find out if the issue still stands, and make a decision on the outcome.

joerdav avatar Jan 31 '24 09:01 joerdav

I found a workaround in the meantime:

templ x() {
	<pre> {`
		package main

		func main() &#123;
			println("Hello, world!")
		&#125;
	`} </pre>
}

This will only work with <pre> not inside <pre><code>.

For example when I am using:

<pre>
  <code>
    { `
        sudo apt update
        sudo apt install nginx
    ` }
  </code>
</pre>

it doesn't work. But if I remove the <code>, then it will work.

<pre>
    { `
        sudo apt update
        sudo apt install nginx
    ` }
</pre>

Is there any other workaround for this?

vblinden avatar Mar 05 '24 10:03 vblinden

@vblinden - what do you mean "works" vs "doesn't work"? Would be good to see the actual HTML output vs what you expected.

a-h avatar Mar 07 '24 17:03 a-h

@a-h Sorry, I was running an older version of the templ. I upgraded to the latest version and now the workaround works. Sorry again for the inconvenience.

vblinden avatar Mar 07 '24 18:03 vblinden

I can see that this now works for both <pre> and <code>

joerdav avatar May 31 '24 12:05 joerdav