"Write after end":如何用watchify模仿gulp-watch?
"Write after end": how to imitate gulp-watch with watchify?
以下 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
节点模块。
据我了解,updateSpecs
的第一个 运行 期间的 end
事件使 testServer
处于不接受任何新输入的状态.不幸的是,Node.js streams documentation 并不清楚如何解决这个问题。
我试过在不同的地方断开管道链,但我得到了相同的结果,这似乎表明这是流的普遍行为。我还尝试通过插入一个不重新发出该事件的直通流来阻止 end
事件传播,但这根本阻止了测试 运行。最后,我尝试 return
ing 来自任务的 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 中的硬性规定是您不能在 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()
。
以下 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
节点模块。
据我了解,updateSpecs
的第一个 运行 期间的 end
事件使 testServer
处于不接受任何新输入的状态.不幸的是,Node.js streams documentation 并不清楚如何解决这个问题。
我试过在不同的地方断开管道链,但我得到了相同的结果,这似乎表明这是流的普遍行为。我还尝试通过插入一个不重新发出该事件的直通流来阻止 end
事件传播,但这根本阻止了测试 运行。最后,我尝试 return
ing 来自任务的 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 中的硬性规定是您不能在 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()
。