Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use with other template languages (Rails, Phoenix, etc) #346

Closed
bradleybeddoes opened this issue Oct 28, 2020 · 25 comments
Closed

Use with other template languages (Rails, Phoenix, etc) #346

bradleybeddoes opened this issue Oct 28, 2020 · 25 comments

Comments

@bradleybeddoes
Copy link

maizzle -v
Framework v2.3.1
CLI v1.0.4
node -v
v14.14.0

Firstly many thanks for your efforts in building Maizzle and helping out the community.

I've scoured the docs, issues and PR looking for an answer to this, apologies if I've just stupidly overlooked something simple here.

What I am trying to do is have my email content designed in Maizzle but for transactional email push the build results into my web app as templates for its template engine to consume when deployed in production, the template languages seem to be colliding however.

An example might make this easier to visualise, what I am trying to do is make this:

...
<if condition="page.env === 'local'">
  <h1>Hi, Fred<h1>
</if>
<if condition="page.env === 'prod'">
  <raw>
    <h1>Hi, <%= @user.name %></h1>
  </raw>
</if>
<p class="m-0 mb-24">Please confirm your email address by clicking the button below:</p>
...

Output (for a prod configuration build) as:

...
<h1>Hi, <%= @user.name %></h1>
<p class="m-0 mb-24">Please confirm your email address by clicking the button below:</p>
...

instead the output is:

...
<h1>Hi, <%= @user.name="" %=""></%=></h1>
<p class="m-0 mb-24">Please confirm your email address by clicking the button below:</p>
...

As you can see the output inside h1 is "corrupted" by something internally "trying to do the right thing" when what I was hoping to get with raw was the block being entirely untouched in the output.

As you'd expect I get <h1>Hi, Fred</h1> perfectly fine when serving locally using maizzle serve

Here is my config.prod.js if helpful, I have tried a number of angles to solve this so it is getting a touch messy by now:

/*
|-------------------------------------------------------------------------------
| Production config           https://maizzle.com/docs/environments/#production
|-------------------------------------------------------------------------------
|
| This is where you define settings that optimize your emails for production.
| These will be merged on top of the base config.js, so you only need to
| specify the options that are changing.
|
*/

module.exports = {
  build: {
    templates: {
      destination: {
        path: 'build_prod',
      },
    },
  },
  // purgeCSS: {},
  // removeUnusedCSS: {},
  // replaceStrings: false,
  // removeAttributes: [],
  // safeClassNames: {},
  // sixHex: false,
  prettify: false,
}

Any help on solving this would be really appreciated.

@bradleybeddoes
Copy link
Author

bradleybeddoes commented Oct 28, 2020

edit: This actually removes quotation from a large number of attributes where it should exist, back to the drawing board.


I had a moment to dig into PostHTML a little and came up with the following:

    posthtml: {
      options: {
        quoteAllAttributes: false,
        singleTags: /^%\S*|\s*%$/,
      }
    },

which does correctly give me the output:

<h1>Hi, <%= @user.name %></h1>
<p class="m-0 mb-24">Please confirm your email address by clicking the button below:</p>

Is this a reasonable approach?

@bradleybeddoes
Copy link
Author

This seems to be another possible approach by using replaceStrings, haven't yet(?) managed to break it.

module.exports = {
  build: {
    templates: {
      destination: {
        path: "build_prod",
      },
    },
    posthtml: {
      options: {
        quoteAllAttributes: true,
        singleTags: /br|img|meta|^%\S*|\s*%$/,
      },
    },
  },
  inlineCSS: {
    enabled: true,
  },
  removeUnusedCSS: {
    enabled: true,
  },
  replaceStrings: {
    '\\s(style|class)(=""|(?=>)|(?=\\s))+': "",
    '=""': "",
  },
};

@cossssmin
Copy link
Member

Hey,

Normally it should just work with PostHTML's directives option:

