diff --git a/test/watch/index.js b/test/watch/index.js index bf873cd4dab..537126d98e8 100644 --- a/test/watch/index.js +++ b/test/watch/index.js @@ -8,6 +8,7 @@ const { writeFileSync } = require('fs'); const { resolve } = require('path'); +const process = require('process'); const { copy, removeSync } = require('fs-extra'); const sander = require('sander'); const rollup = require('../../dist/rollup'); @@ -41,8 +42,8 @@ describe('rollup.watch', () => { return require(resolved); } - function sequence(watcher, events, timeout = 300) { - return new Promise((fulfil, reject) => { + async function sequence(watcher, events, timeout = 300) { + await new Promise((fulfil, reject) => { function go(event) { const next = events.shift(); @@ -50,18 +51,17 @@ describe('rollup.watch', () => { watcher.close(); fulfil(); } else if (typeof next === 'string') { - watcher.once('event', event => { - if (event.code !== next) { + watcher.once('event', event_1 => { + if (event_1.code !== next) { watcher.close(); - if (event.code === 'ERROR') console.log(event.error); - reject(new Error(`Expected ${next} event, got ${event.code}`)); + if (event_1.code === 'ERROR') console.log(event_1.error); + reject(new Error(`Expected ${next} event, got ${event_1.code}`)); } else { - go(event); + go(event_1); } }); } else { - Promise.resolve() - .then(() => wait(timeout)) // gah, this appears to be necessary to fix random errors + wait(timeout) // gah, this appears to be necessary to fix random errors .then(() => next(event)) .then(go) .catch(error => { @@ -72,7 +72,8 @@ describe('rollup.watch', () => { } go(); - }).then(() => wait(100)); + }); + await wait(100); } function getTimeDiffInMs(previous) { @@ -80,103 +81,99 @@ describe('rollup.watch', () => { return seconds * 1e3 + nanoseconds / 1e6; } - it('watches a file and triggers reruns if necessary', () => { + it('watches a file and triggers reruns if necessary', async () => { let triggerRestart = false; - return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - plugins: { - options(options) { - assert.strictEqual(this.meta.watchMode, true, 'watchMode in options'); - }, - transform(code) { - assert.strictEqual(this.meta.watchMode, true, 'watchMode in transform'); - if (triggerRestart) { - triggerRestart = false; - return wait(100) - .then(() => writeFileSync('test/_tmp/input/main.js', 'export default 44;')) - .then(() => wait(100)) - .then(() => code); - } - } - }, - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - triggerRestart = true; - writeFileSync('test/_tmp/input/main.js', 'export default 43;'); + await copy('test/watch/samples/basic', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + plugins: { + options() { + assert.strictEqual(this.meta.watchMode, true, 'watchMode in options'); }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 44); + async transform(code) { + assert.strictEqual(this.meta.watchMode, true, 'watchMode in transform'); + if (triggerRestart) { + triggerRestart = false; + await wait(100); + writeFileSync('test/_tmp/input/main.js', 'export default 44;'); + await wait(100); + return code; + } } - ]); + }, + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + triggerRestart = true; + 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'), 44); + } + ]); }); - it('does not fail for virtual files', () => { - return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - plugins: { - resolveId(id) { - if (id === 'virtual') { - return id; - } - }, - load(id) { - if (id === 'virtual') { - return `export const value = 42;`; - } + it('does not fail for virtual files', async () => { + await copy('test/watch/samples/basic', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + plugins: { + resolveId(id) { + if (id === 'virtual') { + return id; } }, - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - writeFileSync( - 'test/_tmp/input/main.js', - "import {value} from 'virtual';\nexport default value + 1;" - ); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + load(id_1) { + if (id_1 === 'virtual') { + return `export const value = 42;`; + } } - ]); + }, + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + writeFileSync( + 'test/_tmp/input/main.js', + "import {value} from 'virtual';\nexport default value + 1;" + ); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + } + ]); }); it('passes file events to the watchChange plugin hook once for each change', async () => { @@ -385,750 +382,710 @@ describe('rollup.watch', () => { ]); }).timeout(20000); - it('calls closeWatcher plugin hook', () => { + it('calls closeWatcher plugin hook', async () => { let calls = 0; let ctx1; let ctx2; - return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' + await copy('test/watch/samples/basic', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: [ + { + buildStart() { + ctx1 = this; + }, + closeWatcher() { + assert.strictEqual(ctx1, this); + calls++; + } }, - plugins: [ - { - buildStart() { - ctx1 = this; - }, - closeWatcher() { - assert.strictEqual(ctx1, this); - calls++; - } + { + buildStart() { + ctx2 = this; }, - { - buildStart() { - ctx2 = this; - }, - closeWatcher() { - assert.strictEqual(ctx2, this); - calls++; - } + closeWatcher() { + assert.strictEqual(ctx2, this); + calls++; } - ] - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - assert.ok(ctx1); - assert.ok(ctx2); - watcher.once('close', () => { - assert.strictEqual(calls, 2); - }); - watcher.close(); } - ]); + ] }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + assert.ok(ctx1); + assert.ok(ctx2); + watcher.once('close', () => { + assert.strictEqual(calls, 2); + }); + watcher.close(); + } + ]); }); - it('watches a file in code-splitting mode', () => { - return copy('test/watch/samples/code-splitting', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: ['test/_tmp/input/main1.js', 'test/_tmp/input/main2.js'], - output: { - dir: 'test/_tmp/output', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/main1.js'), 21); - assert.strictEqual(run('../_tmp/output/main2.js'), 42); - writeFileSync('test/_tmp/input/shared.js', 'export const value = 22;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/main1.js'), 22); - assert.strictEqual(run('../_tmp/output/main2.js'), 44); - } - ]); + it('watches a file in code-splitting mode', async () => { + await copy('test/watch/samples/code-splitting', 'test/_tmp/input'); + watcher = rollup.watch({ + input: ['test/_tmp/input/main1.js', 'test/_tmp/input/main2.js'], + output: { + dir: 'test/_tmp/output', + format: 'cjs', + exports: 'auto' + } }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/main1.js'), 21); + assert.strictEqual(run('../_tmp/output/main2.js'), 42); + writeFileSync('test/_tmp/input/shared.js', 'export const value = 22;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/main1.js'), 22); + assert.strictEqual(run('../_tmp/output/main2.js'), 44); + } + ]); }); - it('watches a file in code-splitting mode with an input object', () => { - return copy('test/watch/samples/code-splitting', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: { - _main_1: 'test/_tmp/input/main1.js', - 'subfolder/_main_2': 'test/_tmp/input/main2.js' - }, - output: { - dir: 'test/_tmp/output', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/_main_1.js'), 21); - assert.strictEqual(run('../_tmp/output/subfolder/_main_2.js'), 42); - writeFileSync('test/_tmp/input/shared.js', 'export const value = 22;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/_main_1.js'), 22); - assert.strictEqual(run('../_tmp/output/subfolder/_main_2.js'), 44); - } - ]); + it('watches a file in code-splitting mode with an input object', async () => { + await copy('test/watch/samples/code-splitting', 'test/_tmp/input'); + watcher = rollup.watch({ + input: { + _main_1: 'test/_tmp/input/main1.js', + 'subfolder/_main_2': 'test/_tmp/input/main2.js' + }, + output: { + dir: 'test/_tmp/output', + format: 'cjs', + exports: 'auto' + } }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/_main_1.js'), 21); + assert.strictEqual(run('../_tmp/output/subfolder/_main_2.js'), 42); + writeFileSync('test/_tmp/input/shared.js', 'export const value = 22;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/_main_1.js'), 22); + assert.strictEqual(run('../_tmp/output/subfolder/_main_2.js'), 44); + } + ]); }); - it('recovers from an error', () => { - return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - writeFileSync('test/_tmp/input/main.js', 'export nope;'); - }, - 'START', - 'BUNDLE_START', - 'ERROR', - () => { - writeFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); - } - ]); + it('recovers from an error', async () => { + await copy('test/watch/samples/basic', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + writeFileSync('test/_tmp/input/main.js', 'export nope;'); + }, + 'START', + 'BUNDLE_START', + 'ERROR', + () => { + writeFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + } + ]); }); - it('recovers from an error on initial build', () => { - return copy('test/watch/samples/error', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'ERROR', - () => { - assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); - writeFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); - } - ]); + it('recovers from an error on initial build', async () => { + await copy('test/watch/samples/error', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'ERROR', + () => { + assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); + writeFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + } + ]); }); - it('recovers from a plugin error on initial build', () => { + it('recovers from a plugin error on initial build', async () => { let count = 0; - return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - plugins: { - transform() { - if (count++ === 0) { - this.error('The first run failed, try again.'); - } + await copy('test/watch/samples/basic', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + plugins: { + transform() { + if (count++ === 0) { + this.error('The first run failed, try again.'); } - }, - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'ERROR', - () => { - assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); - writeFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); } - ]); + }, + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'ERROR', + () => { + assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); + writeFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + } + ]); }); - it('recovers from an error even when erroring entry was "renamed" (#38)', () => { - return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); + it('recovers from an error even when erroring entry was "renamed" (#38)', async () => { + await copy('test/watch/samples/basic', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } + }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + unlinkSync('test/_tmp/input/main.js'); + writeFileSync('test/_tmp/input/main.js', 'export nope;'); + }, + 'START', + 'BUNDLE_START', + 'ERROR', + () => { + unlinkSync('test/_tmp/input/main.js'); + writeFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + } + ]); + }); - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - unlinkSync('test/_tmp/input/main.js'); - writeFileSync('test/_tmp/input/main.js', 'export nope;'); - }, - 'START', - 'BUNDLE_START', - 'ERROR', - () => { - unlinkSync('test/_tmp/input/main.js'); - writeFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); - } - ]); + it('recovers from an error even when erroring dependency was "renamed" (#38)', async () => { + await copy('test/watch/samples/dependency', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + unlinkSync('test/_tmp/input/dep.js'); + writeFileSync('test/_tmp/input/dep.js', 'export nope;'); + }, + 'START', + 'BUNDLE_START', + 'ERROR', + () => { + unlinkSync('test/_tmp/input/dep.js'); + 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('recovers from an error even when erroring dependency was "renamed" (#38)', () => { - return copy('test/watch/samples/dependency', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' + it('handles closing the watcher during a build', async () => { + await copy('test/watch/samples/basic', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + plugins: { + load() { + watcher.close(); } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); - unlinkSync('test/_tmp/input/dep.js'); - writeFileSync('test/_tmp/input/dep.js', 'export nope;'); - }, - 'START', - 'BUNDLE_START', - 'ERROR', - () => { - unlinkSync('test/_tmp/input/dep.js'); - 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 copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - plugins: { - load() { - watcher.close(); - } - }, - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - const events = []; - watcher.on('event', event => events.push(event.code)); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - () => { - writeFileSync('test/_tmp/input/main.js', 'export default 44;'); - return wait(400).then(() => assert.deepStrictEqual(events, ['START', 'BUNDLE_START'])); - } - ]); + }, + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + const events = []; + watcher.on('event', event_1 => events.push(event_1.code)); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + () => { + writeFileSync('test/_tmp/input/main.js', 'export default 44;'); + return wait(400).then(() => assert.deepStrictEqual(events, ['START', 'BUNDLE_START'])); + } + ]); }); - it('handles closing the watcher during a build even if an error occurred', () => { - return copy('test/watch/samples/error', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - plugins: { - load() { - watcher.close(); - } - }, - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - const events = []; - watcher.on('event', event => events.push(event.code)); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - () => { - writeFileSync('test/_tmp/input/main.js', 'export default 44;'); - return wait(400).then(() => assert.deepStrictEqual(events, ['START', 'BUNDLE_START'])); + it('handles closing the watcher during a build even if an error occurred', async () => { + await copy('test/watch/samples/error', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + plugins: { + load() { + watcher.close(); } - ]); + }, + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + const events = []; + watcher.on('event', event_1 => events.push(event_1.code)); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + () => { + writeFileSync('test/_tmp/input/main.js', 'export default 44;'); + return wait(400).then(() => assert.deepStrictEqual(events, ['START', 'BUNDLE_START'])); + } + ]); }); - it('stops watching files that are no longer part of the graph', () => { - return copy('test/watch/samples/dependency', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); - writeFileSync('test/_tmp/input/main.js', 'export default 42;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - let unexpectedEvent = false; - watcher.once('event', event => { - unexpectedEvent = event; - }); - writeFileSync('test/_tmp/input/dep.js', '= invalid'); - return wait(400).then(() => assert.strictEqual(unexpectedEvent, false)); - } - ]); + it('stops watching files that are no longer part of the graph', async () => { + await copy('test/watch/samples/dependency', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + writeFileSync('test/_tmp/input/main.js', 'export default 42;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + let unexpectedEvent = false; + watcher.once('event', event => { + unexpectedEvent = event; + }); + writeFileSync('test/_tmp/input/dep.js', '= invalid'); + return wait(400).then(() => assert.strictEqual(unexpectedEvent, false)); + } + ]); }); - it('refuses to watch the output file (#15)', () => { - return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - writeFileSync('test/_tmp/input/main.js', `import '../output/bundle.js'`); - }, - 'START', - 'BUNDLE_START', - 'ERROR', - event => { - assert.strictEqual(event.error.message, 'Cannot import the generated bundle'); - writeFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); - } - ]); + it('refuses to watch the output file (#15)', async () => { + await copy('test/watch/samples/basic', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + writeFileSync('test/_tmp/input/main.js', `import '../output/bundle.js'`); + }, + 'START', + 'BUNDLE_START', + 'ERROR', + event => { + assert.strictEqual(event.error.message, 'Cannot import the generated bundle'); + writeFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + } + ]); }); - it('ignores files that are not specified in options.watch.include, if given', () => { - return copy('test/watch/samples/ignored', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - watch: { - include: ['test/_tmp/input/+(main|foo).js'] - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { - foo: 'foo-1', - bar: 'bar-1' - }); - writeFileSync('test/_tmp/input/foo.js', `export default 'foo-2';`); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { - foo: 'foo-2', - bar: 'bar-1' - }); - let unexpectedEvent = false; - watcher.once('event', event => { - unexpectedEvent = event; - }); - writeFileSync('test/_tmp/input/bar.js', "export default 'bar-2';"); - return wait(400).then(() => { - assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { - foo: 'foo-2', - bar: 'bar-1' - }); - assert.strictEqual(unexpectedEvent, false); - }); - } - ]); + it('ignores files that are not specified in options.watch.include, if given', async () => { + await copy('test/watch/samples/ignored', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + watch: { + include: ['test/_tmp/input/+(main|foo).js'] + } }); - }); - - it('ignores files that are specified in options.watch.exclude, if given', () => { - return copy('test/watch/samples/ignored', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - watch: { - exclude: ['test/_tmp/input/bar.js'] - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { - foo: 'foo-1', - bar: 'bar-1' - }); - writeFileSync('test/_tmp/input/foo.js', `export default 'foo-2';`); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { + foo: 'foo-1', + bar: 'bar-1' + }); + writeFileSync('test/_tmp/input/foo.js', `export default 'foo-2';`); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { + foo: 'foo-2', + bar: 'bar-1' + }); + let unexpectedEvent = false; + watcher.once('event', event => { + unexpectedEvent = event; + }); + writeFileSync('test/_tmp/input/bar.js', "export default 'bar-2';"); + return wait(400).then(() => { assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { foo: 'foo-2', bar: 'bar-1' - }); - let unexpectedEvent = false; - watcher.once('event', event => { - unexpectedEvent = event; - }); - writeFileSync('test/_tmp/input/bar.js', "export default 'bar-2';"); - return wait(400).then(() => { - assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { - foo: 'foo-2', - bar: 'bar-1' - }); - assert.strictEqual(unexpectedEvent, false); - }); - } - ]); - }); - }); - - it('only rebuilds the appropriate configs', () => { - return copy('test/watch/samples/multiple', 'test/_tmp/input') - .then(() => wait(100)) - .then(() => { - watcher = rollup.watch([ - { - input: 'test/_tmp/input/main1.js', - output: { - file: 'test/_tmp/output/bundle1.js', - format: 'cjs', - exports: 'auto' - } - }, - { - input: 'test/_tmp/input/main2.js', - output: { - file: 'test/_tmp/output/bundle2.js', - format: 'cjs', - exports: 'auto' - } - } - ]); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.deepStrictEqual(run('../_tmp/output/bundle1.js'), 42); - assert.deepStrictEqual(run('../_tmp/output/bundle2.js'), 43); - writeFileSync('test/_tmp/input/main2.js', 'export default 44'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.deepStrictEqual(run('../_tmp/output/bundle1.js'), 42); - assert.deepStrictEqual(run('../_tmp/output/bundle2.js'), 44); - } - ]); - }); - }); - - it('allows watching only some configs', () => { - return copy('test/watch/samples/multiple', 'test/_tmp/input') - .then(() => wait(100)) - .then(() => { - watcher = rollup.watch([ - { - input: 'test/_tmp/input/main1.js', - watch: false, - output: { - file: 'test/_tmp/output/bundle1.js', - format: 'cjs', - exports: 'auto' - } - }, - { - input: 'test/_tmp/input/main2.js', - output: { - file: 'test/_tmp/output/bundle2.js', - format: 'cjs', - exports: 'auto' - } - } - ]); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(existsSync(resolve(__dirname, '../_tmp/output/bundle1.js')), false); - assert.strictEqual(existsSync(resolve(__dirname, '../_tmp/output/bundle2.js')), true); - assert.deepStrictEqual(run('../_tmp/output/bundle2.js'), 43); - } - ]); - }); + }); + assert.strictEqual(unexpectedEvent, false); + }); + } + ]); }); - it('respects output.globals', () => { - return copy('test/watch/samples/globals', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'iife', - globals: { - jquery: 'jQuery' - } - }, - external: ['jquery'] - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - const generated = readFileSync('test/_tmp/output/bundle.js', 'utf8'); - assert.ok(/jQuery/.test(generated)); - } - ]); + it('ignores files that are specified in options.watch.exclude, if given', async () => { + await copy('test/watch/samples/ignored', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + watch: { + exclude: ['test/_tmp/input/bar.js'] + } }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { + foo: 'foo-1', + bar: 'bar-1' + }); + writeFileSync('test/_tmp/input/foo.js', `export default 'foo-2';`); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { + foo: 'foo-2', + bar: 'bar-1' + }); + let unexpectedEvent = false; + watcher.once('event', event => { + unexpectedEvent = event; + }); + writeFileSync('test/_tmp/input/bar.js', "export default 'bar-2';"); + return wait(400).then(() => { + assert.deepStrictEqual(run('../_tmp/output/bundle.js'), { + foo: 'foo-2', + bar: 'bar-1' + }); + assert.strictEqual(unexpectedEvent, false); + }); + } + ]); }); - it('treats filenames literally, not as globs', () => { - return copy('test/watch/samples/non-glob', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', + it('only rebuilds the appropriate configs', async () => { + await copy('test/watch/samples/multiple', 'test/_tmp/input'); + await wait(100); + watcher = rollup.watch([ + { + input: 'test/_tmp/input/main1.js', output: { - file: 'test/_tmp/output/bundle.js', + file: 'test/_tmp/output/bundle1.js', format: 'cjs', exports: 'auto' } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - writeFileSync('test/_tmp/input/[foo]/bar.js', `export const bar = 43;`); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + }, + { + input: 'test/_tmp/input/main2.js', + output: { + file: 'test/_tmp/output/bundle2.js', + format: 'cjs', + exports: 'auto' } - ]); - }); + } + ]); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.deepStrictEqual(run('../_tmp/output/bundle1.js'), 42); + assert.deepStrictEqual(run('../_tmp/output/bundle2.js'), 43); + writeFileSync('test/_tmp/input/main2.js', 'export default 44'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.deepStrictEqual(run('../_tmp/output/bundle1.js'), 42); + assert.deepStrictEqual(run('../_tmp/output/bundle2.js'), 44); + } + ]); }); - it('updates the right hashes on dependency changes', () => { - let dynamicName; - let staticName; - let chunkName; - return copy('test/watch/samples/hashing', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: ['test/_tmp/input/main-static.js', 'test/_tmp/input/main-dynamic.js'], + it('allows watching only some configs', async () => { + await copy('test/watch/samples/multiple', 'test/_tmp/input'); + await wait(100); + watcher = rollup.watch([ + { + input: 'test/_tmp/input/main1.js', + watch: false, output: { - dir: 'test/_tmp/output', + file: 'test/_tmp/output/bundle1.js', format: 'cjs', - exports: 'auto', - entryFileNames: '[name].[hash].js', - chunkFileNames: '[name].[hash].js' + exports: 'auto' } - }); + }, + { + input: 'test/_tmp/input/main2.js', + output: { + file: 'test/_tmp/output/bundle2.js', + format: 'cjs', + exports: 'auto' + } + } + ]); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(existsSync(resolve(__dirname, '../_tmp/output/bundle1.js')), false); + assert.strictEqual(existsSync(resolve(__dirname, '../_tmp/output/bundle2.js')), true); + assert.deepStrictEqual(run('../_tmp/output/bundle2.js'), 43); + } + ]); + }); - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - [dynamicName, staticName, chunkName] = readdirSync('test/_tmp/output').sort(); - removeSync('test/_tmp/output'); + it('respects output.globals', async () => { + await copy('test/watch/samples/globals', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'iife', + globals: { + jquery: 'jQuery' + } + }, + external: ['jquery'] + }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + const generated = readFileSync('test/_tmp/output/bundle.js', 'utf8'); + assert.ok(/jQuery/.test(generated)); + } + ]); + }); - // this should only update the hash of that particular entry point - writeFileSync( - 'test/_tmp/input/main-static.js', - "import {value} from './shared';\nexport default 2 * value;" - ); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - const [newDynamicName, newStaticName, newChunkName] = - readdirSync('test/_tmp/output').sort(); - removeSync('test/_tmp/output'); - assert.notEqual(newStaticName, staticName); - assert.strictEqual(newDynamicName, dynamicName); - assert.strictEqual(newChunkName, chunkName); - staticName = newStaticName; + it('treats filenames literally, not as globs', async () => { + await copy('test/watch/samples/non-glob', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + } + }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + writeFileSync('test/_tmp/input/[foo]/bar.js', `export const bar = 43;`); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 43); + } + ]); + }); - // this should update all hashes - writeFileSync('test/_tmp/input/shared.js', 'export const value = 42;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - const [newDynamicName, newStaticName, newChunkName] = - readdirSync('test/_tmp/output').sort(); - assert.notEqual(newStaticName, staticName); - assert.notEqual(newDynamicName, dynamicName); - assert.notEqual(newChunkName, chunkName); - } - ]); + it('updates the right hashes on dependency changes', async () => { + let dynamicName; + let staticName; + let chunkName; + await copy('test/watch/samples/hashing', 'test/_tmp/input'); + watcher = rollup.watch({ + input: ['test/_tmp/input/main-static.js', 'test/_tmp/input/main-dynamic.js'], + output: { + dir: 'test/_tmp/output', + format: 'cjs', + exports: 'auto', + entryFileNames: '[name].[hash].js', + chunkFileNames: '[name].[hash].js' + } }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + [dynamicName, staticName, chunkName] = readdirSync('test/_tmp/output').sort(); + removeSync('test/_tmp/output'); + + // this should only update the hash of that particular entry point + writeFileSync( + 'test/_tmp/input/main-static.js', + "import {value} from './shared';\nexport default 2 * value;" + ); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + const [newDynamicName, newStaticName, newChunkName] = + readdirSync('test/_tmp/output').sort(); + removeSync('test/_tmp/output'); + assert.notEqual(newStaticName, staticName); + assert.strictEqual(newDynamicName, dynamicName); + assert.strictEqual(newChunkName, chunkName); + staticName = newStaticName; + + // this should update all hashes + writeFileSync('test/_tmp/input/shared.js', 'export const value = 42;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + const [newDynamicName_1, newStaticName_1, newChunkName_1] = + readdirSync('test/_tmp/output').sort(); + assert.notEqual(newStaticName_1, staticName); + assert.notEqual(newDynamicName_1, dynamicName); + assert.notEqual(newChunkName_1, chunkName); + } + ]); }); it('runs transforms again on previously erroring files that were changed back', () => { @@ -1183,67 +1140,65 @@ describe('rollup.watch', () => { ]); }); - it('skips filesystem writes when configured', () => { + it('skips filesystem writes when configured', async () => { let watchChangeCnt = 0; - return copy('test/watch/samples/skip-writes', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - watch: { - skipWrite: true - }, - plugins: { - watchChange(id) { - watchChangeCnt++; - assert.strictEqual(id, resolve('test/_tmp/input/main.js')); - } - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - watchChangeCnt = 0; - assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); - writeFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); - assert.strictEqual(watchChangeCnt, 1); - writeFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); - assert.strictEqual(watchChangeCnt, 2); - writeFileSync('test/_tmp/input/main.js', 'export default 43;'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - // 'END', - evt => { - assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); - assert.strictEqual(watchChangeCnt, 3); - // still aware of its output destination - assert.strictEqual(evt.output[0], resolve('test/_tmp/output/bundle.js')); + await copy('test/watch/samples/skip-writes', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + watch: { + skipWrite: true + }, + plugins: { + watchChange(id) { + watchChangeCnt++; + assert.strictEqual(id, resolve('test/_tmp/input/main.js')); } - ]); + } }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + watchChangeCnt = 0; + assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); + writeFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); + assert.strictEqual(watchChangeCnt, 1); + writeFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); + assert.strictEqual(watchChangeCnt, 2); + writeFileSync('test/_tmp/input/main.js', 'export default 43;'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + // 'END', + evt => { + assert.strictEqual(existsSync('../_tmp/output/bundle.js'), false); + assert.strictEqual(watchChangeCnt, 3); + // still aware of its output destination + assert.strictEqual(evt.output[0], resolve('test/_tmp/output/bundle.js')); + } + ]); }); it('rebuilds immediately by default', async () => { @@ -1358,293 +1313,20 @@ describe('rollup.watch', () => { assert.strictEqual(run('../_tmp/output/bundle.js'), 43); const timeDiff = getTimeDiffInMs(startTime); assert.ok(timeDiff > 1000, `Time difference ${timeDiff} > 1000`); - } - ]); - }); - - describe('addWatchFile', () => { - it('supports adding additional watch files in plugin hooks', () => { - const watchChangeIds = new Set(); - const buildStartFile = resolve('test/_tmp/input/buildStart'); - const loadFile = resolve('test/_tmp/input/load'); - const resolveIdFile = resolve('test/_tmp/input/resolveId'); - const transformFile = resolve('test/_tmp/input/transform'); - const watchFiles = [buildStartFile, loadFile, resolveIdFile, transformFile]; - return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { - for (const file of watchFiles) writeFileSync(file, 'initial'); - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - plugins: { - buildStart() { - this.addWatchFile(buildStartFile); - }, - load() { - this.addWatchFile(loadFile); - }, - resolveId() { - this.addWatchFile(resolveIdFile); - }, - transform() { - this.addWatchFile(transformFile); - }, - watchChange(id) { - watchChangeIds.add(id); - } - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - // sometimes the watcher is triggered during the initial run - watchChangeIds.clear(); - for (const file of watchFiles) writeFileSync(file, 'changed'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 42); - assert.deepStrictEqual([...watchChangeIds].sort(), watchFiles.sort()); - } - ]); - }); - }); - - it('respects changed watched files in the load hook', () => { - const WATCHED_ID = resolve('test/_tmp/input/watched'); - return copy('test/watch/samples/watch-files', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - plugins: { - load() { - this.addWatchFile(WATCHED_ID); - return `export default "${readFileSync(WATCHED_ID, 'utf8').trim()}"`; - } - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 'initial'); - writeFileSync(WATCHED_ID, 'next'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 'next'); - } - ]); - }); - }); - - it('respects changed watched files in the transform hook and removes them if they are no longer watched', () => { - const WATCHED_ID = resolve('test/_tmp/input/watched'); - let addWatchFile = true; - return copy('test/watch/samples/watch-files', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - plugins: { - resolveId(id) { - if (id === 'dep') { - return id; - } - }, - load(id) { - if (id === 'dep') { - return `throw new Error('This should not be executed);`; - } - }, - transform(code, id) { - if (id.endsWith('main.js')) { - return `export { value as default } from 'dep';`; - } else { - if (addWatchFile) { - this.addWatchFile(WATCHED_ID); - } - return `export const value = "${readFileSync(WATCHED_ID, 'utf8').trim()}"`; - } - } - } - }); - const events = []; - watcher.on('event', event => events.push(event.code)); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 'initial'); - addWatchFile = false; - writeFileSync(WATCHED_ID, 'next'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), 'next'); - writeFileSync(WATCHED_ID, 'other'); - events.length = 0; - return wait(400).then(() => assert.deepStrictEqual(events, [])); - } - ]); - }); - }); - - it('respects changed watched modules that are already part of the graph in the transform hook', () => { - return copy('test/watch/samples/dependencies', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - plugins: { - transform(code, id) { - if (id.endsWith('dep1.js')) { - this.addWatchFile(resolve('test/_tmp/input/dep2.js')); - const text = readFileSync('test/_tmp/input/dep2.js', 'utf8').trim(); - return `export default ${JSON.stringify(text)}`; - } - } - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual( - run('../_tmp/output/bundle.js'), - `dep1: "export default 'dep2';", dep2: "dep2"` - ); - writeFileSync('test/_tmp/input/dep2.js', 'export default "next";'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual( - run('../_tmp/output/bundle.js'), - `dep1: "export default "next";", dep2: "next"` - ); - } - ]); - }); - }); - - it('respects changed watched directories in the transform hook', () => { - const WATCHED_ID = resolve('test/_tmp/input/watched'); - return copy('test/watch/samples/watch-files', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - plugins: { - transform() { - this.addWatchFile('test/_tmp/input'); - return `export default ${existsSync(WATCHED_ID)}`; - } - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), true); - unlinkSync(WATCHED_ID); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), false); - watcher.close(); - } - ]); - }); - }); - - it('respects initially missing added watched files', () => { - return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - plugins: { - transform() { - this.addWatchFile('test/_tmp/input/dep'); - return `export default ${existsSync('test/_tmp/input/dep')}`; - } - } - }); - - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), false); - writeFileSync('test/_tmp/input/dep', ''); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), true); - } - ]); - }); - }); + } + ]); + }); - it('respects unlinked and re-added watched files', () => { + describe('addWatchFile', () => { + it('supports adding additional watch files in plugin hooks', () => { + const watchChangeIds = new Set(); + const buildStartFile = resolve('test/_tmp/input/buildStart'); + const loadFile = resolve('test/_tmp/input/load'); + const resolveIdFile = resolve('test/_tmp/input/resolveId'); + const transformFile = resolve('test/_tmp/input/transform'); + const watchFiles = [buildStartFile, loadFile, resolveIdFile, transformFile]; return copy('test/watch/samples/basic', 'test/_tmp/input').then(() => { - writeFileSync('test/_tmp/input/dep', ''); + for (const file of watchFiles) writeFileSync(file, 'initial'); watcher = rollup.watch({ input: 'test/_tmp/input/main.js', output: { @@ -1653,9 +1335,20 @@ describe('rollup.watch', () => { exports: 'auto' }, plugins: { + buildStart() { + this.addWatchFile(buildStartFile); + }, + load() { + this.addWatchFile(loadFile); + }, + resolveId() { + this.addWatchFile(resolveIdFile); + }, transform() { - this.addWatchFile('test/_tmp/input/dep'); - return `export default ${existsSync('test/_tmp/input/dep')}`; + this.addWatchFile(transformFile); + }, + watchChange(id) { + watchChangeIds.add(id); } } }); @@ -1666,72 +1359,319 @@ describe('rollup.watch', () => { 'BUNDLE_END', 'END', () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), true); - unlinkSync('test/_tmp/input/dep'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), false); - writeFileSync('test/_tmp/input/dep', ''); + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + // sometimes the watcher is triggered during the initial run + watchChangeIds.clear(); + for (const file of watchFiles) writeFileSync(file, 'changed'); }, 'START', 'BUNDLE_START', 'BUNDLE_END', 'END', () => { - assert.strictEqual(run('../_tmp/output/bundle.js'), true); + assert.strictEqual(run('../_tmp/output/bundle.js'), 42); + assert.deepStrictEqual([...watchChangeIds].sort(), watchFiles.sort()); } ]); }); }); - it('does not rerun the transform hook if a non-watched change triggered the re-run', () => { + it('respects changed watched files in the load hook', async () => { const WATCHED_ID = resolve('test/_tmp/input/watched'); - let transformRuns = 0; - return copy('test/watch/samples/watch-files', 'test/_tmp/input') - .then(() => wait(100)) - .then(() => { - writeFileSync('test/_tmp/input/alsoWatched', 'initial'); - watcher = rollup.watch({ - input: 'test/_tmp/input/main.js', - output: { - file: 'test/_tmp/output/bundle.js', - format: 'cjs', - exports: 'auto' - }, - plugins: { - buildStart() { - this.addWatchFile('test/_tmp/input/alsoWatched'); - }, - transform() { - transformRuns++; + await copy('test/watch/samples/watch-files', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: { + load() { + this.addWatchFile(WATCHED_ID); + return `export default "${readFileSync(WATCHED_ID, 'utf8').trim()}"`; + } + } + }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 'initial'); + writeFileSync(WATCHED_ID, 'next'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 'next'); + } + ]); + }); + + it('respects changed watched files in the transform hook and removes them if they are no longer watched', async () => { + const WATCHED_ID = resolve('test/_tmp/input/watched'); + let addWatchFile = true; + await copy('test/watch/samples/watch-files', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: { + resolveId(id) { + if (id === 'dep') { + return id; + } + }, + load(id_1) { + if (id_1 === 'dep') { + return `throw new Error('This should not be executed);`; + } + }, + transform(code, id_2) { + if (id_2.endsWith('main.js')) { + return `export { value as default } from 'dep';`; + } else { + if (addWatchFile) { this.addWatchFile(WATCHED_ID); - return `export default "${readFileSync(WATCHED_ID, 'utf8').trim()}"`; } + return `export const value = "${readFileSync(WATCHED_ID, 'utf8').trim()}"`; } - }); + } + } + }); + const events = []; + watcher.on('event', event_1 => events.push(event_1.code)); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 'initial'); + addWatchFile = false; + writeFileSync(WATCHED_ID, 'next'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), 'next'); + writeFileSync(WATCHED_ID, 'other'); + events.length = 0; + return wait(400).then(() => assert.deepStrictEqual(events, [])); + } + ]); + }); - return sequence(watcher, [ - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(transformRuns, 1); - writeFileSync('test/_tmp/input/alsoWatched', 'next'); - }, - 'START', - 'BUNDLE_START', - 'BUNDLE_END', - 'END', - () => { - assert.strictEqual(transformRuns, 1); + it('respects changed watched modules that are already part of the graph in the transform hook', async () => { + await copy('test/watch/samples/dependencies', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: { + transform(code, id) { + if (id.endsWith('dep1.js')) { + this.addWatchFile(resolve('test/_tmp/input/dep2.js')); + const text = readFileSync('test/_tmp/input/dep2.js', 'utf8').trim(); + return `export default ${JSON.stringify(text)}`; } - ]); - }); + } + } + }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual( + run('../_tmp/output/bundle.js'), + `dep1: "export default 'dep2';", dep2: "dep2"` + ); + writeFileSync('test/_tmp/input/dep2.js', 'export default "next";'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual( + run('../_tmp/output/bundle.js'), + `dep1: "export default "next";", dep2: "next"` + ); + } + ]); + }); + + it('respects changed watched directories in the transform hook', async () => { + const WATCHED_ID = resolve('test/_tmp/input/watched'); + await copy('test/watch/samples/watch-files', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: { + transform() { + this.addWatchFile('test/_tmp/input'); + return `export default ${existsSync(WATCHED_ID)}`; + } + } + }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), true); + unlinkSync(WATCHED_ID); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), false); + watcher.close(); + } + ]); + }); + + it('respects initially missing added watched files', async () => { + await copy('test/watch/samples/basic', 'test/_tmp/input'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: { + transform() { + this.addWatchFile('test/_tmp/input/dep'); + return `export default ${existsSync('test/_tmp/input/dep')}`; + } + } + }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), false); + writeFileSync('test/_tmp/input/dep', ''); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), true); + } + ]); + }); + + it('respects unlinked and re-added watched files', async () => { + await copy('test/watch/samples/basic', 'test/_tmp/input'); + writeFileSync('test/_tmp/input/dep', ''); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: { + transform() { + this.addWatchFile('test/_tmp/input/dep'); + return `export default ${existsSync('test/_tmp/input/dep')}`; + } + } + }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), true); + unlinkSync('test/_tmp/input/dep'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), false); + writeFileSync('test/_tmp/input/dep', ''); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(run('../_tmp/output/bundle.js'), true); + } + ]); + }); + + it('does not rerun the transform hook if a non-watched change triggered the re-run', async () => { + const WATCHED_ID = resolve('test/_tmp/input/watched'); + let transformRuns = 0; + await copy('test/watch/samples/watch-files', 'test/_tmp/input'); + await wait(100); + writeFileSync('test/_tmp/input/alsoWatched', 'initial'); + watcher = rollup.watch({ + input: 'test/_tmp/input/main.js', + output: { + file: 'test/_tmp/output/bundle.js', + format: 'cjs', + exports: 'auto' + }, + plugins: { + buildStart() { + this.addWatchFile('test/_tmp/input/alsoWatched'); + }, + transform() { + transformRuns++; + this.addWatchFile(WATCHED_ID); + return `export default "${readFileSync(WATCHED_ID, 'utf8').trim()}"`; + } + } + }); + return sequence(watcher, [ + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(transformRuns, 1); + writeFileSync('test/_tmp/input/alsoWatched', 'next'); + }, + 'START', + 'BUNDLE_START', + 'BUNDLE_END', + 'END', + () => { + assert.strictEqual(transformRuns, 1); + } + ]); }); }); }).timeout(20000);