[node.js] Gulp 시계가 깨지거나 충돌하는 것을 방지

gulp 3.6.2를 실행 중이며 샘플 온라인에서 설정 한 다음 작업이 있습니다.

gulp.task('watch', ['default'], function () {
  gulp.watch([
    'views/**/*.html',
    'public/**/*.js',
    'public/**/*.css'
  ], function (event) {
    return gulp.src(event.path)
      .pipe(refresh(lrserver));
  });

  gulp.watch(['./app/**/*.coffee'],['scripts']);
  gulp.watch('./app/**/*.scss',['scss']);
});

CoffeeScript gulp 시계에 오류가 발생하면 언제든지 내가 원하는 것이 아닙니다.

다른 곳에서 추천했듯이 이것을 시도했습니다.

gulp.watch(['./app/**/*.coffee'],['scripts']).on('error', swallowError);
gulp.watch('./app/**/*.scss',['scss']).on('error', swallowError);
function swallowError (error) { error.end(); }

그러나 작동하지 않는 것 같습니다.

내가 뭘 잘못하고 있죠?


@ Aperçu의 답변에 따라 내 swallowError방법을 수정 하고 대신 다음을 시도했습니다.

gulp.task('scripts', function () {
  gulp.src('./app/script/*.coffee')
    .pipe(coffee({ bare: true }))
    .pipe(gulp.dest('./public/js'))
    .on('error', swallowError);
});

다시 시작한 다음 커피 파일에 구문 오류가 발생했습니다. 같은 문제 :

[gulp] Finished 'scripts' after 306 μs

stream.js:94
      throw er; // Unhandled stream error in pipe.
            ^
Error: W:\bariokart\app\script\trishell.coffee:5:1: error: unexpected *
*
^
  at Stream.modifyFile (W:\bariokart\node_modules\gulp-coffee\index.js:37:33)
  at Stream.stream.write (W:\bariokart\node_modules\gulp-coffee\node_modules\event-stream\node_modules\through\index.js:26:11)
  at Stream.ondata (stream.js:51:26)
  at Stream.EventEmitter.emit (events.js:95:17)
  at queueData (W:\bariokart\node_modules\gulp\node_modules\vinyl-fs\node_modules\map-stream\index.js:43:21)
  at next (W:\bariokart\node_modules\gulp\node_modules\vinyl-fs\node_modules\map-stream\index.js:71:7)
  at W:\bariokart\node_modules\gulp\node_modules\vinyl-fs\node_modules\map-stream\index.js:85:7
  at W:\bariokart\node_modules\gulp\node_modules\vinyl-fs\lib\src\bufferFile.js:8:5
  at fs.js:266:14
  at W:\bariokart\node_modules\gulp\node_modules\vinyl-fs\node_modules\graceful-fs\graceful-fs.js:104:5
  at Object.oncomplete (fs.js:107:15)



답변

귀하의 swallowError기능은 다음과 같아야합니다 :

function swallowError (error) {

  // If you want details of the error in the console
  console.log(error.toString())

  this.emit('end')
}

문제가 발생하지 않기 때문에 작업이 error아닌 떨어지는 작업의 경우이 기능을 바인딩해야한다고 생각합니다. 작업 중지 를 방지하기 위해 또는 다른 것을 watch놓쳤습니다 .;watch

예 :

gulp.task('all', function () {
  gulp.src('./app/script/*.coffee')
    .pipe(coffee({ bare: true }))
    .on('error', swallowError)
    .pipe(gulp.dest('./public/js'))

  gulp.src('css/*.scss')
    .pipe(sass({ compass: true }))
    .on('error', swallowError)
    .pipe(cssmin())
    .pipe(gulp.dest('dist'))
})

또는 다른 모듈을 포함하지 않으려는 경우 gulp-utillog 함수를 사용하여 추가 함수를 선언하지 못하게 할 수 있습니다 .gulpfile

.on('error', gutil.log)

그러나 이벤트 처리기 를 제거 하여 스트림이 중단 되는 멋진 gulp-plumber 플러그인을 살펴 보는 것이 좋습니다 . 사용이 매우 간단하고 실패 할 수있는 모든 작업을 잡을 수 없습니다.onerrorerror

gulp.src('./app/script/*.coffee')
  .pipe(plumber())
  .pipe(coffee({ bare: true }))
  .pipe(gulp.dest('./public/js'))

관련 플러그인의 작성자 가이 기사 에 대한 자세한 정보를 제공합니다 .


답변

위의 예제는 저에게 효과적이지 않았습니다. 그러나 다음은 수행했습니다.

var plumber = require('gulp-plumber');
var liveReload = require('gulp-livereload');
var gutil = require('gulp-util');
var plumber = require('gulp-plumber');
var compass = require('gulp-compass');
var rename = require('gulp-rename');
var minifycss = require('gulp-minify-css');
var notify = require('gulp-notify');

