From 35db7bb05701d0566616122d4b77d45bf73d36b8 Mon Sep 17 00:00:00 2001 From: Birk Skyum Date: Fri, 1 May 2026 19:35:15 +0200 Subject: [PATCH 1/3] fix: dual rollup and rolldown compat --- plugin/data.ts | 2 +- plugin/index.ts | 8 ++++-- plugin/rollup-types.ts | 60 ++++++++++++++++++++++++++++++++++++++++++ plugin/sourcemap.ts | 2 +- 4 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 plugin/rollup-types.ts diff --git a/plugin/data.ts b/plugin/data.ts index 5a85235..fd7924a 100644 --- a/plugin/data.ts +++ b/plugin/data.ts @@ -1,4 +1,4 @@ -import { GetModuleInfo } from "rollup"; +import type { GetModuleInfo } from "./rollup-types.js"; import { isModuleTree, ModuleLengths, ModuleTree, ModuleTreeLeaf } from "../shared/types.js"; import { ModuleMapper } from "./module-mapper.js"; diff --git a/plugin/index.ts b/plugin/index.ts index 689109e..9909103 100644 --- a/plugin/index.ts +++ b/plugin/index.ts @@ -1,7 +1,8 @@ import { promises as fs } from "node:fs"; import path from "node:path"; -import { OutputBundle, Plugin, NormalizedOutputOptions, OutputOptions } from "rollup"; +import type { OutputBundle, NormalizedOutputOptions } from "rollup"; +import type { Plugin, OutputOptions } from "./rollup-types.js"; import opn, { Options as OpenOptions } from "open"; import { ModuleLengths, ModuleTree, ModuleTreeLeaf, VisualizerData } from "../shared/types.js"; @@ -140,7 +141,10 @@ export const visualizer = ( outputOptions: NormalizedOutputOptions, outputBundle: OutputBundle, ): Promise { - opts = typeof opts === "function" ? opts(outputOptions) : opts; + // The local `OutputOptions` is a structural subset of rollup's + // `NormalizedOutputOptions` — see plugin/rollup-types.ts for why we + // don't import directly from "rollup" here. + opts = typeof opts === "function" ? opts(outputOptions as unknown as OutputOptions) : opts; if ("json" in opts) { this.warn(WARN_JSON_DEPRECATED); diff --git a/plugin/rollup-types.ts b/plugin/rollup-types.ts new file mode 100644 index 0000000..405e49e --- /dev/null +++ b/plugin/rollup-types.ts @@ -0,0 +1,60 @@ +/** + * Local structural type stubs for rollup/rolldown. + * + * `rollup` and `rolldown` are declared as *optional* peer dependencies, so the + * published `.d.ts` files cannot hard-import from either package — that would + * force consumers using only one bundler to also install the other (~1 MB plus + * native binaries) just to satisfy TypeScript. + * + * These minimal interfaces describe only what the visualizer plugin actually + * exposes in its public API or consumes internally. They are intentionally + * structural subsets of the corresponding `rollup` and `rolldown` types — both + * of which export `Plugin`, `OutputOptions`, `OutputChunk`, and + * `GetModuleInfo` with compatible shapes — so the plugin object the visualizer + * returns is assignable to either bundler's `plugins` array. + * + * If you need richer typing for output options inside an options factory or + * for a particular hook, cast to the relevant bundler's type in your own code. + */ + +export interface OutputOptions { + dir?: string; + file?: string; + format?: string; + name?: string; + entryFileNames?: string | ((chunkInfo: any) => string); + chunkFileNames?: string | ((chunkInfo: any) => string); + assetFileNames?: string | ((assetInfo: any) => string); + sourcemap?: boolean | "inline" | "hidden"; + banner?: unknown; + footer?: unknown; + intro?: unknown; + outro?: unknown; + globals?: unknown; + exports?: "auto" | "default" | "named" | "none"; +} + +export interface Plugin { + name: string; + generateBundle?: ( + this: any, + options: any, + bundle: any, + isWrite?: boolean, + ) => unknown | Promise; +} + +export interface OutputChunk { + type: "chunk"; + code: string; + map?: unknown; + facadeModuleId?: string | null; + modules: Record; +} + +export type GetModuleInfo = (moduleId: string) => { + isEntry: boolean; + isExternal: boolean; + importedIds: readonly string[]; + dynamicallyImportedIds?: readonly string[]; +} | null; diff --git a/plugin/sourcemap.ts b/plugin/sourcemap.ts index 6ed061e..4889101 100644 --- a/plugin/sourcemap.ts +++ b/plugin/sourcemap.ts @@ -1,5 +1,5 @@ import path from "node:path"; -import { OutputChunk } from "rollup"; +import type { OutputChunk } from "./rollup-types.js"; import type { RawSourceMap } from "source-map"; import { SourceMapConsumer } from "source-map"; From 048680d127dcc30865325deb28a69195b3b3d4f4 Mon Sep 17 00:00:00 2001 From: Birk Skyum Date: Fri, 1 May 2026 19:36:16 +0200 Subject: [PATCH 2/3] void --- plugin/rollup-types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/rollup-types.ts b/plugin/rollup-types.ts index 405e49e..5704b7a 100644 --- a/plugin/rollup-types.ts +++ b/plugin/rollup-types.ts @@ -41,7 +41,7 @@ export interface Plugin { options: any, bundle: any, isWrite?: boolean, - ) => unknown | Promise; + ) => void | Promise; } export interface OutputChunk { From 8d344ed826b292af2ccf449e4b16cce0c097148a Mon Sep 17 00:00:00 2001 From: Birk Skyum Date: Fri, 1 May 2026 19:48:30 +0200 Subject: [PATCH 3/3] cleanup --- plugin/index.ts | 3 --- plugin/rollup-types.ts | 20 ++------------------ 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/plugin/index.ts b/plugin/index.ts index 9909103..ae477e1 100644 --- a/plugin/index.ts +++ b/plugin/index.ts @@ -141,9 +141,6 @@ export const visualizer = ( outputOptions: NormalizedOutputOptions, outputBundle: OutputBundle, ): Promise { - // The local `OutputOptions` is a structural subset of rollup's - // `NormalizedOutputOptions` — see plugin/rollup-types.ts for why we - // don't import directly from "rollup" here. opts = typeof opts === "function" ? opts(outputOptions as unknown as OutputOptions) : opts; if ("json" in opts) { diff --git a/plugin/rollup-types.ts b/plugin/rollup-types.ts index 5704b7a..7af8e12 100644 --- a/plugin/rollup-types.ts +++ b/plugin/rollup-types.ts @@ -1,21 +1,5 @@ -/** - * Local structural type stubs for rollup/rolldown. - * - * `rollup` and `rolldown` are declared as *optional* peer dependencies, so the - * published `.d.ts` files cannot hard-import from either package — that would - * force consumers using only one bundler to also install the other (~1 MB plus - * native binaries) just to satisfy TypeScript. - * - * These minimal interfaces describe only what the visualizer plugin actually - * exposes in its public API or consumes internally. They are intentionally - * structural subsets of the corresponding `rollup` and `rolldown` types — both - * of which export `Plugin`, `OutputOptions`, `OutputChunk`, and - * `GetModuleInfo` with compatible shapes — so the plugin object the visualizer - * returns is assignable to either bundler's `plugins` array. - * - * If you need richer typing for output options inside an options factory or - * for a particular hook, cast to the relevant bundler's type in your own code. - */ +// Structural stubs for rollup/rolldown types. Both bundlers are optional peer +// deps, so the published .d.ts files can't hard-import from either. export interface OutputOptions { dir?: string;