
本文介绍如何利用 javascript 闭包与柯里化技术,将多个结构相同但路径不同的 gulp nunjucks 渲染任务抽象为单一可复用函数,避免代码重复、提升可维护性。
本文介绍如何利用 javascript 闭包与柯里化技术,将多个结构相同但路径不同的 gulp nunjucks 渲染任务抽象为单一可复用函数,避免代码重复、提升可维护性。
在构建工具链中,尤其是使用 Gulp v4+ 编写 gulpfile.js 时,常会遇到「功能一致、仅输入路径不同」的重复任务定义问题。例如,你可能需要分别处理 src/views/home/ 和 src/views/blog/ 两个视图目录,并各自输出到不同的目标路径(如 dist/home/ 和 dist/blog/)。若为每个路径单独编写一个 genNunJucks 类函数,不仅违反 DRY(Don’t Repeat Yourself)原则,还会显著增加维护成本——一旦渲染配置(如 nunjucksRender 选项或 htmlbeautify 格式)需调整,就必须同步修改多处。
解决这一问题的核心思路是:将变化的参数(如源路径、目标路径)提取为函数输入,将不变的流程封装为可复用的执行逻辑。这正是函数式编程中 柯里化(Currying) 与 闭包(Closure) 的典型应用场景。
✅ 推荐方案:柯里化 + 闭包生成任务函数
我们定义一个高阶函数 createNunjucksTask,它接收源路径(srcPath)和目标路径(destPath)作为参数,并返回一个符合 Gulp 任务签名((cb) => stream)的函数:
const { src, dest } = require('gulp');
const nunjucksRender = require('gulp-nunjucks');
const htmlbeautify = require('gulp-html-beautify');
// 高阶函数:返回一个可直接注册为 Gulp 任务的函数
function createNunjucksTask(srcPath, destPath) {
return function genNunJucks(cb) {
return src(srcPath)
.pipe(nunjucksRender({
path: ['src/views/'],
ext: '.html',
inheritExtension: false,
envOptions: { watch: true },
manageEnv: manageEnvironment,
loaders: null
}))
.pipe(htmlbeautify({
indentSize: 2,
eol: '\n',
indent_level: 0,
preserve_newlines: false
}))
.pipe(dest(destPath));
cb(); // 注意:Gulp v4 中若返回 stream,无需显式调用 cb();此处保留以兼容回调风格写法
};
}
// 使用示例:动态创建两个任务
exports.genHome = createNunjucksTask(paths.views.src, paths.views.dest);
exports.genBlog = createNunjucksTask(paths.views.src2, paths.views.dest2);? 关键说明:
- createNunjucksTask 在调用时捕获 srcPath 和 destPath,并通过闭包将其持久化到返回的 genNunJucks 函数作用域中;
- 返回的函数完全复用同一套管道逻辑,仅动态切换 I/O 路径,真正实现「逻辑一处定义,多处实例化」;
- 此方式天然支持任意数量的视图目录,只需新增一行 exports.xxx = createNunjucksTask(...) 即可。
? 进阶优化:批量注册任务(支持路径数组)
若视图目录较多(如 ['home', 'blog', 'docs']),还可进一步封装为批量注册函数:
function registerNunjucksTasks(configs) {
configs.forEach(({ name, src, dest }) => {
exports[name] = createNunjucksTask(src, dest);
});
}
// 批量声明
registerNunjucksTasks([
{ name: 'genHome', src: paths.views.src, dest: paths.views.dest },
{ name: 'genBlog', src: paths.views.src2, dest: paths.views.dest2 },
{ name: 'genDocs', src: 'src/views/docs/**/*', dest: 'dist/docs/' }
]);⚠️ 注意事项与最佳实践
- Gulp 版本兼容性:上述写法适用于 Gulp v4+。若使用 Gulp v3,请确保返回 stream 或显式调用 cb();v4 推荐返回 stream(自动处理异步),此时可省略 cb() 调用;
- 路径变量安全校验:建议在 createNunjucksTask 内部添加 if (!srcPath || !destPath) throw new Error('Missing src/dest path'),避免静默失败;
- 配置集中管理:将 nunjucksRender 和 htmlbeautify 的通用配置抽离为常量(如 NUJUCKS_OPTS, BEAUTIFY_OPTS),便于全局统一维护;
- 错误处理增强:可在 .pipe() 链后添加 .on('error', console.error) 或使用 gulp-plumber 插件防止管道中断。
通过函数式抽象,你不仅消除了重复代码,更赋予了构建脚本更强的表达力与扩展性——当业务增长、视图增多时,只需声明新路径,无需重写逻辑。这才是自动化构建应有的优雅姿态。










