Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hook for modifying OutputOptions #2736

Merged
merged 8 commits into from Mar 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/05-plugins.md
Expand Up @@ -149,6 +149,12 @@ Kind: `sync, sequential`

Reads and replaces or manipulates the options object passed to `rollup.rollup`. Returning `null` does not replace anything. This is the only hook that does not have access to most [plugin context](guide/en#plugin-context) utility functions as it is run before rollup is fully configured.

#### `outputOptions`
Type: `(outputOptions: OutputOptions) => OutputOptions | null`<br>
Kind: `sync, sequential`

Reads and replaces or manipulates the output options object passed to `bundle.generate`. Returning `null` does not replace anything.

#### `outro`
Type: `string | (() => string)`<br>
Kind: `async, parallel`
Expand Down
17 changes: 14 additions & 3 deletions src/rollup/index.ts
Expand Up @@ -11,6 +11,7 @@ import { writeFile } from '../utils/fs';
import getExportMode from '../utils/getExportMode';
import mergeOptions, { GenericConfigObject } from '../utils/mergeOptions';
import { basename, dirname, isAbsolute, resolve } from '../utils/path';
import { PluginDriver } from '../utils/pluginDriver';
import { SOURCEMAPPING_URL } from '../utils/sourceMappingURL';
import { getTimings, initialiseTimers, timeEnd, timeStart } from '../utils/timers';
import {
Expand Down Expand Up @@ -174,7 +175,8 @@ export default function rollup(rawInputOptions: GenericConfigObject): Promise<Ro
const outputOptions = normalizeOutputOptions(
inputOptions,
rawOutputOptions,
chunks.length > 1
chunks.length > 1,
graph.pluginDriver
);

timeStart('GENERATE', 1);
Expand Down Expand Up @@ -413,7 +415,8 @@ function writeOutputFile(
function normalizeOutputOptions(
inputOptions: GenericConfigObject,
rawOutputOptions: GenericConfigObject,
hasMultipleChunks: boolean
hasMultipleChunks: boolean,
pluginDriver: PluginDriver
): OutputOptions {
if (!rawOutputOptions) {
throw new Error('You must supply an options object');
Expand All @@ -427,7 +430,15 @@ function normalizeOutputOptions(
if (mergedOptions.optionError) throw new Error(mergedOptions.optionError);

// now outputOptions is an array, but rollup.rollup API doesn't support arrays
const outputOptions = mergedOptions.outputOptions[0];
const mergedOutputOptions = mergedOptions.outputOptions[0];
const outputOptionsReducer = (outputOptions: OutputOptions, result: OutputOptions) => {
return result || outputOptions;
};
const outputOptions = pluginDriver.hookReduceArg0Sync(
'outputOptions',
[mergedOutputOptions],
outputOptionsReducer
);

checkOutputOptions(outputOptions);

Expand Down
1 change: 1 addition & 0 deletions src/rollup/types.d.ts
Expand Up @@ -237,6 +237,7 @@ export interface Plugin {
chunk: OutputChunk
) => void | Promise<void>;
options?: (this: MinimalPluginContext, options: InputOptions) => InputOptions | void | null;
outputOptions?: (this: PluginContext, options: OutputOptions) => OutputOptions | void | null;
outro?: AddonHook;
renderChunk?: RenderChunkHook;
renderError?: (this: PluginContext, err?: Error) => Promise<void> | void;
Expand Down
14 changes: 14 additions & 0 deletions src/utils/pluginDriver.ts
Expand Up @@ -29,6 +29,12 @@ export interface PluginDriver {
reduce: Reduce<R, T>,
hookContext?: HookContext
): Promise<T>;
hookReduceArg0Sync<R = any, T = any>(
hook: string,
args: any[],
reduce: Reduce<R, T>,
hookContext?: HookContext
): T;
hookReduceValue<R = any, T = any>(
hook: string,
value: T | Promise<T>,
Expand Down Expand Up @@ -307,6 +313,14 @@ export function createPluginDriver(
}
return promise;
},
// chains, synchronically reduces returns of type R, to type T, handling the reduced value as the first hook argument
hookReduceArg0Sync(name, [arg0, ...args], reduce, hookContext) {
for (let i = 0; i < plugins.length; i++) {
const result = runHookSync(name, [arg0, ...args], i, false, hookContext);
arg0 = reduce.call(pluginContexts[i], arg0, result, plugins[i]);
}
return arg0;
},
// chains, reduces returns of type R, to type T, handling the reduced value separately. permits hooks as values.
hookReduceValue(name, initial, args, reduce, hookContext) {
let promise = Promise.resolve(initial);
Expand Down
32 changes: 32 additions & 0 deletions test/hooks/index.js
Expand Up @@ -29,6 +29,38 @@ describe('hooks', () => {
.then(bundle => {});
});

it('allows to read and modify output options in the outputOptions hook', () => {
return rollup
.rollup({
input: 'input',
treeshake: false,
plugins: [
loader({ input: `alert('hello')` }),
{
renderChunk(code, chunk, options) {
assert.strictEqual(options.banner, 'new banner');
assert.strictEqual(options.format, 'cjs');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to verify that not only the options are updated, but the code was actually rendered using the updated options by inspecting the generated code.

For the latter, I think it would be best to inspect the output of bundle.generate

},
outputOptions(options) {
assert.strictEqual(options.banner, 'banner');
assert.strictEqual(options.format, 'cjs');
assert.ok(/^\d+\.\d+\.\d+/.test(this.meta.rollupVersion));
return Object.assign({}, options, { banner: 'new banner' });
}
}
]
})
.then(bundle => {
return bundle.generate({
format: 'cjs',
banner: 'banner'
});
})
.then(({ output }) => {
assert.equal(output[0].code, `new banner\n'use strict';\n\nalert('hello');\n`);
});
});

it('supports buildStart and buildEnd hooks', () => {
let buildStartCnt = 0;
let buildEndCnt = 0;
Expand Down