Skip to content

feat: Upgrade to MJML5 and prepare for V4 release#147

Open
AshCorr wants to merge 10 commits into
Faire:mainfrom
AshCorr:ash/mjml-v5
Open

feat: Upgrade to MJML5 and prepare for V4 release#147
AshCorr wants to merge 10 commits into
Faire:mainfrom
AshCorr:ash/mjml-v5

Conversation

@AshCorr
Copy link
Copy Markdown

@AshCorr AshCorr commented Apr 24, 2026

Upgrades @faire/mjml-react to MJML v5 which was released a few weeks ago. This is a breaking change as:

  • MJML v5 switches to using async functions, in particular the mjmlToHtml function, meaning @faire/mjml-react will also have to use async functions.
  • MJML v5 also drops the html-minifier dependency in exchange for htmlnano + cssnano and

This PR also prepares the documentations for a V4 release. Previously the documentation hinted at a V4 release that would include more type safety, however its been 3 years since work on that V4 release began and it seems like it might be dead now, so I've removed that documentation for the time being in order to use the v4 tag for this breaking change.

Fixes #145

@faizhasim
Copy link
Copy Markdown

@AshCorr @emmclaughlin , any ways we can help on this? Keen to see this out.

@AshCorr
Copy link
Copy Markdown
Author

AshCorr commented May 7, 2026

@AshCorr @emmclaughlin , any ways we can help on this? Keen to see this out.

Ah sorry, I got a bit stuck. For some reason the dist tests (yarn test-dist) keep failing with the following error:

TypeError: cssnano is not a function

However the same tests work fine in dev mode (yarn test), not entirely sure whats happening and why it specifically fails in dist mode. I have a suspicion its due to how htmlnano optionally imports cssnano here.

Attaching a debugger I noticed that when running yarn test-dist the cssnano import for some reason resolves to this package (@faire/mjml-react)

@anajavi
Copy link
Copy Markdown
Contributor

anajavi commented May 7, 2026

However the same tests work fine in dev mode (yarn test), not entirely sure whats happening and why it specifically fails in dist mode. I have a suspicion its due to how htmlnano optionally imports cssnano here.

Attaching a debugger I noticed that when running yarn test-dist the cssnano import for some reason resolves to this package (@faire/mjml-react)

yarn test-dist works for me if I change moduleNameMapper in jest-dist.config.js to:

  moduleNameMapper: {
    "^src(.*)$": "<rootDir>/dist$1",
  },

"src(.*)$": "<rootDir>/dist$1",

Don't know if it is the right fix, but this points that the problem lies in jest config.

edit: actually it just makes the tests not to run against dist. so ignore this

@anajavi
Copy link
Copy Markdown
Contributor

anajavi commented May 7, 2026

The cssnano has its main defined as `src/index.js:
https://github.com/cssnano/cssnano/blob/master/packages/cssnano/package.json#L5

The jest-dist.config.js moduleNameMapper mangles it to <rootDir>/dist/index.js

That is why cssnano import gets @faire/mjml-react as its module.

Setting the moduleNameMapper to include ../src used in tests fixes it while still running tests against dist.

  moduleNameMapper: {
    "\\.\\./src(.*)$": "<rootDir>/dist$1",
  },

It ain't pretty fix though.

@faizhasim
Copy link
Copy Markdown

^\\.\\./src(.*)$ seems good enough to target only the files in this repo.

@anajavi
Copy link
Copy Markdown
Contributor

anajavi commented May 8, 2026

Since this is going to be v4 release, I'd bump the tsconfig target to es2020 too.
https://github.com/Faire/mjml-react/blob/main/tsconfig.json#L5

Easier to use debugger when async..await is not transformed.

@AshCorr
Copy link
Copy Markdown
Author

AshCorr commented May 8, 2026

The cssnano has its main defined as `src/index.js: https://github.com/cssnano/cssnano/blob/master/packages/cssnano/package.json#L5

The jest-dist.config.js moduleNameMapper mangles it to <rootDir>/dist/index.js

That is why cssnano import gets @faire/mjml-react as its module.

Setting the moduleNameMapper to include ../src used in tests fixes it while still running tests against dist.

  moduleNameMapper: {
    "\\.\\./src(.*)$": "<rootDir>/dist$1",
  },

It ain't pretty fix though.

Aha! Thanks, I'll give that a shot and update this PR today!

BREAKING CHANGE: The `render` function is now asynchronous and returns a promise.
This is because MJML v5 introduces asynchronous rendering which is non optional.
@anajavi
Copy link
Copy Markdown
Contributor

anajavi commented May 8, 2026

This PR is still draft. Should it be set to ready for review?

@AshCorr
Copy link
Copy Markdown
Author

AshCorr commented May 8, 2026

This PR is still draft. Should it be set to ready for review?

Just testing everything!

Also wondering if we should do some dependency upgrades, but maybe that should be a follow up PR. Would be nice to release V4 with the latest versions of everything rather than just MJML.

@AshCorr
Copy link
Copy Markdown
Author

AshCorr commented May 8, 2026

Alrighty, I published a test version to @ashcorr/mjml-react@1.0.2 and tried using it in for one of our services and the new version of the library seems to behave appropriately. Tried with minification both on and off and didn't notice any issues.

Obviously we're not going to be using all of the functionality of mjml-react, so this test wouldn't have covered everything, but hopefully the unit tests that mjml-react has will be enough to catch any other regressions.

@AshCorr AshCorr marked this pull request as ready for review May 8, 2026 11:33
Comment thread package.json
"format": "prettier --write .",
"test": "jest",
"test-dist-skip-build": "jest --config=jest-dist.config.js",
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without --experimental-vm-modules Jest seemingly explodes due to a dependency on prettier@3.0.0 by mjml-core

prettier/prettier#15769 (I tried upgrading to Jest v30 and it didnt fix the issue)

@anajavi
Copy link
Copy Markdown
Contributor

anajavi commented May 10, 2026

Also wondering if we should do some dependency upgrades, but maybe that should be a follow up PR. Would be nice to release V4 with the latest versions of everything rather than just MJML.

I created a PR for typescript upgrade #149.

@AshCorr
Copy link
Copy Markdown
Author

AshCorr commented May 11, 2026

@emmclaughlin FYI!

Copy link
Copy Markdown
Collaborator

@emmclaughlin emmclaughlin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking this on! Left a few comments

Comment thread package.json Outdated
Comment thread src/utils/render.ts Outdated
Comment thread README.md Outdated
Comment thread README.md Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mjml 5.0 support

4 participants