mirror of
https://github.com/bitwarden/server
synced 2025-12-20 18:23:44 +00:00
* docs: update readme for MJML * docs: add readme for MailTemplates directory * feat: add node build script for cross platform build support
129 lines
3.9 KiB
JavaScript
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);
|
|
}
|