larslr

larslr

We are using MJML to template our emails within a Phoenix application. This has worked very well until now, when we started upgrading from Phoenix 1.6 to 1.7. Suddenly, the HEEX parser started caring a lot more about the contents of our mjml-heex, and specifically the tag.

This tag lets us define css elements analogously to the tag in regular HTML, which means that the HEEX parser will complain about the syntax. Digging a bit, I can see that the tokenizer has special handling for tags, but I can find no way of telling it to parse tags in the same way.

We’ve tried falling back to using the old ~L sigil for the section containing , but that is only a stopgap solution, as that sigil is deprecated.

Are there any other sigils that could be used? Or some other way to tell the parser not to care so much about certain segments?

Showing Posts 10 to 1

larslr

larslr OP

I’m not sure what you’re asking for, but here is a sketch of the situation I was asking about. We have a module which defines layouts for emails, e.g.:

 def basic_layout(assigns) do
    ~H"""
    <mjml>
      <mj-head>
        <mj-preview>{@preview}</mj-preview>
        <XXX.Email.Components.head />
      </mj-head>
      <mj-body ...>
        <mj-wrapper css-class="wrapper">
          <mj-section>
            <mj-column>
              {render_slot(@inner_block)}
            </mj-column>
          </mj-section>
        </mj-wrapper>
      ...
      </mj-body>
    </mjml>
    """
  end

The header component, with the previously troublesome <mj-style> tag:

  def head(assigns) do
    ~H"""
    <mj-font ... />

    <mj-attributes>
      <mj-all ... />
      <mj-button ... />
      ...
    </mj-attributes>

    <mj-style inline="inline" phx-no-curly-interpolation>
      .wrapper {
      border-radius: 14px;
      background-color: #FFF;
      border: 1px solid rgba(0,0,0,0.1);
      overflow: hidden;
      text-align: left;
      }
      .op3{
      opacity: 0.3;
      }
    </mj-style>
    """
  end

We can then use the layout in templates:

def render(assigns) do
    ~H"""
    <XXX.Email.Layouts.basic_layout preview=@preview>
      ... email body ...
    </XXX.Email.Layouts.basic_layout>
    """
  end

Rendering the template, both for previews and actual email bodies:

def render_heex_mjml(module, template, assigns) do
  {:ok, html_body} =
    Phoenix.Template.render(module, template, "html", assigns)
    |> Phoenix.HTML.Safe.to_iodata()
    |> Enum.join()
    |> Mjml.to_html()

  html_body
end
alexslade

alexslade

Sorry to dig this up, but could you expand on your heex / mjml usage more?

We’re doing something similar, and initially I was putting everything inside a <script type="text/plain"> tag. But recently that has broken change tracking, and using a hidden <pre> tag works.

That <pre> tag has a hook attached which looks for updates and re-triggers a MJML render. (This seems to be perfectly performant, even on larger emails with keystroke-frequency updates on an old laptop).

I’m curious what others are doing with the larger structure of their MJML rendering?

larslr

larslr OP

Perfect, thank you!

harmon25

harmon25

That helped me this week solving the same issue - but I also bumped up against debug notation causing some issues in dev without the ability to selectively disable it - mjml parser did not really like the html comments that were injected.

I was not using the annotations much - so I just disabled them

chrismccord

chrismccord

Creator of Phoenix

<mj-style phx-no-curly-interpolation>

10
Post #6
LostKobrakai

LostKobrakai

That makes sense. HEEx needs to special case style and script tags, because it cannot parse their contents. It doesn’t know about mj-style though and therefore cannot do that there. That’s one of the downsides of a syntax aware templating language – ~L didn’t parse the syntax of your template.

I’d probably move the styles to be an assign and do <mj-style>{styles}</mj-style>.

larslr

larslr OP

That would be fine as long as EEx is supported, but I couldn’t find the appropriate sigil to use. I thought it had been removed, what are you using?

larslr

larslr OP

...

<mj-style inline="inline">
  .wrapper {
    border-radius: 14px;
    background-color: #FFF;
    border: 1px solid rgba(0,0,0,0.1);
    overflow: hidden;
    text-align: left;
  }
  .op3{
    opacity: 0.3;
  }
</mj-style>

...

This is the block that’s causing headaches. The CSS-syntax inside the tags are parsed as syntax errors when we use the ~H sigil. It works with ~L.

LostKobrakai

LostKobrakai

Can you post a specific example? I’m building mjml with heex in a project of mine.

jswanner

jswanner

I too use MJML in a phoenix app, but I parse the files with EEx instead of HEEX. Are you willing to go that route?

— All posts loaded —

Where Next? Top

Trending in Questions Top

water
I’m aware of 2 such projects, are there others? git: GitHub - team-alembic/realworld: A fullstack Phoenix LiveView application with back...
New
katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
peck
Hi everyone. My team and I have been working on a fairly modest app based around video streaming and chat, but we’ve landed a customer t...
New
bradley
I really like the adapter patterns that ecto, nebulex, waffle, etc. use and would love find something similar for a key management servic...
New
unaware8150
Hello folks! So at work, we are seeing some situations where we have to define some “fixed” strings that are used across the codebase in...
New
Alvinkariuki
How Can I Optimise Compile Time Dependencies I have been building an elixir application for about 2 years now. Many modules and files ha...
New
leoschweizer
Hi, we run different LLM models across a cluster, with each node loading a configurable subset. Model-specific queues let nodes consume ...
New

Other Trending Topics Top

budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews