mjmlio / mjml

MJML: the only framework that makes responsive-email easy
https://mjml.io
MIT License
17.08k stars 960 forks source link

Custom mj-head component causes TypeError: this.context.processing is not a function #2871

Closed Niesyto closed 5 months ago

Niesyto commented 5 months ago

Describe the bug I've tried creating custom head component but it crashes during mjml2html with TypeError: this.context.processing is not a function error

To Reproduce Steps to reproduce the behavior:

  1. Create following files Main component
    <mjml>
    <mj-head>
    <pp-head />
    </mj-head>
    <mj-body> </mj-body>
    </mjml>

    pp-head

    
    import { HeadComponent } from 'mjml-core';

export class PpHead extends HeadComponent { static endingTag = false; static tagName = 'pp-head';

render() { return this.renderMJML(`

  <mj-style inline="inline"> .link-nostyle { text-decoration: none } </mj-style>
  <mj-attributes>
    <mj-text color="#46586B" font-family="Inter, Arial" padding="12px 25px" />
    <mj-image align="left" />
    <mj-button align="left" font-family="Inter, Arial" />
    <mj-divider width="120px" border-width="1px" border-color="#E7E7E7" align="left" padding="0px 25px" />
  </mj-attributes>  
`);

} }


2. Register the pp-head component
3. Render using mjml2html

**Expected behavior**
`<pp-head>` component is created and included in `<head>` after rendering

**MJML environment (please complete the following information):**
 - OS: [fedora linux]
 - MJML Version [e.g. 4.15.2]
 - MJML tool used [e.g MJML npm package]

**Additional context**
I think the docs could use some improvement when it comes to custom components. 
iRyusa commented 5 months ago

Yeah you're using BodyComponent as a HeadComponent. There's no equivalent of renderMJML for HeadComponent. Head component can't use renderMJML because it define the context for the body components.

If you need to do so just use the low level API, but here you seem only to need a mj-include rather than over complexify your project with custom component

Niesyto commented 4 months ago

mj-include won't work in my case. mj-include is not bundled in my deployment file in AWS

iRyusa commented 4 months ago

mj-include are resolved by the parser, it's not a component 🤔

Niesyto commented 4 months ago

I know, and that's why i can't use it. Components have to be imported and registered, so they are included in the deployment file. mj-include is resolved by the parses, but since there's no reference to it, it's not bundled in.

iRyusa commented 4 months ago

I don't really follow you here if you render MJML files why you can't includes those "partial" too in your workflow ?

Niesyto commented 4 months ago

Even if I include this partial in the bundle, it does not get recognized by the mj-include. It seems like my setup prevents me from using it.

If you need to do so just use the low level API

What did you mean by that? It might be the solution I'm looking for

iRyusa commented 4 months ago

Are you using the cli or directly mjml2html if so you might need to pass the proper file path.

You can check the source code for MJML Head components to see how they push everything in the context https://github.com/mjmlio/mjml/blob/master/packages/mjml-head-style/src/index.js

Niesyto commented 4 months ago

I'm using mjml2html, but doing this worked well:

import { HeadComponent } from 'mjml-core';

export class PpHead extends HeadComponent {
  static tagName = 'pp-head';
  static endingTag = true;

  handler() {
    const { add } = this.context;

    add('inlineStyle', '.link-nostyle { text-decoration: none }');
    add('fonts', 'Inter', 'https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap');
    add('defaultAttributes', 'mj-text', {
      color: '#46586B',
      'font-family': 'Inter, Arial',
      padding: '12px 25px',
    });
    add('defaultAttributes', 'mj-image', { align: 'left' });
    add('defaultAttributes', 'mj-button', { align: 'left', 'font-family': 'Inter, Arial' });
    add('defaultAttributes', 'mj-divider', {
      width: '120px',
      'border-width': '1px',
      'border-color': '#E7E7E7',
      align: 'left',
      padding: '0px 25px',
    });
  }
}