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

feat: support nested plugin #4657

Merged
merged 6 commits into from Oct 12, 2022
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
19 changes: 9 additions & 10 deletions cli/run/commandPlugins.ts
@@ -1,28 +1,29 @@
import { resolve } from 'node:path';
import { pathToFileURL } from 'node:url';
import type { InputOptions } from '../../src/rollup/types';
import type { InputOptionsWithPlugins } from '../../src/rollup/types';
import { normalizePluginOption } from '../../src/utils/options/options';
import { stdinPlugin } from './stdin';
import { waitForInputPlugin } from './waitForInput';

export async function addCommandPluginsToInputOptions(
inputOptions: InputOptions,
inputOptions: InputOptionsWithPlugins,
command: Record<string, unknown>
): Promise<void> {
if (command.stdin !== false) {
inputOptions.plugins!.push(stdinPlugin(command.stdin));
inputOptions.plugins.push(stdinPlugin(command.stdin));
}
if (command.waitForBundleInput === true) {
inputOptions.plugins!.push(waitForInputPlugin());
inputOptions.plugins.push(waitForInputPlugin());
}
await addPluginsFromCommandOption(command.plugin, inputOptions);
}

export async function addPluginsFromCommandOption(
commandPlugin: unknown,
inputOptions: InputOptions
inputOptions: InputOptionsWithPlugins
): Promise<void> {
if (commandPlugin) {
const plugins = Array.isArray(commandPlugin) ? commandPlugin : [commandPlugin];
const plugins: any[] = normalizePluginOption(commandPlugin as any);
for (const plugin of plugins) {
if (/[={}]/.test(plugin)) {
// -p plugin=value
Expand All @@ -40,7 +41,7 @@ export async function addPluginsFromCommandOption(
}

async function loadAndRegisterPlugin(
inputOptions: InputOptions,
inputOptions: InputOptionsWithPlugins,
pluginText: string
): Promise<void> {
let plugin: any = null;
Expand Down Expand Up @@ -96,9 +97,7 @@ async function loadAndRegisterPlugin(
)}" for Rollup to recognize it.`
);
}
inputOptions.plugins!.push(
typeof plugin === 'function' ? plugin.call(plugin, pluginArg) : plugin
);
inputOptions.plugins.push(typeof plugin === 'function' ? plugin.call(plugin, pluginArg) : plugin);
}

function getCamelizedPluginBaseName(pluginText: string): string {
Expand Down
8 changes: 4 additions & 4 deletions docs/999-big-list-of-options.md
Expand Up @@ -258,9 +258,9 @@ this.a.b.c = ...

#### output.plugins

Type: `OutputPlugin | (OutputPlugin | void)[]`
Type: `OutputPlugin | (OutputPlugin | OutputPlugin[] | void)[]`

Adds a plugin just to this output. See [Using output plugins](guide/en/#using-output-plugins) for more information on how to use output-specific plugins and [Plugins](guide/en/#plugin-development) on how to write your own. For plugins imported from packages, remember to call the imported plugin function (i.e. `commonjs()`, not just `commonjs`). Falsy plugins will be ignored, which can be used to easily activate or deactivate plugins.
Adds a plugin just to this output. See [Using output plugins](guide/en/#using-output-plugins) for more information on how to use output-specific plugins and [Plugins](guide/en/#plugin-development) on how to write your own. For plugins imported from packages, remember to call the imported plugin function (i.e. `commonjs()`, not just `commonjs`). Falsy plugins will be ignored, which can be used to easily activate or deactivate plugins. Nested plugins will be flatten.

Not every plugin can be used here. `output.plugins` is limited to plugins that only use hooks that run during `bundle.generate()` or `bundle.write()`, i.e. after Rollup's main analysis is complete. If you are a plugin author, see [output generation hooks](guide/en/#output-generation-hooks) to find out which hooks can be used.

Expand Down Expand Up @@ -288,9 +288,9 @@ export default {

#### plugins

Type: `Plugin | (Plugin | void)[]`
Type: `Plugin | (Plugin | Plugin[] | void)[]`

See [Using plugins](guide/en/#using-plugins) for more information on how to use plugins and [Plugins](guide/en/#plugin-development) on how to write your own (try it out, it's not as difficult as it may sound and very much extends what you can do with Rollup). For plugins imported from packages, remember to call the imported plugin function (i.e. `commonjs()`, not just `commonjs`). Falsy plugins will be ignored, which can be used to easily activate or deactivate plugins.
See [Using plugins](guide/en/#using-plugins) for more information on how to use plugins and [Plugins](guide/en/#plugin-development) on how to write your own (try it out, it's not as difficult as it may sound and very much extends what you can do with Rollup). For plugins imported from packages, remember to call the imported plugin function (i.e. `commonjs()`, not just `commonjs`). Falsy plugins will be ignored, which can be used to easily activate or deactivate plugins. Nested plugins will be flatten.

```js
// rollup.config.js
Expand Down
14 changes: 11 additions & 3 deletions src/rollup/types.d.ts
Expand Up @@ -492,6 +492,8 @@ export type SourcemapPathTransformOption = (
sourcemapPath: string
) => string;

export type InputPluginOption = Plugin | null | false | undefined | InputPluginOption[];

export interface InputOptions {
acorn?: Record<string, unknown>;
acornInjectPlugins?: (() => unknown)[] | (() => unknown);
Expand All @@ -511,7 +513,7 @@ export interface InputOptions {
moduleContext?: ((id: string) => string | null | void) | { [id: string]: string };
onwarn?: WarningHandlerWithDefault;
perf?: boolean;
plugins?: (Plugin | null | false | undefined)[];
plugins?: InputPluginOption;
preserveEntrySignatures?: PreserveEntrySignaturesOption;
/** @deprecated Use the "preserveModules" output option instead. */
preserveModules?: boolean;
Expand All @@ -522,6 +524,10 @@ export interface InputOptions {
watch?: WatcherOptions | false;
}

export interface InputOptionsWithPlugins extends InputOptions {
plugins: Plugin[];
}

export interface NormalizedInputOptions {
acorn: Record<string, unknown>;
acornInjectPlugins: (() => unknown)[];
Expand Down Expand Up @@ -610,6 +616,8 @@ export type NormalizedAmdOptions = (

type AddonFunction = (chunk: RenderedChunk) => string | Promise<string>;

type OutputPluginOption = OutputPlugin | null | false | undefined | OutputPluginOption[];

export interface OutputOptions {
amd?: AmdOptions;
assetFileNames?: string | ((chunkInfo: PreRenderedAsset) => string);
Expand Down Expand Up @@ -647,7 +655,7 @@ export interface OutputOptions {
noConflict?: boolean;
outro?: string | AddonFunction;
paths?: OptionsPaths;
plugins?: (OutputPlugin | null | false | undefined)[];
plugins?: OutputPluginOption;
/** @deprecated Use "generatedCode.constBindings" instead. */
preferConst?: boolean;
preserveModules?: boolean;
Expand Down Expand Up @@ -800,7 +808,7 @@ export interface RollupOptions extends InputOptions {
output?: OutputOptions | OutputOptions[];
}

export interface MergedRollupOptions extends InputOptions {
export interface MergedRollupOptions extends InputOptionsWithPlugins {
output: OutputOptions[];
}

Expand Down
7 changes: 5 additions & 2 deletions src/utils/options/mergeOptions.ts
@@ -1,8 +1,10 @@
import type {
ExternalOption,
InputOptions,
InputPluginOption,
MergedRollupOptions,
OutputOptions,
OutputPluginOption,
RollupCache,
WarningHandler,
WarningHandlerWithDefault
Expand All @@ -13,6 +15,7 @@ import {
defaultOnWarn,
generatedCodePresets,
type GenericConfigObject,
normalizePluginOption,
objectifyOption,
objectifyOptionWithPresets,
treeshakePresets,
Expand Down Expand Up @@ -126,7 +129,7 @@ function mergeInputOptions(
moduleContext: getOption('moduleContext'),
onwarn: getOnWarn(config, defaultOnWarnHandler),
perf: getOption('perf'),
plugins: ensureArray(config.plugins) as Plugin[],
plugins: normalizePluginOption(config.plugins as InputPluginOption),
preserveEntrySignatures: getOption('preserveEntrySignatures'),
preserveModules: getOption('preserveModules'),
preserveSymlinks: getOption('preserveSymlinks'),
Expand Down Expand Up @@ -261,7 +264,7 @@ function mergeOutputOptions(
noConflict: getOption('noConflict'),
outro: getOption('outro'),
paths: getOption('paths'),
plugins: ensureArray(config.plugins) as Plugin[],
plugins: normalizePluginOption(config.plugins as OutputPluginOption),
preferConst: getOption('preferConst'),
preserveModules: getOption('preserveModules'),
preserveModulesRoot: getOption('preserveModulesRoot'),
Expand Down
3 changes: 2 additions & 1 deletion src/utils/options/normalizeInputOptions.ts
Expand Up @@ -16,6 +16,7 @@ import {
defaultOnWarn,
type GenericConfigObject,
getOptionWithPreset,
normalizePluginOption,
treeshakePresets,
warnUnknownOptions
} from './options';
Expand Down Expand Up @@ -54,7 +55,7 @@ export function normalizeInputOptions(config: InputOptions): {
moduleContext: getModuleContext(config, context),
onwarn,
perf: config.perf || false,
plugins: ensureArray(config.plugins),
plugins: normalizePluginOption(config.plugins),
preserveEntrySignatures: config.preserveEntrySignatures ?? 'exports-only',
preserveModules: getPreserveModules(config, onwarn, strictDeprecations),
preserveSymlinks: config.preserveSymlinks || false,
Expand Down
4 changes: 2 additions & 2 deletions src/utils/options/normalizeOutputOptions.ts
Expand Up @@ -6,7 +6,6 @@ import type {
OutputOptions,
SourcemapPathTransformOption
} from '../../rollup/types';
import { ensureArray } from '../ensureArray';
import { errInvalidExportOptionValue, errInvalidOption, error, warnDeprecation } from '../error';
import { resolve } from '../path';
import { sanitizeFileName as defaultSanitizeFileName } from '../sanitizeFileName';
Expand All @@ -15,6 +14,7 @@ import {
generatedCodePresets,
type GenericConfigObject,
getOptionWithPreset,
normalizePluginOption,
warnUnknownOptions
} from './options';

Expand Down Expand Up @@ -68,7 +68,7 @@ export function normalizeOutputOptions(
noConflict: config.noConflict || false,
outro: getAddon(config, 'outro'),
paths: config.paths || {},
plugins: ensureArray(config.plugins),
plugins: normalizePluginOption(config.plugins),
preferConst,
preserveModules,
preserveModulesRoot: getPreserveModulesRoot(config),
Expand Down
9 changes: 9 additions & 0 deletions src/utils/options/options.ts
@@ -1,9 +1,13 @@
import type {
InputOptions,
InputPluginOption,
NormalizedGeneratedCodeOptions,
NormalizedOutputOptions,
NormalizedTreeshakingOptions,
OutputOptions,
OutputPlugin,
OutputPluginOption,
Plugin,
WarningHandler
} from '../../rollup/types';
import { errInvalidOption, error, errUnknownOption } from '../error';
Expand Down Expand Up @@ -145,3 +149,8 @@ export const getOptionWithPreset = <T extends ObjectOptionWithPresets>(

const getHashFromObjectOption = (optionName: string): string =>
optionName.split('.').join('').toLowerCase();

export const normalizePluginOption: {
(plugins: InputPluginOption): Plugin[];
(plugins: OutputPluginOption): OutputPlugin[];
} = (plugins: any) => [plugins].flat(Infinity).filter(Boolean);
9 changes: 7 additions & 2 deletions src/utils/timers.ts
@@ -1,4 +1,9 @@
import type { InputOptions, Plugin, PluginHooks, SerializedTimings } from '../rollup/types';
import type {
NormalizedInputOptions,
Plugin,
PluginHooks,
SerializedTimings
} from '../rollup/types';
import performance from './performance';
import process from './process';

Expand Down Expand Up @@ -117,7 +122,7 @@ function getPluginWithTimers(plugin: any, index: number): Plugin {
return plugin;
}

export function initialiseTimers(inputOptions: InputOptions): void {
export function initialiseTimers(inputOptions: NormalizedInputOptions): void {
if (inputOptions.perf) {
timers = new Map();
timeStart = timeStartImpl;
Expand Down
22 changes: 22 additions & 0 deletions test/function/samples/nested-plugin/_config.js
@@ -0,0 +1,22 @@
const plugin = [
{
name: 'nested-plugin-1',
transform(code) {
return code.replace('foo = 1', 'foo = 2');
}
},
{
name: 'nested-plugin-2',
transform(code) {
return code.replace('answer = 41', 'answer = 42');
}
}
];
sxzz marked this conversation as resolved.
Show resolved Hide resolved

module.exports = {
description: 'works when nested plugin',
options: {
// eslint-disable-next-line no-sparse-arrays
plugins: [plugin, [undefined, [null]], ,]
}
};
5 changes: 5 additions & 0 deletions test/function/samples/nested-plugin/main.js
@@ -0,0 +1,5 @@
const foo = 1;
const answer = 41;

assert.equal(foo, 2);
assert.equal(answer, 42);