
EJS 官方 CLI 不支持递归处理目录,但可通过 Node.js 脚本轻松实现:遍历源目录所有文件(含子目录),对每个 .ejs 或纯文本文件执行模板渲染,并按原始路径结构输出到目标目录。本文提供可直接运行的健壮脚本,支持数据注入、路径保留与扩展名智能处理。
ejs 官方 cli 不支持递归处理目录,但可通过 node.js 脚本轻松实现:遍历源目录所有文件(含子目录),对每个 `.ejs` 或纯文本文件执行模板渲染,并按原始路径结构输出到目标目录。本文提供可直接运行的健壮脚本,支持数据注入、路径保留与扩展名智能处理。
虽然 EJS 官方 CLI(ejs 命令)仅支持单文件渲染(如 ejs template.ejs -o output.html),它不提供递归处理整个目录树的功能,也无法自动保留嵌套目录结构。但借助 Node.js 原生 fs 模块与 ejs 库,我们能快速构建一个轻量、可靠且生产就绪的批量渲染工具。
以下是一个增强版递归渲染脚本,已解决原始示例中的关键缺陷(如路径冲突、子目录缺失、.ejs 后缀残留、数据复用等):
const fs = require('fs');
const path = require('path');
const ejs = require('ejs');
// ✅ 配置区:按需修改
const INPUT_DIR = 'my-template'; // 源模板目录(含 .ejs 文件或普通文本)
const OUTPUT_DIR = 'output'; // 输出根目录(将严格复现输入目录结构)
const DATA_FILE = 'data.json'; // 全局数据文件(同级目录下,JSON 格式)
const RENDER_EXTENSIONS = ['.ejs', '.html', '.txt', '.md', '.json', '.js', '.css']; // 支持渲染的扩展名
// 读取全局数据(支持注释的 JSON5 可选,此处用标准 JSON)
let data = {};
try {
data = JSON.parse(fs.readFileSync(path.join(__dirname, DATA_FILE), 'utf8'));
} catch (e) {
console.warn(`⚠️ 数据文件 ${DATA_FILE} 未找到或格式错误,使用空数据对象`);
}
// 递归处理函数(带路径映射)
function renderDirectory(dirPath) {
const files = fs.readdirSync(dirPath);
for (const file of files) {
const srcPath = path.join(dirPath, file);
const stats = fs.statSync(srcPath);
const relPath = path.relative(INPUT_DIR, srcPath); // 相对路径,用于重建输出结构
const dstPath = path.join(OUTPUT_DIR, relPath);
if (stats.isDirectory()) {
// 创建对应子目录
fs.mkdirSync(dstPath, { recursive: true });
renderDirectory(srcPath);
} else {
// 仅处理匹配扩展名的文件
const ext = path.extname(file).toLowerCase();
if (RENDER_EXTENSIONS.includes(ext)) {
try {
const content = fs.readFileSync(srcPath, 'utf8');
// 渲染:移除 .ejs 后缀(如 index.ejs → index.html)
let outputPath = dstPath;
if (ext === '.ejs') {
outputPath = outputPath.replace(/\.ejs$/, '');
}
const rendered = ejs.render(content, data, {
filename: srcPath, // 提供 filename 以支持 include 和错误定位
delimiter: '%', // 可选:兼容常见分隔符(默认为 , 也可设为 ? 或 $)
});
fs.writeFileSync(outputPath, rendered);
console.log(`✅ 渲染完成: ${relPath} → ${path.relative(OUTPUT_DIR, outputPath)}`);
} catch (err) {
console.error(`❌ 渲染失败 ${srcPath}:`, err.message);
process.exit(1);
}
} else {
// 非模板文件直接复制(如图片、字体等)
fs.copyFileSync(srcPath, dstPath);
console.log(`? 已复制(非模板): ${relPath}`);
}
}
}
}
// 启动
if (!fs.existsSync(INPUT_DIR)) {
throw new Error(`输入目录不存在: ${INPUT_DIR}`);
}
fs.rmSync(OUTPUT_DIR, { recursive: true, force: true });
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
console.log(`? 开始递归渲染目录: ${INPUT_DIR} → ${OUTPUT_DIR}`);
renderDirectory(INPUT_DIR);
console.log(`? 渲染完成!输出位于: ${OUTPUT_DIR}`);
? 使用说明:
- 在项目根目录安装依赖:
npm install ejs - 创建
my-template/目录,放入含等 EJS 语法的文件(支持嵌套子目录) - 创建
data.json(同级),例如:{ "title": "我的网站", "version": "2.1.0", "features": ["登录", "搜索", "导出"] } - 运行脚本:
node render.js
? 关键特性与注意事项:
- ✅ 路径保真:输出目录结构 1:1 复制源目录(
my-template/pages/about.ejs→output/pages/about) - ✅ 智能后缀处理:
.ejs文件自动剥离后缀,其他扩展名(如.html.ejs)可手动调整逻辑 - ✅ 错误友好:渲染失败时明确报错位置,便于调试模板语法或数据缺失问题
- ✅ 静态资源透传:非指定扩展名文件(如
.png,.woff2)自动复制,无需额外配置 - ⚠️ 安全提醒:勿在
data中传入不可信用户输入;生产环境建议启用ejs的escape选项或手动过滤 - ? 进阶扩展:可集成
chokidar实现热重载,或通过commander封装为 CLI 工具(如ejs-batch --input my-template --output dist --data config.json)
该方案无需依赖第三方 fork,代码简洁、无隐藏依赖、易于维护,是替代官方 CLI 批量能力的推荐实践。











