如何解決在執行gulp任務中出現的錯誤ReferenceError: primordials is not defined

  最近在執行一個gulp任務時遇到下面這個錯誤:

  Google的結果是說這個是gulp 3在Node 12.x上的一個bug。解決的辦法有兩個:要麼通過nvm將node版本降到12以下,要麼將gulp升級到4。由於我工作的電腦上還有其它的項目需要依賴node 12.x版本,所以只能採用第二種辦法,將gulp升級到4.0.2。升級完之後繼續執行剛纔的命令,然後問題又來了:

  按照console中的錯誤描述:Did you forget to signal async completion? 意思是說這個gulp任務有可能是個異步操作,需要標記爲async。然後我修改了gulp.js文件,在對應的task的回調函數前加了async標記,重新執行命令,順利通過!

gulp.task('makeNodeModule', async () => {
    var destPath = "./out";

    gulp.src("./lib/**", { 'dot': true })
    .pipe(gulp.dest(destPath + "/lib", {'overwrite':true}));

    gulp.src("./res/**", { 'dot': true })
    .pipe(gulp.dest(destPath + "/res", {'overwrite':true}));

    gulp.src("./package.json")
    .pipe(gulp.dest(destPath, {'overwrite':true}));
});

  這是由於在gulp的任務中包含了異步代碼,你必須在任務執行完後告訴gulp(異步操作)。在gulp 3.x中可以不用處理,如果沒有顯式地進行async標記,gulp會假定任務是同步執行的,一旦函數返回結果,gulp的任務也就結束了。但是gulp 4在這方面要求更加嚴格,你必須明確告知gulp任務何時執行完畢。事實上,按照gulp的官方文檔的描述,有以下六種解決辦法

  1. 返回Stream
    如果gulp任務只是在控制檯輸出一些信息,這個解決辦法可能並不適用。不過在大多數情況下我們都會使用gulp streams來完成一個異步操作,下面是一個例子:
    var print = require('gulp-print');
    
    gulp.task('message', function() {
      return gulp.src('package.json')
        .pipe(print(function() { return 'HTTP Server Started'; }));
    });

    這裏的return語句是關鍵,如果不返回stream,gulp就不會知道該任務何時結束。當然,如果一個gulp任務中存在多個異步操作,則該解決辦法也不適用,繼續往下看。

  2. 返回一個Promise
    在大多數情況下,這個解決辦法可能更適用。不過在真實使用場景下,你可能並不需要自己創建一個Promise對象,我們可以藉助於第三方的包來構建一個Promise(例如使用del包)。
    gulp.task('message', function() { 
      return new Promise(function(resolve, reject) {
        console.log("HTTP Server Started");
        resolve();
      });
    });

    使用async/await語法可以進一步簡化上面的代碼。所有標記爲async的函數都會隱式地返回一個Promise,所以上面的代碼也可以改成下面這種形式(前提是你使用的node版本要支持):

    gulp.task('message', async function() {
      console.log("HTTP Server Started");
    });

    顯然,如果一個gulp中存在多個異步操作,這個解決辦法更加適用。

  3. 調用回調函數
    這個解決辦法可能是最容易的。由於gulp會自動將回調函數作爲第一個參數傳遞進來,所以當任務執行完後,你可以顯式地執行這個回調函數:
    gulp.task('message', function(done) {
      console.log("HTTP Server Started");
      done();
    }); 
  4. 返回一個子進程
    不太推薦這個解決辦法,因爲它可能會過度依賴於系統環境。但是如果你可以在代碼中直接調用命令行工具,這個解決辦法可能會有用。
    var spawn = require('child_process').spawn;
    
    gulp.task('message', function() {
      return spawn('echo', ['HTTP', 'Server', 'Started'], { stdio: 'inherit' });
    });
  5. 返回一個RxJS Observable
    如果你使用RxJS,這個解決辦法可能會適用。
    var of = require('rxjs').of;
    
    gulp.task('message', function() {
      var o = of('HTTP Server Started');
      o.subscribe(function(msg) { console.log(msg); });
      return o;
    });
  6. 返回一個EventEmitter
    和前一個一樣,真實場景下你可能不太會使用這個解決辦法,不過如果你已經在代碼中使用了EventEmitter,這個解決辦法可能會有用。
    gulp.task('message3', function() {
      var e = new EventEmitter();
      e.on('msg', function(msg) { console.log(msg); });
      setTimeout(() => { e.emit('msg', 'HTTP Server Started'); e.emit('finish'); });
      return e;
    });

     

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章