Skip to content

Commit

Permalink
Adds type definitions for RollupWatcher events. (#3302)
Browse files Browse the repository at this point in the history
* Adds type definitions for RollupWatcher events.

The type information is extracted from https://github.com/rollup/rollup/blob/master/src/watch/index.ts, someone should double check that I got it all right.  I'm new to rollup and have never actually used any of this stuff, but when I tried to I ran into the problem of there being no useful type information which caused me to have to read source code.  Rather than having everyone suffer like I did, I decided to create a PR to resolve the issue.

* Fixes RollupWatcher.on type signature.

I didn't realize that `on` was chainable, this should resolve the issue.

* Utilize new watcher type

* Remove FATAL references

Co-authored-by: Micah Zoltu <micah@zoltu.net>
Co-authored-by: Andrew Powell <shellscape@users.noreply.github.com>
  • Loading branch information
3 people authored and lukastaegert committed Jan 8, 2020
1 parent b3d610f commit 7769fb9
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 55 deletions.
34 changes: 8 additions & 26 deletions cli/run/watch.ts
Expand Up @@ -5,13 +5,9 @@ import onExit from 'signal-exit';
import tc from 'turbocolor';
import * as rollup from '../../src/node-entry';
import {
InputOption,
RollupBuild,
RollupError,
RollupWatcher,
RollupWatchOptions,
WarningHandler,
WatcherOptions
WarningHandler
} from '../../src/rollup/types';
import mergeOptions, { GenericConfigObject } from '../../src/utils/mergeOptions';
import relativeId from '../../src/utils/relativeId';
Expand All @@ -21,15 +17,6 @@ import loadConfigFile from './loadConfigFile';
import { getResetScreen } from './resetScreen';
import { printTimings } from './timings';

interface WatchEvent {
code?: string;
duration?: number;
error?: RollupError | Error;
input?: InputOption;
output?: string[];
result?: RollupBuild;
}

export default function watch(
configFile: string,
configs: GenericConfigObject[],
Expand All @@ -40,7 +27,7 @@ export default function watch(
const warnings = batchWarnings();
const initialConfigs = processConfigs(configs);
const clearScreen = initialConfigs.every(
config => (config.watch as WatcherOptions).clearScreen !== false
config => config.watch!.clearScreen !== false
);

const resetScreen = getResetScreen(isTTY && clearScreen);
Expand Down Expand Up @@ -75,16 +62,11 @@ export default function watch(
function start(configs: RollupWatchOptions[]) {
watcher = rollup.watch(configs as any);

watcher.on('event', (event: WatchEvent) => {
watcher.on('event', event => {
switch (event.code) {
case 'FATAL':
handleError(event.error as RollupError, true);
process.exit(1);
break;

case 'ERROR':
warnings.flush();
handleError(event.error as RollupError, true);
handleError(event.error, true);
break;

case 'START':
Expand All @@ -106,7 +88,7 @@ export default function watch(
stderr(
tc.cyan(
`bundles ${tc.bold(input)}${tc.bold(
(event.output as string[]).map(relativeId).join(', ')
event.output.map(relativeId).join(', ')
)}...`
)
);
Expand All @@ -119,8 +101,8 @@ export default function watch(
stderr(
tc.green(
`created ${tc.bold(
(event.output as string[]).map(relativeId).join(', ')
)} in ${tc.bold(ms(event.duration as number))}`
event.output.map(relativeId).join(', ')
)} in ${tc.bold(ms(event.duration))}`
)
);
if (event.result && event.result.getTimings) {
Expand Down Expand Up @@ -204,6 +186,6 @@ export default function watch(

configWatcher = fs.watch(configFile, (event: string) => {
if (event === 'change') restart();
});
}) as RollupWatcher;
}
}
5 changes: 2 additions & 3 deletions docs/02-javascript-api.md
Expand Up @@ -117,7 +117,7 @@ const outputOptions = {
globals,
name,
plugins,

// advanced output options
assetFileNames,
banner,
Expand All @@ -135,7 +135,7 @@ const outputOptions = {
sourcemapExcludeSources,
sourcemapFile,
sourcemapPathTransform,

// danger zone
amd,
dynamicImportFunction,
Expand Down Expand Up @@ -167,7 +167,6 @@ watcher.on('event', event => {
// BUNDLE_END — finished building a bundle
// END — finished building all bundles
// ERROR — encountered an error while bundling
// FATAL — encountered an unrecoverable error
});

// stop watching
Expand Down
3 changes: 2 additions & 1 deletion src/rollup/index.ts
Expand Up @@ -401,7 +401,8 @@ function createOutput(outputBundle: Record<string, OutputChunk | OutputAsset | {
.map(fileName => outputBundle[fileName])
.filter(outputFile => Object.keys(outputFile).length > 0) as (
| OutputChunk
| OutputAsset)[]).sort((outputFileA, outputFileB) => {
| OutputAsset
)[]).sort((outputFileA, outputFileB) => {
const fileTypeA = getSortingFileType(outputFileA);
const fileTypeB = getSortingFileType(outputFileB);
if (fileTypeA === fileTypeB) return 0;
Expand Down
38 changes: 37 additions & 1 deletion src/rollup/types.d.ts
Expand Up @@ -614,7 +614,43 @@ export interface RollupWatchOptions extends InputOptions {
watch?: WatcherOptions;
}

export interface RollupWatcher extends EventEmitter {
interface TypedEventEmitter<T> {
addListener<K extends keyof T>(event: K, listener: T[K]): this;
emit<K extends keyof T>(event: K, ...args: any[]): boolean;
eventNames(): Array<keyof T>;
getMaxListeners(): number;
listenerCount(type: keyof T): number;
listeners<K extends keyof T>(event: K): Array<T[K]>;
off<K extends keyof T>(event: K, listener: T[K]): this;
on<K extends keyof T>(event: K, listener: T[K]): this;
once<K extends keyof T>(event: K, listener: T[K]): this;
prependListener<K extends keyof T>(event: K, listener: T[K]): this;
prependOnceListener<K extends keyof T>(event: K, listener: T[K]): this;
rawListeners<K extends keyof T>(event: K): Array<T[K]>;
removeAllListeners<K extends keyof T>(event?: K): this;
removeListener<K extends keyof T>(event: K, listener: T[K]): this;
setMaxListeners(n: number): this;
}

export type RollupWatcherEvent =
| { code: 'START' }
| { code: 'BUNDLE_START'; input: InputOption; output: readonly string[] }
| {
code: 'BUNDLE_END';
duration: number;
input: InputOption;
output: readonly string[];
result: RollupBuild;
}
| { code: 'END' }
| { code: 'ERROR'; error: RollupError };

export interface RollupWatcher
extends TypedEventEmitter<{
change: (id: string) => void;
event: (event: RollupWatcherEvent) => void;
restart: () => void;
}> {
close(): void;
}

Expand Down
2 changes: 1 addition & 1 deletion src/utils/PluginContext.ts
Expand Up @@ -194,7 +194,7 @@ export function getPluginContexts(
});
deprecationWarningShown = true;
}
return watcher!.on(event, handler);
return watcher!.on(event as any, handler);
}

return {
Expand Down
7 changes: 4 additions & 3 deletions src/utils/deconflictChunk.ts
Expand Up @@ -97,9 +97,10 @@ function deconflictImportsOther(
if (chunk.exportMode === 'default' || (preserveModules && variable.isNamespace)) {
variable.setRenderNames(null, chunk.variableName);
} else {
variable.setRenderNames(chunk.variableName, chunk.getVariableExportName(variable) as
| string
| null);
variable.setRenderNames(
chunk.variableName,
chunk.getVariableExportName(variable) as string | null
);
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/watch/index.ts
Expand Up @@ -28,7 +28,7 @@ export class Watcher {
private tasks: Task[];

constructor(configs: GenericConfigObject[] | GenericConfigObject) {
this.emitter = new (class extends EventEmitter implements RollupWatcher {
this.emitter = new (class extends EventEmitter {
close: () => void;
constructor(close: () => void) {
super();
Expand All @@ -37,7 +37,7 @@ export class Watcher {
// showing the `MaxListenersExceededWarning` to the user.
this.setMaxListeners(Infinity);
}
})(this.close.bind(this));
})(this.close.bind(this)) as RollupWatcher;
this.tasks = (Array.isArray(configs) ? configs : configs ? [configs] : []).map(
config => new Task(this, config)
);
Expand All @@ -55,7 +55,7 @@ export class Watcher {
}

emit(event: string, value?: any) {
this.emitter.emit(event, value);
this.emitter.emit(event as any, value);
}

invalidate(id?: string) {
Expand Down
Expand Up @@ -22,11 +22,14 @@ module.exports = {
]
},
bundle(bundle) {
return bundle.generate({ format: 'esm' }).then(generated =>
assert.deepEqual(
generated.output.map(chunk => chunk.fileName),
['main.js', '_virtual/_virtualModule.js', '_virtual/_virtualModule2.js']
)
);
return bundle
.generate({ format: 'esm' })
.then(generated =>
assert.deepEqual(generated.output.map(chunk => chunk.fileName), [
'main.js',
'_virtual/_virtualModule.js',
'_virtual/_virtualModule2.js'
])
);
}
};
Expand Up @@ -22,11 +22,14 @@ module.exports = {
]
},
bundle(bundle) {
return bundle.generate({ format: 'esm' }).then(generated =>
assert.deepEqual(
generated.output.map(chunk => chunk.fileName),
['main.js', '_virtual/_virtualModule', 'lib/lib.js']
)
);
return bundle
.generate({ format: 'esm' })
.then(generated =>
assert.deepEqual(generated.output.map(chunk => chunk.fileName), [
'main.js',
'_virtual/_virtualModule',
'lib/lib.js'
])
);
}
};
7 changes: 5 additions & 2 deletions test/hooks/index.js
Expand Up @@ -914,7 +914,7 @@ describe('hooks', () => {
return new Promise((resolve, reject) => {
watcher.on('event', event => {
if (event.code === 'BUNDLE_END') resolve();
else if (event.code === 'ERROR' || event.code === 'FATAL') reject(event.error);
else if (event.code === 'ERROR') reject(event.error);
});
}).catch(err => {
assert.strictEqual(
Expand Down Expand Up @@ -1192,7 +1192,10 @@ describe('hooks', () => {
})
)
.then(() => {
assert.deepEqual(result, [{ a: file, format: 'cjs' }, { b: file, format: 'cjs' }]);
assert.deepEqual(result, [
{ a: file, format: 'cjs' },
{ b: file, format: 'cjs' }
]);
return sander.rimraf(TEMP_DIR);
});
});
Expand Down
3 changes: 0 additions & 3 deletions test/watch/index.js
Expand Up @@ -34,9 +34,6 @@ describe('rollup.watch', () => {
} else if (typeof next === 'string') {
watcher.once('event', event => {
if (event.code !== next) {
if (event.code === 'FATAL') {
console.error(event.error);
}
watcher.close();
if (event.code === 'ERROR') console.log(event.error);
reject(new Error(`Expected ${next} event, got ${event.code}`));
Expand Down

0 comments on commit 7769fb9

Please sign in to comment.