1
0
mirror of https://github.com/bitwarden/server synced 2025-12-20 18:23:44 +00:00
Files
server/src/Core/MailTemplates/Mjml/build.js
Ike d722314e2d [PM-26551] MJML build script (#6417)
* docs: update readme for MJML
* docs: add readme for MailTemplates directory
* feat: add node build script for cross platform build support
2025-10-10 12:15:29 -04:00

129 lines
3.9 KiB
JavaScript

const mjml2html = require("mjml");
const { registerComponent } = require("mjml-core");
const fs = require("fs");
const path = require("path");
const glob = require("glob");
// Parse command line arguments
const args = process.argv.slice(2); // Remove 'node' and script path
// Parse flags
const flags = {
minify: args.includes("--minify") || args.includes("-m"),
watch: args.includes("--watch") || args.includes("-w"),
hbs: args.includes("--hbs") || args.includes("-h"),
trace: args.includes("--trace") || args.includes("-t"),
clean: args.includes("--clean") || args.includes("-c"),
help: args.includes("--help"),
};
// Use __dirname to get absolute paths relative to the script location
const config = {
inputDir: path.join(__dirname, "emails"),
outputDir: path.join(__dirname, "out"),
minify: flags.minify,
validationLevel: "strict",
hbsOutput: flags.hbs,
};
// Debug output
if (flags.trace) {
console.log("[DEBUG] Script location:", __dirname);
console.log("[DEBUG] Input directory:", config.inputDir);
console.log("[DEBUG] Output directory:", config.outputDir);
}
// Ensure output directory exists
if (!fs.existsSync(config.outputDir)) {
fs.mkdirSync(config.outputDir, { recursive: true });
if (flags.trace) {
console.log("[INFO] Created output directory:", config.outputDir);
}
}
// Find all MJML files with absolute path
const mjmlFiles = glob.sync(`${config.inputDir}/**/*.mjml`);
console.log(`\n[INFO] Found ${mjmlFiles.length} MJML file(s) to compile...`);
if (mjmlFiles.length === 0) {
console.error("[ERROR] No MJML files found!");
console.error("[ERROR] Looked in:", config.inputDir);
console.error(
"[ERROR] Does this directory exist?",
fs.existsSync(config.inputDir),
);
process.exit(1);
}
// Compile each MJML file
let successCount = 0;
let errorCount = 0;
mjmlFiles.forEach((filePath) => {
try {
const mjmlContent = fs.readFileSync(filePath, "utf8");
const fileName = path.basename(filePath, ".mjml");
const relativePath = path.relative(config.inputDir, filePath);
console.log(`\n[BUILD] Compiling: ${relativePath}`);
// Compile MJML to HTML
const result = mjml2html(mjmlContent, {
minify: config.minify,
validationLevel: config.validationLevel,
filePath: filePath, // Important: tells MJML where the file is for resolving includes
mjmlConfigPath: __dirname, // Point to the directory with .mjmlconfig
});
// Check for errors
if (result.errors.length > 0) {
console.error(`[ERROR] Failed to compile ${fileName}.mjml:`);
result.errors.forEach((err) =>
console.error(` ${err.formattedMessage}`),
);
errorCount++;
return;
}
// Calculate output path preserving directory structure
const relativeDir = path.dirname(relativePath);
const outputDir = path.join(config.outputDir, relativeDir);
// Ensure subdirectory exists
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const outputExtension = config.hbsOutput ? ".html.hbs" : ".html";
const outputPath = path.join(outputDir, `${fileName}${outputExtension}`);
fs.writeFileSync(outputPath, result.html);
console.log(
`[OK] Built: ${fileName}.mjml → ${path.relative(__dirname, outputPath)}`,
);
successCount++;
// Log warnings if any
if (result.warnings && result.warnings.length > 0) {
console.warn(`[WARN] Warnings for ${fileName}.mjml:`);
result.warnings.forEach((warn) =>
console.warn(` ${warn.formattedMessage}`),
);
}
} catch (error) {
console.error(`[ERROR] Exception processing ${path.basename(filePath)}:`);
console.error(` ${error.message}`);
errorCount++;
}
});
console.log(`\n[SUMMARY] Compilation complete!`);
console.log(` Success: ${successCount}`);
console.log(` Failed: ${errorCount}`);
console.log(` Output: ${config.outputDir}`);
if (errorCount > 0) {
process.exit(1);
}