posthtml: {
  options: {
    directives: [
      { name: '%=', start: '<', end: '>' }
    ],
},

For some reason it doesn't though, it still outputs something like Hi, <%= @user.name="" %=""></%=>.

I've tested thoroughly and I can't see it coming from other parts of Maizzle - I disabled all transformers and anything else that might manipulate HTML, even tested with all PostHTML plugins removed when rendering with PostHTML.

What's really weird is that if you modify this test in PostHTML to work with these <%= %> tags, it works - and I have no idea why it doesn't in Maizzle, not even when the posthtml() build process is identical to the one in that test 😐

@Scrum do you have any insight as to why it wouldn't work with directives like that?

@cossssmin
Copy link
Member

@bradleybeddoes a quick solution would be to use some made-up tags/delimiters that you then replace with replaceStrings:

<h1>Hi, !%= @user.name %!</h1>
replaceStrings: {
  '!%=': "<%=",
  '%!': "%>",
},

@cossssmin
Copy link
Member

cossssmin commented Oct 28, 2020

Looks like it's fixed in posthtml-parser@0.5.1, just tested and it worked fine, didn't even had to use the directives option. For some reason we were stuck with posthtml-parser@0.5.0 even though the latest poshtml (which we do use) requires 0.5.1 🤷‍♂️

I'll release a patch for Maizzle once this and this PR get merged and those two plugins each get a patch release.

@bradleybeddoes for now, you can remove package-lock.json and your node_modules directory, then npm install again so you get posthtml-parser@0.5.1 (check it by running npm list posthtml-parser).

@bradleybeddoes
Copy link
Author

bradleybeddoes commented Oct 29, 2020

Thank you so much for your help with this @cossssmin 🏆

I can confirm that by removing package-lock.json and node_modules to force the appropriate update of posthtml-parser all is working exactly as I had hoped it would within the <raw> block, ready for feeding the result into my web-app.

@cossssmin
Copy link
Member

Happy to help :)

Tip: you don't need the <raw> tag unless you're using {{ }} or other posthtml-expressions tags that you'd like to keep (docs).

@cossssmin
Copy link
Member

@bradleybeddoes published v2.3.2

@chasegiunta
Copy link

@cossssmin I'm actually still seeing this on a new Maizzle install. Been fighting it the past two days but I'm at wits end.
A simple example:

<title><%= @title %></title>

<title><%= @title="" %=""></%=></title>

@bradleybeddoes You're not still having issues with this?!

@bradleybeddoes
Copy link
Author

No problems here, update fixed my issue completely 🤔.

@chasegiunta
Copy link

@bradleybeddoes do you mind sharing your config.js? Can't understand why I'm still seeing this.

@cossssmin
Copy link
Member

Can confirm it's an issue with Maizzle 3.0, I think this bug has multiple causes. Could be posthtml-parser@0.6.0 since it upgraded to htmlparser2@5.0.1, but CSS inlining also has something to do with it (mainly because Juice uses a different HTML parser...)

For example, with inlining enabled, this:

<title><%= @title %></title>

... is rendered as:

<title><%= @title %></%=>
</title>

If you disable CSS inlining however, you get:

<title><%= @title="" %=""></%=></title>

If we use a <div>:

<div><%= @title %></div>

... it's rendered as expected, but only if inlining is enabled. Otherwise it renders as <div><%= @title="" %=""></div>

You could still use the replaceStrings trick I mentioned above until we come up with a fix.

@cossssmin cossssmin reopened this Nov 22, 2020
@chasegiunta
Copy link

Thanks @crosssmin, I am utilizing replaceStrings with some luck

replaceStrings: {
    '%=""></%=>': "%>",
    '=""': "",
  },

but there's other instances, even with all applicable transformers disabled, where thing are still getting mangled, like this line:

<% if ((attachments && attachments['doc_thumb.jpg']) || @email_record) && content_for?(:document_url) %>

is being output as:

<% if ((attachments && attachments['doc_thumb.jpg']) || @email_record) content_for?(:document_url) %>

(notice the missing &&)

Until a fix where everything between the delimiters is completely ignored, this will be a tough one to crack.

@Scrum
Copy link

Scrum commented Nov 23, 2020

