【问题标题】:"Write after end": how to imitate gulp-watch with watchify?“结束后写”:如何用watchify模仿gulp-watch?
【发布时间】:2019-01-31 22:46:42
【问题描述】:

以下 Gulp 任务几乎完成了我想要的。

const gulp = require('gulp');
const browserify = require('browserify');
const vinylStream = require('vinyl-source-stream');
const vinylBuffer = require('vinyl-buffer');
const watchify = require('watchify');
const glob = require('glob');
const jasmineBrowser = require('gulp-jasmine-browser');

gulp.task('test', function() {
    let testBundler = browserify({
        entries: glob.sync('src/**/*-test.js'),
        cache: {},
        packageCache: {},
    }).plugin(watchify);
    function updateSpecs() {
        return testBundler.bundle()
            .pipe(vinylStream(jsBundleName))
            .pipe(vinylBuffer())
            .pipe(jasmineBrowser.specRunner({console: true}))
            .pipe(jasmineBrowser.headless({driver: 'phantomjs'}));
    }
    testBundler.on('update', updateSpecs);
    updateSpecs();
});

它使用 Browserify 捆绑了我所有的 Jasmine 规格,并通过 gulp-jasmine-browser 对其进行了测试。它还会监视它们所依赖的所有规范和所有模块,并在这些模块中的任何一个发生更改时重新运行测试。

我真正希望看到解决的唯一丑陋的一点是,每次运行updateSpecs 时都会创建一个新的 PhantomJS 实例和一个新的 Jasmine 服务器。我希望使用如下代码来避免这种情况:

gulp.task('test', function() {
    let testBundler = browserify({
        entries: glob.sync('src/**/*-test.js'),
        cache: {},
        packageCache: {},
    }).plugin(watchify);
    // persist the Jasmine server and PhantomJS browser
    let testServer = jasmineBrowser.headless({driver: 'phantomjs'});
    function updateSpecs() {
        return testBundler.bundle()
            .pipe(vinylStream(jsBundleName))
            .pipe(vinylBuffer())
            .pipe(jasmineBrowser.specRunner({console: true}))
            .pipe(testServer);
    }
    testBundler.on('update', updateSpecs);
    updateSpecs();
});

唉,这行不通。启动任务后,所有测试都运行良好,但下次调用 updateSpecs 时,我收到 write after end 错误,任务以状态 1 退出。此错误源自 readable-stream Node 模块。

据我了解,updateSpecs 第一次运行期间的end 事件使testServer 处于不接受任何新输入的状态。不幸的是,Node.js streams documentation 并不清楚如何解决这个问题。

我尝试在不同的地方断开管道链,但得到了相同的结果,这似乎表明这是流的普遍行为。我还尝试通过插入一个没有重新发出该事件的直通流来阻止 end 事件的传播,但这完全阻止了测试的运行。最后,我尝试returning 来自任务的testServer 流;这停止了​​错误,但是尽管每次源更改时都会调用 updateSpecs 函数,但测试仅在任务第一次启动时运行。这一次,testServer 似乎只是忽略了新的输入。

gulp-jasmine-browser 文档建议以下代码可以工作:

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

gulp.task('test', function() {
    var filesForTest = ['src/**/*.js', 'spec/**/*-test.js'];
    return gulp.src(filesForTest)
        .pipe(watch(filesForTest))
        .pipe(jasmineBrowser.specRunner())
        .pipe(jasmineBrowser.server());
});

它继续建议您也可以使用 Browserify 进行这项工作,但这没有说明。显然,gulp-watch 做了一些事情,导致后续管道稍后接受更新的输入。如何使用 watchify 模仿这种行为?

【问题讨论】:

    标签: node.js gulp gulp-watch node-streams watchify


    【解决方案1】:

    GitHub issue

    事实证明,Node.js 中有一条硬性规定,即您不能在 end 事件之后编写代码。此外,jasmineBrowser.specRunner().server().headless() 必须接收end 信号才能实际测试任何东西。此限制继承自官方 Jasmine 测试运行器。

    出于同样的原因,README 中带有gulp-watch 的示例实际上也不起作用。为了使其正常工作,必须执行类似于问题中我的watchify 代码的工作版本的操作:

    gulp.task('test', function() {
        var filesForTest = ['src/**/*.js', 'spec/**/*-test.js'];
        function runTests() {
            return gulp.src(filesForTest)
                .pipe(jasmineBrowser.specRunner())
                .pipe(jasmineBrowser.server());
        }
        watch(filesForTest).on('add change unlink', runTests);
    });
    

    (我没有测试它,但非常接近这个的东西应该可以工作。)

    因此,无论您使用什么监视机制,您总是需要在每个周期再次调用 .specRunner().server()。好消息是,显然,如果您明确传递端口号,Jasmine 服务器将被重用:

                .pipe(jasmineBrowser.server({port: 8080}));
    

    这也适用于.headless()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-25
      相关资源
      最近更新 更多