gulp.task('styles', function () {
    //only process main.scss which imports all other required styles - including vendor files.
    return gulp.src('./assets/scss/main.scss')
            .pipe(plumber(function (error) {
                gutil.log(error.message);
                this.emit('end');
            }))
            .pipe(compass({
                config_file: './config.rb',
                css: './css'
                , sass: './assets/scss'
            }))
            //minify files
            .pipe(rename({suffix: '.min'}))
            .pipe(minifycss())

            //output
            .pipe(gulp.dest('./css'))
            .pipe(notify({message: 'Styles task complete'}));
});

gulp.task('watch', function () {
    liveReload.listen();
    gulp.watch('assets/scss/**/*.scss', ['styles']);
});


답변

한 가지 형식의 파일

(예 : *. 커피 만)

한 가지 형식의 파일로만 작업하려면 gulp-plumber솔루션이 필요합니다.

예를 들어 풍부한 처리 오류 및 커피 스크립팅에 대한 경고 :

gulp.task('scripts', function() {
  return gulp.src(['assets/scripts/**/*.coffee'])
    .pipe(plumber())
    .pipe(coffeelint())
    .pipe(coffeelint.reporter())
    .pipe(lintThreshold(10, 0, lintThresholdHandler))
    .pipe(coffee({
      bare: true
    }))
    .on('error', swallowError)
    .pipe(concat('application.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe(notify({ message: 'Scripts task complete' }));
});

여러 유형의 파일 형식

(예 : * .coffee와 * .js를 동시에)

그러나 여러 유형의 파일 형식 (예 : *.js*.coffee) 으로 작업하지 않으면 솔루션을 게시합니다.

여기에 설명이 포함 된 자체 설명 코드를 게시하겠습니다.

gulp.task('scripts', function() {
  // plumber don't fetch errors inside gulpif(.., coffee(...)) while in watch process
  return gulp.src(['assets/scripts/**/*.js', 'assets/scripts/**/*.coffee'])
    .pipe(plumber())
    .pipe(gulpif(/[.]coffee$/, coffeelint()))
    .pipe(coffeelint.reporter())
    .pipe(lintThreshold(10, 0, lintThresholdHandler))
    .pipe(gulpif(/[.]coffee$/, coffee({ // if some error occurs on this step, plumber won't catch it
      bare: true
    })))
    .on('error', swallowError)
    .pipe(concat('application.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe(notify({ message: 'Scripts task complete' }));
});

나는 사용 gulp-plumber하고 있는 문제에 직면했다.gulp-ifgulp.watch(...

https://github.com/floatdrop/gulp-plumber/issues/23에서 관련 문제를 참조하십시오.

그래서 가장 좋은 옵션은 다음과 같습니다.

  • 각 부분은 파일로 사용되며 이후에 연결 됩니다. grunt처럼 별도의 파일로 각 부분을 처리 할 수있는 여러 작업을 만들어 연결
  • 각 부분을 스트림으로하고 스트림을에 병합합니다 . merge-stream(에서 만든 event-stream)을 사용하여 두 개의 스트림 을 하나로 병합 하고 작업을 계속하십시오 (먼저 시도했지만 제대로 작동하므로 이전보다 더 빠른 솔루션입니다)

각 부분을 스트림으로 만들고 이후에 스트림을 병합

그녀는 내 코드의 주요 부분입니다.

gulp.task('scripts', function() {
  coffeed = gulp.src(['assets/scripts/**/*.coffee'])
    .pipe(plumber())
    .pipe(coffeelint())
    .pipe(coffeelint.reporter())
    .pipe(lintThreshold(10, 0, lintThresholdHandler))
    .pipe(coffee({
      bare: true
    }))
    .on('error', swallowError);

  jsfiles = gulp.src(['assets/scripts/**/*.js']);

  return merge([jsfiles, coffeed])
    .pipe(concat('application.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe(notify({ message: 'Scripts task complete' }));
});

각 부분은 파일로 연결되고

이것을 부분으로 분리하면 각 부분에 결과 파일이 작성되어야합니다. 예를 들어 :

gulp.task('scripts-coffee', function() {

  return gulp.src(['assets/scripts/**/*.coffee'])
    .pipe(plumber())
    .pipe(coffeelint())
    .pipe(coffeelint.reporter())
    .pipe(lintThreshold(10, 0, lintThresholdHandler))
    .pipe(coffee({
      bare: true
    }))
    .on('error', swallowError)
    .pipe(concat('application-coffee.js'))
    .pipe(gulp.dest('dist/scripts'));

});

gulp.task('scripts-js', function() {

  return gulp.src(['assets/scripts/**/*.js'])
    .pipe(concat('application-coffee.js'))
    .pipe(gulp.dest('dist/scripts'));

});

gulp.task('scripts', ['scripts-js', 'scripts-coffee'], function() {

  var re = gulp.src([
    'dist/scripts/application-js.js', 'dist/scripts/application-coffee.js'
  ])
    .pipe(concat('application.js'))
    .pipe(gulp.dest('dist/scripts'))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe(notify({ message: 'Scripts task complete' }));

  del(['dist/scripts/application-js.js', 'dist/scripts/application-coffee.js']);

  return re;

});

추신:

사용 된 노드 모듈 및 기능은 다음과 같습니다.

// Load plugins
var gulp = require('gulp'),
    uglify = require('gulp-uglify'),
    rename = require('gulp-rename'),
    concat = require('gulp-concat'),
    notify = require('gulp-notify'),
    plumber = require('gulp-plumber'),
    merge = require('ordered-merge-stream'),
    replace = require('gulp-replace'),
    del = require('del'),
    gulpif = require('gulp-if'),
    gulputil = require('gulp-util'),
    coffee = require('gulp-coffee'),
    coffeelint = require('gulp-coffeelint),
    lintThreshold = require('gulp-coffeelint-threshold');

var lintThresholdHandler = function(numberOfWarnings, numberOfErrors) {
  var msg;
  gulputil.beep();
  msg = 'CoffeeLint failure; see above. Warning count: ';
  msg += numberOfWarnings;
  msg += '. Error count: ' + numberOfErrors + '.';
  gulputil.log(msg);
};
var swallowError = function(err) {
  gulputil.log(err.toString());
  this.emit('end');
};


답변

나는 gulp 배관공을 사용하여 작업에 전역 리스너를 추가하고 의미있는 메시지를 표시 할 수 있기 때문에 사용하고 싶습니다.

var plumber = require('gulp-plumber');

gulp.task('compile-scss', function () {
    gulp.src('scss/main.scss')
        .pipe(plumber())
        .pipe(sass())
        .pipe(autoprefixer())
        .pipe(cssnano())
        .pipe(gulp.dest('css/'));
});

참조 : https://scotch.io/tutorials/prevent-errors-from-crashing-gulp-watch


답변

https://github.com/gulpjs/gulp/issues/71에 대한 해결 방법으로 다음 해킹을 구현했습니다 .

// Workaround for https://github.com/gulpjs/gulp/issues/71
var origSrc = gulp.src;
gulp.src = function () {
    return fixPipe(origSrc.apply(this, arguments));
};
function fixPipe(stream) {
    var origPipe = stream.pipe;
    stream.pipe = function (dest) {
        arguments[0] = dest.on('error', function (error) {
            var state = dest._readableState,
                pipesCount = state.pipesCount,
                pipes = state.pipes;
            if (pipesCount === 1) {
                pipes.emit('error', error);
            } else if (pipesCount > 1) {
                pipes.forEach(function (pipe) {
                    pipe.emit('error', error);
                });
            } else if (dest.listeners('error').length === 1) {
                throw error;
            }
        });
        return fixPipe(origPipe.apply(this, arguments));
    };
    return stream;
}

gulpfile.js에 추가하고 다음과 같이 사용하십시오.

gulp.src(src)
    // ...
    .pipe(uglify({compress: {}}))
    .pipe(gulp.dest('./dist'))
    .on('error', function (error) {
        console.error('' + error);
    });

이것은 나에게 가장 자연스러운 오류 처리처럼 느껴집니다. 오류 처리기가 전혀 없으면 오류가 발생합니다. 노드 v0.11.13으로 테스트되었습니다.


답변

이것에 대한 간단한 해결책 gulp watch은 Bash (또는 sh) 쉘 내에 무한 루프 를 넣는 것 입니다.

while true; do gulp; gulp watch; sleep 1; done

JavaScript를 편집 할 때이 명령의 출력을 화면의 보이는 영역에 유지하십시오. 편집 결과 오류가 발생하면 Gulp는 충돌을 일으켜 스택 추적을 인쇄하고 잠시 기다렸다가 소스 파일보기를 다시 시작합니다. 그런 다음 구문 오류를 정정 할 수 있으며 Gulp는 편집 결과가 정상 출력인지 또는 다시 크래시 (다시 시작)하여 성공했는지 여부를 나타냅니다.

이것은 Linux 또는 Mac 터미널에서 작동합니다. Windows를 사용하는 경우 Cygwin 또는 Ubuntu Bash (Windows 10)를 사용하십시오.


답변

타이프 스크립트

이것이 나를 위해 일한 것입니다. 처리 Typescript하는 기능 ( this키워드 와의 혼란을 aovid 하기 위해)으로 작업 하고 분리했습니다 less. 이것은 또한 작동 Javascript합니다.

var gulp = require('gulp');
var less = require('gulp-less');

gulp.task('less', function() {
    // writing a function to avoid confusion of 'this'
    var l = less({});
    l.on('error', function(err) {
        // *****
        // Handle the error as you like
        // *****
        l.emit('end');
    });

    return gulp
        .src('path/to/.less')
        .pipe(l)
        .pipe(gulp.dest('path/to/css/output/dir'))
})

이제 귀하가 watch .less파일 을 제출하고 error발생 했을 때이 watch중지되지 않고 새로운 변경 사항이에 따라 처리됩니다 less task.

참고 : 나는 시도했다 l.end();; 그러나 작동하지 않았습니다. 하나,l.emit('end'); 완전히 작동합니다.

이 도움을 바랍니다. 행운을 빕니다.