'use strict' const mjml2html = require('mjml') const fs = require('fs') const Eta = require('eta') const path = require('path') const glob = require('glob') const chokidar = require('chokidar') const BASEROW_BACKEND_SRC_DIR = path.join(__dirname, '..', 'src') const MJML_FILE_SEARCH_ROOT = process.env.MJML_FILE_SEARCH_ROOT ? process.env.MJML_FILE_SEARCH_ROOT : BASEROW_BACKEND_SRC_DIR const MJML_ETA_FILE_GLOB = path.join(MJML_FILE_SEARCH_ROOT, '**', '*.mjml.eta') const ETA_LAYOUT_FILE_GLOB = path.join( MJML_FILE_SEARCH_ROOT, '**', '*.layout.eta' ) /** * Given a .mjml.eta file first renders the eta template to get a .mjml file and then * renders the mjml file to a normal html django template file. * * @param mjmlEtaFile The path to the .mjml.eta file. */ function compileEtaAndMjml(mjmlEtaFile) { const Reset = '\x1B[0m' const FgGreen = '\x1B[32m' console.log(`Compiling ${mjmlEtaFile}`) Eta.configure({ // Set views to the directory of the file to template so it can use layout(path) // statements relative to its own directory. views: path.dirname(mjmlEtaFile), }) const tmplText = fs.readFileSync(mjmlEtaFile, 'utf8') const mjmlText = Eta.render(tmplText, {}) const html = mjml2html(mjmlText, { validationLevel: 'strict', beautify: true, }).html const targetHtmlFile = mjmlEtaFile.replace('.mjml.eta', '.html') console.log( `${FgGreen}Writing compiled email template to ${targetHtmlFile}${Reset}` ) fs.writeFileSync(targetHtmlFile, html) } function recompileAllEtaAndMjmlFilesAfterLayoutFileChanges(layoutFile) { console.log(`Layout file changed (${layoutFile})`) glob(MJML_ETA_FILE_GLOB, {}, function (er, files) { files.forEach((file) => { compileEtaAndMjml(file) }) }) } /** * Watches *.mjml.eta and *.layout.eta files and runs the eta templater followed by * the mjml cli over them initial run and on change if run in watch mode. * * We use the simple javascript eta templating engine to first extend any base layout * files as MJML does not come with any built in templating. Secondly we use the MJML * cli tool to convert the MJML files into html ready to be used as a Django template. * * @param args If command line arg is watch then continually watches the files, * otherwise just runs templating/compiling once over matching files and exits. */ function main(args) { const watchMode = args.length > 0 && args[0] === 'watch' const mjmlEtaWatcher = chokidar .watch(MJML_ETA_FILE_GLOB, { persistent: watchMode }) .on('add', compileEtaAndMjml) if (watchMode) { console.log( 'Watching and recompiling changes to files found using glob pattern' + ` ${MJML_ETA_FILE_GLOB}` ) mjmlEtaWatcher.on('change', compileEtaAndMjml) chokidar .watch(ETA_LAYOUT_FILE_GLOB, { persistent: watchMode }) .on('change', recompileAllEtaAndMjmlFilesAfterLayoutFileChanges) } } const args = process.argv.slice(2) main(args)