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 1 to 10

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?

LostKobrakai

LostKobrakai

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

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.

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?

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>.

chrismccord

chrismccord

Creator of Phoenix

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

10
Post #6
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

larslr

larslr OP

Perfect, thank you!

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

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
— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
ryanwinchester
apply_graft/2 doesn’t rewrite an add_many sub-workflow’s deps on an add step. Grafted jobs cancel with “upstream job was deleted” Version...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
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
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews