HEEX formatter adds a line break in generated html?

HEEX formatter (Phoenix.LiveView.HTMLFormatter / mix format) seems to introduce an unexpected line break in the generated html. User error? A bug? ; )

This looks super-related to Formatter adds space/newline to inline elements · Issue #2237 · phoenixframework/phoenix_live_view · GitHub, but, AFAICT, the fix got merged in LiveView 0.18.2, and I am seeing the problem in 0.18.3.

Details:

Here is my repro (happy to provide a more streamline repro gist, if useful):

I want to add a comma after some text

        <%= link to: ... do %>
          <%= @item.content %><% end %>,

and this works great. Here is the web page (loaded in Safari, on a Mac):
image

Running mix format, moves the <% end %> element (and, therefore, the comma that follows) to its own line:

        <%= link to: ... do %>
          <%= @item.content %>
        <% end %>,

which introduces a space before the comma:
image

I am not expecting a code formatter to change what the code does, only what the code looks like. Am I doing something obviously silly here, or does this look like a bug? ; )

Thank you!

PS A bit more data:

$ cat .formatter.exs
[
  line_length: 120,
  import_deps: [:ecto, :phoenix],
  plugins: [Phoenix.LiveView.HTMLFormatter],
  inputs: ["*.{heex,ex,exs}", "priv/*/seeds.exs", "{config,lib,test}/**/*.{heex,ex,exs}"],
  subdirectories: ["priv/*/migrations"]
]
$ cat mix.exs | grep phoenix
      {:phoenix, "~> 1.6"},
      {:phoenix_ecto, "~> 4.4"},
      {:phoenix_html, "~> 3.2"},
      {:phoenix_live_dashboard, "~> 0.7"},
      {:phoenix_live_reload, "~> 1.4", only: :dev},
      {:phoenix_live_view, "~> 0.18.3"},
$ elixir --version
Erlang/OTP 25 [erts-13.1.1] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace]

Elixir 1.14.1 (compiled with Erlang/OTP 25)
1 Like

I guess this has to do with how how HTML is specced. Browsers condense multiple whitespace characters (including newlines) to a single space for most scripts (Latin for example).

Can you show us the generated HTML source? Won’t be surprised when it looks like

<a href=“http://foo.com”>content</a>
,

or

<a href=“http://foo.com”>
   content
</a>
,

W3C about whitespace

However…as this is code and not HTML I guess the formatter should recognize such and this is a bug.

1 Like

In the meantime, you could do:

<%= link to: ... do %>
  <%= "#{@item.content}," %>
<% end %>
1 Like

Sure, here is what the html looks like in both cases:

$ elixir heexformat.exs
next_line: "<a href=\"/i\">\n  next line\n</a>,\n" <<<<< notice \n just before the closing </a> and ","
same_line: "<a href=\"/i\">\n  same line</a>,\n"

, where heexformat.exs is

Mix.install(
  [
    {:jason, "~> 1.4"},
    {:phoenix, "~> 1.6"},
    {:phoenix_live_view, "~> 0.18.3"}
  ],
  config: [
    phoenix: [json_library: Jason]
  ]
)

defmodule HeexFormatTest do
  use Phoenix.HTML
  import Phoenix.Component, only: [sigil_H: 2]

  def to_text(h) do
    h
    |> Phoenix.HTML.Safe.to_iodata()
    |> List.to_string()
  end

  def generate_html_next_line() do
    assigns = %{}

    ~H"""
    <%= link to: "/i", method: :get do %>
      <%= "next line" %>
    <% end %>,
    """
  end

  def generate_html_same_line() do
    assigns = %{}

    ~H"""
    <%= link to: "/i", method: :get do %>
      <%= "same line" %><% end %>,
    """
  end
end

HeexFormatTest.generate_html_next_line() |> HeexFormatTest.to_text() |> IO.inspect(label: :next_line)
HeexFormatTest.generate_html_same_line() |> HeexFormatTest.to_text() |> IO.inspect(label: :same_line)

Update: this is by design:

Thank you, José!

2 Likes