4

I'm getting an error when I watch for changes in index.html (full path in CONFIG.APP.INDEX). All my tasks are in separate files. this is tasks/watch.ts, for example:

import * as CONFIG from '../config';

export default done => {
  // other watches
  gulp.watch(CONFIG.APP.INDEX, gulp.series('inject'));
};

on first change task is executed normally, but on second change I'm getting this error:

c:\~\node_modules\through2\node_modules\readable-stream\lib\_stream_writable.js:203
  var er = new Error('write after end');
           ^
Error: write after end
    at writeAfterEnd (c:\~\node_modules\through2\node_modules\readable-stream\lib\_stream_writable.js:203:12)
    at DestroyableTransform.Writable.write (c:\~\node_modules\through2\node_modules\readable-stream\lib\_stream_writable.js:239:20)
    at DestroyableTransform.ondata (c:\~\node_modules\through2\node_modules\readable-stream\lib\_stream_readable.js:531:20)
    at emitOne (events.js:77:13)
    at DestroyableTransform.emit (events.js:169:7)
    at readableAddChunk (c:\~\node_modules\through2\node_modules\readable-stream\lib\_stream_readable.js:198:18)
    at DestroyableTransform.Readable.push (c:\~\node_modules\through2\node_modules\readable-stream\lib\_stream_readable.js:157:10)
    at DestroyableTransform.Transform.push (c:\~\node_modules\through2\node_modules\readable-stream\lib\_stream_transform.js:123:32)
    at afterTransform (c:\~\node_modules\through2\node_modules\readable-stream\lib\_stream_transform.js:79:51)
    at TransformState.afterTransform (c:\~\node_modules\through2\node_modules\readable-stream\lib\_stream_transform.js:58:12)
    at c:\~\node_modules\vinyl-fs\lib\src\getContents\bufferFile.js:18:5
    at c:\~\node_modules\graceful-fs\graceful-fs.js:78:16
    at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:404:3)

tasks/inject.ts task:

declare var require;
const gulp = require('gulp');
const plugins = require('gulp-load-plugins')();
import * as CONFIG from '../config';

export default done => {
  return gulp
    .src(CONFIG.APP.INDEX)

    .pipe(require('../util/inject/fixes').default) // <--- PROBLEM IS HERE
    // other stuff...
    .pipe(gulp.dest(CONFIG.DST.BUILD))
    .on('error', plugins.util.log);
};

util/inject/fixes.ts task

declare var require;
const plugins = require('gulp-load-plugins')();

// errors even with this...
export default plugins.util.noop();

Tasks are loaded from gulpfile.ts/index.ts like this:

fs.readdirSync('./gulpfile.ts/tasks').map(file => {
  let name = file.replace(/\.ts$/, '');
  let task = require(path.join(path.resolve('.'), 'gulpfile.ts', 'tasks', file));
  gulp.task(name, task.default);
});

I've managed to identify where the error comes from, but no idea what's causing it, or how to fix it. Problem only occurs when watching index.html after first change and task execution. Running task manually works normally (gulp inject), and all other watches and tasks work normally.

Sasxa
  • 40,334
  • 16
  • 88
  • 102

1 Answers1

4

I suspect that your implementation of fixes.ts is reusing the same noop() result instead of recreating the result each time the task is run.

Try converting the fixes.ts to return a factory function that will return a new noop instance each time the task is invoked.

util/inject/fixes.ts:

declare var require;
const plugins = require('gulp-load-plugins')();

// Return a function that will return a new `noop` instance each time:
export default () => {
    return plugins.util.noop();
};

For context, I just had a similar problem in my project where I was accidentally reusing a gulp stream and getting the "write after end" error.

I suspect your code is doing the same sort of thing with the noop() result because that one value will be cached as the value of that module.

Incorrect version of my gulpfile.js - the result of my gulp.dest() calls was being reused each time.

let gulp = require('gulp');
let merge = require('merge-stream');

let _path = require('path');

let files = {
    'html': {
        src: _path.join('public', 'index.html'),
        dest: gulp.dest('public')  // <-- WRONG use of `gulp.dest()`, causes result to be reused and gives "write after end" error
    },
    'files': 'html': {
        src: _path.join('files', '*'),
        dest: gulp.dest('files')  // <-- WRONG use of`gulp.dest()`
    },
};

gulp.task('copy', function(){
    let html = gulp.src(files.html.src)
        .pipe(files.html.dest);   // <-- `gulp.dest()` should be here

    let files = gulp.src(files.files.src)
        .pipe(files.files.dest);  // <-- `gulp.dest()` should be here

    return merge(html, files);
});


gulp.task('copy-watch', function(){
    let srcList = Object.keys(files).map(i => files[i].src);
    gulp.watch(srcList, ['copy']);
});

Fixed version of my gulpfile.js - gulp.dest() is being called each time the task is run:

let files = {
    'html': {
        src: _path.join('public', 'index.html'),
        dest: 'public'  // <-- removed `gulp.dest()` call from here
    },
    'files': 'html': {
        src: _path.join('files', '*'),
        dest: 'files'  // <-- removed `gulp.dest()` call from here
    },
};

gulp.task('copy', function(){
    let html = gulp.src(files.html.src)
        .pipe(gulp.dest(files.html.dest));  // <-- CORRECT use of`gulp.dest()`

    let files = gulp.src(files.files.src)
        .pipe(gulp.dest(files.files.dest)); // <-- CORRECT use of `gulp.dest()`

    return merge(html, files);
});
Sly_cardinal
  • 12,270
  • 5
  • 49
  • 50