You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Gulp JS任务报错NodeError:回调函数被多次调用

Gulp任务js_bundle报错:NodeError: Callback function called multiple times

我有五个Gulp JS任务,其中名为js_bundle的任务出现如下报错:

NodeError: Callback function called multiple times

以下是我的gulpfile.js完整代码:

const { src, dest, parallel , series , watch } = require('gulp');

const sass = require('gulp-sass')(require('sass'));
const fileinclude = require('gulp-file-include');
const sourcemaps = require('gulp-sourcemaps');
const uglify = require('gulp-uglify');
const minify = require('gulp-minifier');
const strip = require('gulp-strip-comments');
const rtlcss = require('gulp-rtlcss');
const rename = require('gulp-rename');

// sass.compiler = require('node-sass'); // no-need for gulp-sass v5+

var node_path = '../../../';


function html(cb) {
  src('html/src/**')
  .pipe(dest('html/dist/'));

  cb();
}

function scss(cb) {
  src(['scss/*.scss'])
  // .pipe(sourcemaps.init())               // If you want generate source map.
  .pipe(sass().on('error', sass.logError))  // uses {outputStyle: 'compressed'} in saas() for minify css
  // .pipe(sourcemaps.write('./'))          // If you want generate source map.
  .pipe(dest('assets/dist/css'));

  src(['scss/*.scss', '!scss/style-email.scss'])
  // .pipe(sourcemaps.init())               // If you want generate source map.
  .pipe(sass().on('error', sass.logError))  // uses {outputStyle: 'compressed'} in saas() for minify css
  // .pipe(sourcemaps.write('./'))          // If you want generate source map.
  .pipe(rtlcss())
  .pipe(rename({ suffix: '.rtl' }))
  .pipe(dest('assets/dist/css'));

  // EDITORS
  src(['scss/editors/*.scss'])
  // .pipe(sourcemaps.init())                                           // If you want generate source map.
  .pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError))   // remove {outputStyle: 'compressed'} from saas() if do not want to minify css
  // .pipe(sourcemaps.write('./'))                                      // If you want generate source map.
  .pipe(dest('assets/dist/css/editors'));

  src(['scss/editors/*.scss'])
  // .pipe(sourcemaps.init())                                           // If you want generate source map.
  .pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError))   // remove {outputStyle: 'compressed'} from saas() if do not want to minify css
  // .pipe(sourcemaps.write('./'))                                      // If you want generate source map.
  .pipe(rtlcss())
  .pipe(rename({ suffix: '.rtl' }))
  .pipe(dest('assets/dist/css/editors'));

  src(['scss/libs/*.scss'])
  // .pipe(sourcemaps.init())                                           // If you want generate source map.
  .pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError))   // remove {outputStyle: 'compressed'} from saas() if do not want to minify css
  // .pipe(sourcemaps.write('./'))                                      // If you want generate source map.
  .pipe(dest('assets/dist/css/libs'));

  // SKINS
  src(['scss/skins/*.scss'])
  // .pipe(sourcemaps.init())               // If you want generate source map.
  .pipe(sass().on('error', sass.logError))  // uses {outputStyle: 'compressed'} in saas() for minify css
  // .pipe(sourcemaps.write('./'))          // If you want generate source map.
  .pipe(dest('assets/dist/css/skins'));

  cb();
}

function js_scripts(cb) {
  src(['assets/src/js/*.js','!assets/src/js/bundle.js'])
  // .pipe(uglify())                        // If you minify the code.
  .pipe(dest('assets/dist/js'));

  src(['assets/src/js/charts/*.js'])
  .pipe(uglify())                        // If you want minify the code.
  .pipe(dest('assets/dist/js/charts'));

  src(['assets/src/js/apps/*.js'])
  // .pipe(uglify())                        // If you minify the code.
  .pipe(dest('assets/dist/js/apps'));

  cb();
}

