Lifecycle Hooks
When compiling your email templates, Maizzle goes through a series of steps, like generating a Template config, rendering with Nunjucks, or applying Transformers.
Along the way, it also runs some functions known as lifecycle hooks.
We'll call them Events, for short.
Usage
You can use Events both when developing locally with the CLI build
or serve
commands, and when using the render()
method in Node.js.
CLI
To use events when developing locally with the CLI commands, add them inside an events
object in your config:
module.exports = {
events: {
afterConfig(config) {
//
},
// other events...
}
},
Node.js
To use Events in a Node context, add them inside the options
object that you pass to the render()
method:
const Maizzle = require('@maizzle/framework')
const str = `some HTML string...`
html = Maizzle.render(str, {
tailwind: { /* ... */ },
maizzle: { /* ... */ },
beforeRender(nunjucks, config) {
// ..
},
}
)
Events
These are the events that you can use in Maizzle.
The following events are CLI-only, meaning you can only use them in the events: {}
object in your config.js
:
The rest of the events run every time a Template is compiled. Unless you need access to the Template-specific config, or to its HTML, consider using the ones above instead:
beforeCreate
Runs after the Environment config has been computed, but before Templates are processed. Exposes the config object so you can further customize it.
For example, let's use a custom highlight function for Markdown fenced code blocks:
const Prism = require('prismjs')
module.exports = {
// ...
events: {
async beforeCreate(config) {
config.markdown.highlight = (code, lang, callback) => {
return Prism.highlight(code, Prism.languages[lang], lang)
}
},
},
}
beforeCreate
if you need to your config manipulation to run only once.afterConfig
Runs right after your Template-specific config has been generated.
It accepts the config
as a parameter, so you can further customize it.
For example, let's use Axios to set a random Bacon Ipsum preheader:
// config.js
const axios = require('axios')
module.exports = {
events: {
async afterConfig(config) {
const preheader = await axios('https://baconipsum.com/api/?type=all-meat&sentences=1&start-with-lorem=1')
config.preheader = preheader.data[0]
},
},
},
afterConfig
runs for each template that is going to be compiled. For performance reasons, you should use it only if you need access to the Template config (which includes variables from the template's Front Matter).beforeRender
Runs after Nunjucks is initialized, but before your Templates are rendered. It exposes the Nunjucks environment so you can add your own filters, extensions, or globals.
It also exposes the config, so you can further customize that as well.
As an example, let's add a custom filter to Nunjucks, that will allow us to shorten paragraphs to a custom character length (20 by default):
// config.js
module.exports = {
events: {
beforeRender(nunjucks, config) {
nunjucks.addFilter('shorten', (str, count) => str.slice(0, count || 20))
},
},
},
<!-- layouts/default.njk -->
{% if page.preheader %}
<div class="hidden text-0 leading-0">{{ page.preheader | shorten(35) }}</div>
{% endif %}
afterRender
Runs after the Template has been rendered with Nunjucks, but before any Transfomers have been applied.
Exposes the rendered html
string and the config
.
You can use it to alter the HTML, even before CSS inlining takes place. It's also your last chance to modify any Transformer-related settings in your config.
For example, let's assume that for some reason we change our mind and want to disable inlining. Oh, and we also want to rewrite all call-to-action labels (maybe they're coming from an external source, like a database?):
// config.js
module.exports = {
events: {
afterRender(html, config) {
config.inlineCSS.enabled = false
// must return `html`
return html.replace(/Confirm email/g, 'Confirm your email')
},
},
},
html
when using afterRender()
.afterTransformers
Runs after all Transformers have been applied, just before the final HTML is returned.
Same as afterRender()
, it exposes the html
and the config
, so you can do further adjustments to the HTML, or read some config settings.
For example, maybe you don't like the minifier that Maizzle includes, and you disabled it in your config so that you can use your own once the template has been compiled:
// config.js
const Minifier = require('imaginary-minifier')
module.exports = {
minify: {
enabled: false,
},
events: {
afterTransformers(html, config) {
// must return `html`
if (!config.minify.enabled) {
return Minifier.minify(html)
}
return html
},
},
},
html
when using afterTransformers()
.afterBuild
Runs after all Templates have been compiled and output to disk.
Returns an array with a list of all files inside the build.destination.path
directory.
// config.js
module.exports = {
events: {
afterBuild(files) {
console.log(files)
},
},
},
Using it with the default Starter, maizzle build production
will output:
[
'build_production/images/maizzle.png',
'build_production/promotional.html',
'build_production/transactional.html'
]
afterBuild
event is available only when using the maizzle build
CLI command, so it will only work if added to the events
object in your environment config.