diff --git a/LICENSE.md b/LICENSE.md index a2f89205e25..30d0081b0a1 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -112,7 +112,7 @@ Repository: https://github.com/acornjs/acorn.git ## anymatch License: ISC By: Elan Shanker -Repository: git+https://github.com/micromatch/anymatch.git +Repository: https://github.com/micromatch/anymatch > The ISC License > @@ -135,14 +135,14 @@ Repository: git+https://github.com/micromatch/anymatch.git ## binary-extensions License: MIT By: Sindre Sorhus -Repository: git+https://github.com/sindresorhus/binary-extensions.git +Repository: sindresorhus/binary-extensions --------------------------------------- ## braces License: MIT By: Jon Schlinkert, Brian Woodward, Elan Shanker, Eugene Sharygin, hemanth.hm -Repository: git+https://github.com/micromatch/braces.git +Repository: micromatch/braces > The MIT License (MIT) > @@ -207,7 +207,7 @@ Repository: sindresorhus/date-time ## fill-range License: MIT By: Jon Schlinkert, Edo Rivai, Paul Miller, Rouven Weßling -Repository: git+https://github.com/jonschlinkert/fill-range.git +Repository: jonschlinkert/fill-range > The MIT License (MIT) > @@ -236,7 +236,7 @@ Repository: git+https://github.com/jonschlinkert/fill-range.git ## glob-parent License: ISC By: Gulp Team, Elan Shanker, Blaine Bublitz -Repository: git+https://github.com/gulpjs/glob-parent.git +Repository: gulpjs/glob-parent > The ISC License > @@ -288,7 +288,7 @@ Repository: git://github.com/isaacs/inherits ## is-binary-path License: MIT By: Sindre Sorhus -Repository: git+https://github.com/sindresorhus/is-binary-path.git +Repository: sindresorhus/is-binary-path --------------------------------------- @@ -353,7 +353,7 @@ Repository: micromatch/is-glob ## is-number License: MIT By: Jon Schlinkert, Olsten Larck, Rouven Weßling -Repository: git+https://github.com/jonschlinkert/is-number.git +Repository: jonschlinkert/is-number > The MIT License (MIT) > @@ -668,7 +668,7 @@ Repository: sindresorhus/time-zone ## to-regex-range License: MIT By: Jon Schlinkert, Rouven Weßling -Repository: git+https://github.com/micromatch/to-regex-range.git +Repository: micromatch/to-regex-range > The MIT License (MIT) > diff --git a/src/watch/fileWatcher.ts b/src/watch/fileWatcher.ts new file mode 100644 index 00000000000..9dfd62225a8 --- /dev/null +++ b/src/watch/fileWatcher.ts @@ -0,0 +1,64 @@ +import chokidar, { FSWatcher } from 'chokidar'; +import { ChokidarOptions } from '../rollup/types'; +import { Task } from './watch'; + +export class FileWatcher { + private chokidarOptions: ChokidarOptions; + private task: Task; + private transformWatchers = new Map(); + private watcher: FSWatcher; + + constructor(task: Task, chokidarOptions: ChokidarOptions) { + this.chokidarOptions = chokidarOptions; + this.task = task; + this.watcher = this.createWatcher(null); + } + + close() { + this.watcher.close(); + for (const watcher of this.transformWatchers.values()) { + watcher.close(); + } + } + + unwatch(id: string) { + this.watcher.unwatch(id); + const transformWatcher = this.transformWatchers.get(id); + if (transformWatcher) { + this.transformWatchers.delete(id); + transformWatcher.close(); + } + } + + watch(id: string, isTransformDependency: boolean) { + if (isTransformDependency) { + const watcher = this.transformWatchers.get(id) || this.createWatcher(id); + watcher.add(id); + this.transformWatchers.set(id, watcher); + } else { + this.watcher.add(id); + } + } + + private createWatcher(transformWatcherId: string | null): FSWatcher { + const handleChange = transformWatcherId + ? () => { + // unwatching and watching fixes an issue with chokidar where on certain systems, + // a file that was unlinked and immediately recreated would create a change event + // but then no longer any further events + watcher.unwatch(transformWatcherId); + watcher.add(transformWatcherId); + this.task.invalidate(transformWatcherId, true); + } + : (id: string) => { + watcher.unwatch(id); + watcher.add(id); + this.task.invalidate(id, false); + }; + const watcher = chokidar + .watch([], this.chokidarOptions) + .on('change', handleChange) + .on('unlink', handleChange); + return watcher; + } +} diff --git a/src/watch/fileWatchers.ts b/src/watch/fileWatchers.ts deleted file mode 100644 index fbd451f93a8..00000000000 --- a/src/watch/fileWatchers.ts +++ /dev/null @@ -1,113 +0,0 @@ -import chokidar, { FSWatcher } from 'chokidar'; -import * as fs from 'fs'; -import { ChokidarOptions } from '../rollup/types'; -import { Task } from './watch'; - -const watchers = new Map>(); - -export function addTask( - id: string, - task: Task, - chokidarOptions: ChokidarOptions, - chokidarOptionsHash: string, - isTransformDependency: boolean -) { - if (!watchers.has(chokidarOptionsHash)) watchers.set(chokidarOptionsHash, new Map()); - const group = watchers.get(chokidarOptionsHash)!; - - const watcher = group.get(id) || new FileWatcher(id, chokidarOptions, group); - if (!watcher.fsWatcher) { - if (isTransformDependency) throw new Error(`Transform dependency ${id} does not exist.`); - } else { - watcher.addTask(task, isTransformDependency); - } -} - -export function deleteTask(id: string, target: Task, chokidarOptionsHash: string) { - const group = watchers.get(chokidarOptionsHash)!; - const watcher = group.get(id); - if (watcher) watcher.deleteTask(target, group); -} - -export default class FileWatcher { - fsWatcher?: FSWatcher; - - private id: string; - private tasks: Set; - private transformDependencyTasks: Set; - - constructor(id: string, chokidarOptions: ChokidarOptions, group: Map) { - this.id = id; - this.tasks = new Set(); - this.transformDependencyTasks = new Set(); - - let modifiedTime: number; - - try { - const stats = fs.statSync(id); - modifiedTime = +stats.mtime; - } catch (err) { - if (err.code === 'ENOENT') { - // can't watch files that don't exist (e.g. injected - // by plugins somehow) - return; - } - throw err; - } - - const handleWatchEvent = (event: string) => { - if (event === 'rename' || event === 'unlink') { - this.close(); - group.delete(id); - this.trigger(id); - return; - } else { - let stats: fs.Stats; - try { - stats = fs.statSync(id); - } catch (err) { - if (err.code === 'ENOENT') { - modifiedTime = -1; - this.trigger(id); - return; - } - throw err; - } - // debounce - if (+stats.mtime - modifiedTime > 15) this.trigger(id); - } - }; - - this.fsWatcher = chokidar.watch(id, chokidarOptions).on('all', handleWatchEvent); - - group.set(id, this); - } - - addTask(task: Task, isTransformDependency: boolean) { - if (isTransformDependency) this.transformDependencyTasks.add(task); - else this.tasks.add(task); - } - - close() { - if (this.fsWatcher) this.fsWatcher.close(); - } - - deleteTask(task: Task, group: Map) { - let deleted = this.tasks.delete(task); - deleted = this.transformDependencyTasks.delete(task) || deleted; - - if (deleted && this.tasks.size === 0 && this.transformDependencyTasks.size === 0) { - group.delete(this.id); - this.close(); - } - } - - trigger(id: string) { - for (const task of this.tasks) { - task.invalidate(id, false); - } - for (const task of this.transformDependencyTasks) { - task.invalidate(id, true); - } - } -} diff --git a/src/watch/watch.ts b/src/watch/watch.ts index 273238302a6..ba165701ef0 100644 --- a/src/watch/watch.ts +++ b/src/watch/watch.ts @@ -2,17 +2,15 @@ import path from 'path'; import createFilter from 'rollup-pluginutils/src/createFilter'; import rollup, { setWatcher } from '../rollup/rollup'; import { - ChokidarOptions, InputOptions, OutputOptions, RollupBuild, RollupCache, - RollupError, RollupWatcher, WatcherOptions } from '../rollup/types'; import mergeOptions, { GenericConfigObject } from '../utils/mergeOptions'; -import { addTask, deleteTask } from './fileWatchers'; +import { FileWatcher } from './fileWatcher'; const DELAY = 200; @@ -40,7 +38,6 @@ export class Watcher { for (const task of this.tasks) { task.close(); } - this.emitter.removeAllListeners(); } @@ -70,36 +67,33 @@ export class Watcher { }, DELAY); } - private run() { + private async run() { this.running = true; this.emit('event', { code: 'START' }); - let taskPromise = Promise.resolve(); - for (const task of this.tasks) taskPromise = taskPromise.then(() => task.run()); - return taskPromise - .then(() => { - this.running = false; - - this.emit('event', { - code: 'END' - }); - }) - .catch(error => { - this.running = false; - this.emit('event', { - code: 'ERROR', - error - }); - }) - .then(() => { - if (this.rerun) { - this.rerun = false; - this.invalidate(); - } + try { + for (const task of this.tasks) { + await task.run(); + } + this.running = false; + this.emit('event', { + code: 'END' }); + } catch (error) { + this.running = false; + this.emit('event', { + code: 'ERROR', + error + }); + } + + if (this.rerun) { + this.rerun = false; + this.invalidate(); + } } } @@ -107,9 +101,8 @@ export class Task { cache: RollupCache = { modules: [] }; watchFiles: string[] = []; - private chokidarOptions: ChokidarOptions; - private chokidarOptionsHash: string; private closed: boolean; + private fileWatcher: FileWatcher; private filter: (id: string) => boolean; private inputOptions: InputOptions; private invalidated = true; @@ -120,7 +113,6 @@ export class Task { constructor(watcher: Watcher, config: GenericConfigObject) { this.watcher = watcher; - this.closed = false; this.watched = new Set(); @@ -128,7 +120,6 @@ export class Task { config }); this.inputOptions = inputOptions; - this.outputs = outputOptions; this.outputFiles = this.outputs.map(output => { if (output.file || output.dir) return path.resolve(output.file || output.dir!); @@ -136,24 +127,20 @@ export class Task { }); const watchOptions: WatcherOptions = inputOptions.watch || {}; - this.chokidarOptions = { + this.filter = createFilter(watchOptions.include, watchOptions.exclude); + this.fileWatcher = new FileWatcher(this, { ...watchOptions.chokidar, disableGlobbing: true, ignoreInitial: true - }; - this.chokidarOptionsHash = JSON.stringify(this.chokidarOptions); - - this.filter = createFilter(watchOptions.include, watchOptions.exclude); + }); } close() { this.closed = true; - for (const id of this.watched) { - deleteTask(id, this, this.chokidarOptionsHash); - } + this.fileWatcher.close(); } - invalidate(id: string, isTransformDependency: boolean) { + invalidate(id: string, isTransformDependency: boolean | undefined) { this.invalidated = true; if (isTransformDependency) { for (const module of this.cache.modules) { @@ -165,7 +152,7 @@ export class Task { this.watcher.invalidate(id); } - run() { + async run() { if (!this.invalidated) return; this.invalidated = false; @@ -182,32 +169,35 @@ export class Task { output: this.outputFiles }); + // TODO Lukas improve setWatcher(this.watcher.emitter); - return rollup(options) - .then(result => { - if (this.closed) return undefined as any; - this.updateWatchedFiles(result); - return Promise.all(this.outputs.map(output => result.write(output))).then(() => result); - }) - .then((result: RollupBuild) => { - this.watcher.emit('event', { - code: 'BUNDLE_END', - duration: Date.now() - start, - input: this.inputOptions.input, - output: this.outputFiles, - result - }); - }) - .catch((error: RollupError) => { - if (this.closed) return; - - if (Array.isArray(error.watchFiles)) { - for (const id of error.watchFiles) { - this.watchFile(id); - } - } - throw error; + + try { + const result = await rollup(options); + if (this.closed) { + return; + } + this.updateWatchedFiles(result); + await Promise.all(this.outputs.map(output => result.write(output))); + this.watcher.emit('event', { + code: 'BUNDLE_END', + duration: Date.now() - start, + input: this.inputOptions.input, + output: this.outputFiles, + result }); + } catch (error) { + if (this.closed) { + return; + } + + if (Array.isArray(error.watchFiles)) { + for (const id of error.watchFiles) { + this.watchFile(id); + } + } + throw error; + } } private updateWatchedFiles(result: RollupBuild) { @@ -224,7 +214,9 @@ export class Task { } } for (const id of previouslyWatched) { - if (!this.watched.has(id)) deleteTask(id, this, this.chokidarOptionsHash); + if (!this.watched.has(id)) { + this.fileWatcher.unwatch(id); + } } } @@ -238,6 +230,6 @@ export class Task { // this is necessary to ensure that any 'renamed' files // continue to be watched following an error - addTask(id, this, this.chokidarOptions, this.chokidarOptionsHash, isTransformDependency); + this.fileWatcher.watch(id, isTransformDependency); } } diff --git a/test/hooks/index.js b/test/hooks/index.js index 719b6a128ed..904775bef7f 100644 --- a/test/hooks/index.js +++ b/test/hooks/index.js @@ -916,20 +916,23 @@ describe('hooks', () => { if (event.code === 'BUNDLE_END') resolve(); else if (event.code === 'ERROR') reject(event.error); }); - }).catch(err => { - assert.strictEqual( - err.message, - 'You must specify "output.file" or "output.dir" for the build.' - ); - assert.strictEqual(warnings.length, 1); - const warning = warnings[0]; - assert.strictEqual(warning.code, 'PLUGIN_WARNING'); - assert.strictEqual(warning.pluginCode, 'PLUGIN_WATCHER_DEPRECATED'); - assert.strictEqual( - warning.message, - 'this.watcher usage is deprecated in plugins. Use the watchChange plugin hook and this.addWatchFile() instead.' - ); - }); + }) + .catch(err => { + watcher.close(); + assert.strictEqual( + err.message, + 'You must specify "output.file" or "output.dir" for the build.' + ); + assert.strictEqual(warnings.length, 1); + const warning = warnings[0]; + assert.strictEqual(warning.code, 'PLUGIN_WARNING'); + assert.strictEqual(warning.pluginCode, 'PLUGIN_WATCHER_DEPRECATED'); + assert.strictEqual( + warning.message, + 'this.watcher usage is deprecated in plugins. Use the watchChange plugin hook and this.addWatchFile() instead.' + ); + }) + .then(() => watcher.close()); }); it('Throws when not specifying "file" or "dir"', () => { @@ -945,12 +948,15 @@ describe('hooks', () => { if (event.code === 'BUNDLE_END') reject(new Error('Expected an error')); else if (event.code === 'ERROR') reject(event.error); }); - }).catch(err => { - assert.strictEqual( - err.message, - 'You must specify "output.file" or "output.dir" for the build.' - ); - }); + }) + .catch(err => { + watcher.close(); + assert.strictEqual( + err.message, + 'You must specify "output.file" or "output.dir" for the build.' + ); + }) + .then(() => watcher.close()); }); it('Throws when using the "file"" option for multiple chunks', () => { @@ -967,12 +973,15 @@ describe('hooks', () => { if (event.code === 'BUNDLE_END') reject(new Error('Expected an error')); else if (event.code === 'ERROR') reject(event.error); }); - }).catch(err => { - assert.strictEqual( - err.message, - 'You must set "output.dir" instead of "output.file" when generating multiple chunks.' - ); - }); + }) + .catch(err => { + watcher.close(); + assert.strictEqual( + err.message, + 'You must set "output.dir" instead of "output.file" when generating multiple chunks.' + ); + }) + .then(() => watcher.close()); }); it('Throws when using the "sourcemapFile" option for multiple chunks', () => { @@ -990,12 +999,15 @@ describe('hooks', () => { if (event.code === 'BUNDLE_END') reject(new Error('Expected an error')); else if (event.code === 'ERROR') reject(event.error); }); - }).catch(err => { - assert.strictEqual( - err.message, - '"output.sourcemapFile" is only supported for single-file builds.' - ); - }); + }) + .catch(err => { + watcher.close(); + assert.strictEqual( + err.message, + '"output.sourcemapFile" is only supported for single-file builds.' + ); + }) + .then(() => watcher.close()); }); it('assigns chunk IDs before creating outputBundle chunks', () => { diff --git a/test/watch/index.js b/test/watch/index.js index 61e53ad445e..c8105a996e4 100644 --- a/test/watch/index.js +++ b/test/watch/index.js @@ -12,11 +12,20 @@ function wait(ms) { } describe('rollup.watch', () => { + let watcher; + beforeEach(() => { process.chdir(cwd); return sander.rimraf('test/_tmp'); }); + afterEach(() => { + if (watcher) { + watcher.close(); + watcher = null; + } + }); + function run(file) { const resolved = require.resolve(file); delete require.cache[resolved]; @@ -57,13 +66,26 @@ describe('rollup.watch', () => { }); } - it('watches a file', () => { + it('watches a file and triggers reruns if necessary', () => { + let triggerRestart = false; + return sander .copydir('test/watch/samples/basic') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', + plugins: { + transform(code) { + if (triggerRestart) { + triggerRestart = false; + return wait(100) + .then(() => sander.writeFileSync('test/_tmp/input/main.js', 'export default 44;')) + .then(() => wait(100)) + .then(() => code); + } + } + }, output: { file: 'test/_tmp/output/bundle.js', format: 'cjs' @@ -77,14 +99,19 @@ describe('rollup.watch', () => { 'END', () => { assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + triggerRestart = true; sander.writeFileSync('test/_tmp/input/main.js', 'export default 43;'); }, 'START', 'BUNDLE_START', 'BUNDLE_END', 'END', + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + assert.strictEqual(run('../_tmp/output/bundle.js'), 44); } ]); }); @@ -95,7 +122,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/basic') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', plugins: { resolveId(id) { @@ -144,7 +171,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/basic') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -203,7 +230,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/code-splitting') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: ['test/_tmp/input/main1.js', 'test/_tmp/input/main2.js'], output: { dir: 'test/_tmp/output', @@ -238,7 +265,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/code-splitting') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: { _main_1: 'test/_tmp/input/main1.js', 'subfolder/_main_2': 'test/_tmp/input/main2.js' @@ -276,7 +303,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/basic') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -315,7 +342,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/error') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -348,7 +375,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/basic') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', plugins: { transform() { @@ -382,12 +409,12 @@ describe('rollup.watch', () => { }); }); - it('recovers from an error even when erroring file was "renamed" (#38)', () => { + it('recovers from an error even when erroring entry was "renamed" (#38)', () => { return sander .copydir('test/watch/samples/basic') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -423,32 +450,73 @@ describe('rollup.watch', () => { }); }); + it('recovers from an error even when erroring dependency was "renamed" (#38)', () => { + return sander + .copydir('test/watch/samples/dependency') + .to('test/_tmp/input') + .then(() => { + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs' + } + }); + + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + sander.unlinkSync('test/_tmp/input/dep.js'); + sander.writeFileSync('test/_tmp/input/dep.js', 'export nope;'); + }, + 'START', + 'BUNDLE_START', + 'ERROR', + () => { + sander.unlinkSync('test/_tmp/input/dep.js'); + sander.writeFileSync('test/_tmp/input/dep.js', 'export const value = 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 44); + } + ]); + }); + }); + it('handles closing the watcher during a build', () => { return sander .copydir('test/watch/samples/basic') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', + plugins: { + load() { + watcher.close(); + } + }, output: { file: 'test/_tmp/output/bundle.js', format: 'cjs' } }); + const events = []; + watcher.on('event', event => events.push(event.code)); - setTimeout(() => watcher.close(), 50); return sequence(watcher, [ 'START', 'BUNDLE_START', - 'BUNDLE_END', () => { - sander.writeFileSync('test/_tmp/input/main.js', 'export default 43;'); - let unexpectedEvent = false; - watcher.once('event', event => { - unexpectedEvent = event; - }); - sander.writeFileSync('test/_tmp/input/dep.js', '= invalid'); - return wait(400).then(() => assert.strictEqual(unexpectedEvent, false)); + sander.writeFileSync('test/_tmp/input/main.js', 'export default 44;'); + return wait(400).then(() => assert.deepStrictEqual(events, ['START', 'BUNDLE_START'])); } ]); }); @@ -459,27 +527,27 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/error') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', + plugins: { + load() { + watcher.close(); + } + }, output: { file: 'test/_tmp/output/bundle.js', format: 'cjs' } }); + const events = []; + watcher.on('event', event => events.push(event.code)); - setTimeout(() => watcher.close(), 50); return sequence(watcher, [ 'START', 'BUNDLE_START', - 'ERROR', () => { - sander.writeFileSync('test/_tmp/input/main.js', 'export default 43;'); - let unexpectedEvent = false; - watcher.once('event', event => { - unexpectedEvent = event; - }); - sander.writeFileSync('test/_tmp/input/dep.js', '= invalid'); - return wait(400).then(() => assert.strictEqual(unexpectedEvent, false)); + sander.writeFileSync('test/_tmp/input/main.js', 'export default 44;'); + return wait(400).then(() => assert.deepStrictEqual(events, ['START', 'BUNDLE_START'])); } ]); }); @@ -490,7 +558,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/dependency') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -529,7 +597,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/basic') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -569,7 +637,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/ignored') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -623,7 +691,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/ignored') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -677,7 +745,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/multiple') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch([ + watcher = rollup.watch([ { input: 'test/_tmp/input/main1.js', output: { @@ -723,7 +791,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/globals') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -755,7 +823,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/non-glob') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -791,7 +859,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/hashing') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: ['test/_tmp/input/main-static.js', 'test/_tmp/input/main-dynamic.js'], output: { dir: 'test/_tmp/output', @@ -863,7 +931,7 @@ describe('rollup.watch', () => { .to('test/_tmp/input') .then(() => { for (const file of watchFiles) sander.writeFileSync(file, 'initial'); - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -915,7 +983,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/watch-files') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -957,7 +1025,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/watch-files') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -1013,7 +1081,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/watch-files') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -1055,7 +1123,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/watch-files') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -1095,9 +1163,10 @@ describe('rollup.watch', () => { return sander .copydir('test/watch/samples/watch-files') .to('test/_tmp/input') + .then(() => wait(100)) .then(() => { sander.writeFileSync('test/_tmp/input/alsoWatched', 'initial'); - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -1146,7 +1215,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/basic') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -1196,7 +1265,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/watch-files') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -1235,48 +1304,12 @@ describe('rollup.watch', () => { }); }); - it("throws if transform dependency doesn't exist", () => { - return sander - .copydir('test/watch/samples/watch-files') - .to('test/_tmp/input') - .then(() => { - const watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs' - }, - plugins: { - transform() { - return { - code: `export default "${sander - .readFileSync('test/_tmp/input/watched') - .toString() - .trim()}"`, - dependencies: ['./doesnotexist'] - }; - } - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'ERROR', - event => { - assert.ok(event.error.message.startsWith('Transform dependency')); - assert.ok(event.error.message.endsWith('does not exist.')); - } - ]); - }); - }); - it('watches and rebuilds transform dependencies that are modules', () => { return sander .copydir('test/watch/samples/watch-files') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -1320,7 +1353,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/watch-files') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -1362,7 +1395,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/watch-files') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -1411,7 +1444,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/watch-files') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -1461,7 +1494,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/watch-files') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { file: 'test/_tmp/output/bundle.js', @@ -1512,7 +1545,7 @@ describe('rollup.watch', () => { .copydir('test/watch/samples/watch-files-multiple') .to('test/_tmp/input') .then(() => { - const watcher = rollup.watch({ + watcher = rollup.watch({ input: 'test/_tmp/input/index.js', output: { file: 'test/_tmp/output/bundle.js',