/* The task giving me the error */
function js_bundle(cb) {
  src('assets/src/js/bundle.js')
  .pipe(fileinclude({
    prefix: '@@',
    basepath: '@file',
    context: { build: 'dist', nodeRoot: node_path }
  }))
  .pipe(strip())
  .pipe(minify({ minify: true, minifyJS: { sourceMap: false } }))     // Disable, if you dont want to minify bundle file.
  .pipe(dest('assets/dist/js'));

  src(['assets/src/js/libs/**', '!assets/src/js/libs/editors/skins/**'])
  .pipe(fileinclude({
    prefix: '@@',
    basepath: '@file',
    context: { build: 'dist', nodeRoot: node_path }
  }))
  .pipe(strip())
  .pipe(minify({ minify: true, minifyJS: { sourceMap: false } }))     // Disable, if you dont want to minify bundle file.
  .pipe(dest('assets/dist/js/libs'));

  src('assets/src/js/libs/editors/skins/**').pipe(dest('assets/dist/js/libs/editors/skins'));

  cb();
}

function assets(cb){
  src(['assets/src/**', '!assets/src/js/**', '!assets/src/css/**'])
  .pipe(dest('assets/dist/'));

  cb();
}

exports.build = series(html, scss, js_scripts, /* The task giving me the error */ js_bundle, assets);

exports.develop = function() {
    watch(['scss/*.scss','scss/**'], scss)
    watch(['html/src/*.html','html/src/**/*.html'], html)
    watch(['assets/src/**'], assets)
    watch(['assets/src/js/*.js','assets/src/js/charts/*.js', 'assets/src/js/apps/*.js', '!assets/src/js/bundle.js'], js_scripts)
    watch(['assets/src/js/libs/**','assets/src/js/bundle.js'], js_bundle)
};

经排查,引发报错的核心代码片段是:

.pipe(fileinclude({
    prefix: '@@',
    basepath: '@file',
    context: { build: 'dist', nodeRoot: node_path }
}))

已尝试的解决方法(均无效)

  • 将gulp-file-include插件更新至最新版本;
  • 日志排查回调函数调用情况,未发现异常;
  • 移除strip和minify步骤后仍报错,确认gulp-file-include是可疑根源;
  • 参考相关问题,但未使用文中提到的gulp-imagemin插件。

解决方案

问题出在你使用**回调函数(cb)**的方式上:Gulp任务中如果存在多个异步流(比如多个src()调用),直接调用cb()会导致任务在异步流完成前就结束,而后续异步流的回调可能会触发多次cb,从而引发错误。

正确的做法是将多个异步流合并,或者使用返回流/Promise的方式处理异步操作。这里推荐使用parallel来合并多个流,确保所有异步操作完成后再结束任务:

修改js_bundle任务如下:

const { src, dest, parallel , series , watch } = require('gulp');
// ... 保留其他依赖

/* 修改后的js_bundle任务 */
function js_bundle() {
  // 定义三个异步流任务
  const bundleMain = src('assets/src/js/bundle.js')
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file',
      context: { build: 'dist', nodeRoot: node_path }
    }))
    .pipe(strip())
    .pipe(minify({ minify: true, minifyJS: { sourceMap: false } }))
    .pipe(dest('assets/dist/js'));

  const bundleLibs = src(['assets/src/js/libs/**', '!assets/src/js/libs/editors/skins/**'])
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file',
      context: { build: 'dist', nodeRoot: node_path }
    }))
    .pipe(strip())
    .pipe(minify({ minify: true, minifyJS: { sourceMap: false } }))
    .pipe(dest('assets/dist/js/libs'));

  const copySkins = src('assets/src/js/libs/editors/skins/**').pipe(dest('assets/dist/js/libs/editors/skins'));

  // 用parallel合并所有流,返回合并后的任务
  return parallel(bundleMain, bundleLibs, copySkins);
}

同理,你的其他任务(html、scss、js_scripts、assets)也存在同样的问题,建议一并修改,避免后续出现类似错误。比如修改html任务:

function html() {
  return src('html/src/**').pipe(dest('html/dist/'));
}

原理说明

Gulp 4+要求异步任务必须通过以下方式之一告知任务完成:

  1. 返回一个流(Stream)
  2. 返回一个Promise
  3. 使用async/await
  4. 调用回调函数cb(只能调用一次)

你之前的写法直接调用cb(),没有等待多个src()流完成,当gulp-file-include这类异步插件处理完成后,可能会触发额外的回调,导致cb被多次调用,从而抛出错误。改用返回流或合并流的方式,Gulp会自动跟踪所有异步操作的完成状态,避免重复调用回调的问题。


内容的提问来源于stack exchange,提问作者Codestrip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 18:00:02