Can confirm it's an issue with Maizzle 3.0, I think this bug has multiple causes. Could be posthtml-parser@0.6.0 since it upgraded to htmlparser2@5.0.1, but CSS inlining also has something to do with it (mainly because Juice uses a different HTML parser...)

For example, with inlining enabled, this:

Confirm, the problems are related to the update htmlparser2

@Scrum
Copy link

Scrum commented Nov 23, 2020

i checked on current posthtml version and i get expected result

const posthtml = require('posthtml') // "posthtml": "^0.14.0"

const html = `<title><%= @title %></title><div><%= @title %></div>`;
const plugins = [];
const options = {};

posthtml(plugins)
  .process(html, options)
  .then((result) =>  console.log(result.html)) // => <title><%= @title %></title><div><%= @title %></div>

@cossssmin
Copy link
Member

i checked on current posthtml version and i get expected result

@Scrum hmm, I suppose it's caused by plugins then?

$ npm list posthtml-parser
@maizzle/framework@3.0.0 F:\DEV\open-source\maizzle\framework
+-- posthtml@0.14.0
| `-- posthtml-parser@0.6.0 
+-- posthtml-expressions@1.6.2
| `-- posthtml-parser@0.5.3 
+-- posthtml-extend@0.5.2
| +-- posthtml@0.13.4
| | `-- posthtml-parser@0.5.3  deduped
| `-- posthtml-parser@0.5.3 
+-- posthtml-fetch@1.2.0
| `-- posthtml@0.13.4
|   `-- posthtml-parser@0.5.3 
+-- posthtml-markdownit@1.2.2
| +-- posthtml@0.13.4
| | `-- posthtml-parser@0.5.3  deduped
| `-- posthtml-parser@0.5.3 
+-- posthtml-mso@1.0.2
| `-- posthtml@0.13.4
|   `-- posthtml-parser@0.5.3 
+-- posthtml-postcss-merge-longhand@1.0.2
| `-- posthtml@0.13.4
|   `-- posthtml-parser@0.5.3 
+-- posthtml-safe-class-names@1.0.4
| `-- posthtml@0.13.4
|   `-- posthtml-parser@0.5.3 
`-- posthtml-url-parameters@1.0.4
  `-- posthtml@0.13.4
    `-- posthtml-parser@0.5.3

@Scrum
Copy link

Scrum commented Nov 24, 2020

hmm, I suppose it's caused by plugins then?

@cossssmin Maybe. Each plugin can render / parse a tree and return a mutated one

@cossssmin
Copy link
Member

Yeah, gonna have to start updating them all to use the latest posthtml or posthtml-parser, starting with posthtml-expressions.

@cossssmin
Copy link
Member

cossssmin commented Nov 24, 2020

Here's a list with plugins that need updating, ✔ = updated:

  • posthtml-expressions (v1.7.0)
  • posthtml-extend (v0.6.0)
  • posthtml-fetch (v1.2.1)
  • posthtml-markdownit (v1.2.3)
  • posthtml-mso (v1.0.3)
  • posthtml-postcss-merge-longhand (v1.0.3)
  • posthtml-safe-class-names (v1.0.5)
  • posthtml-url-parameters (v1.0.5)

@Scrum
Copy link

Scrum commented Nov 24, 2020

@cossssmin
posthtml-expressions -> 1.7.0
posthtml-extend -> 0.6.0

@cossssmin
Copy link
Member

@chasegiunta published v3.0.1, should work as expected now.

You'll need to delete your node_modules and package-lock.json, and run npm install again.

@chasegiunta
Copy link

@cossssmin Perfect. Looks like that works! Thank you for you help!

@cossssmin
Copy link
Member

Awesome, closing as resolved then 👍

@dwightwatson
Copy link

I wonder if anyone here would be willing to share how they've integrated Maizzle with their backend framework - both in a conceptual sense but also what a config file might look like. I'm trying to see how best to fit Maizzle into a Rails app and integrate it with ActionMailer. Would be super interesting as a blog post.

@pau-riosa
Copy link

Hi guys do you have sample integration for Phoenix Framework? Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants