diff --git a/packages/vite/rollup.dts.config.ts b/packages/vite/rollup.dts.config.ts index 0299f9a95e4e8e..a4d3886d2a7026 100644 --- a/packages/vite/rollup.dts.config.ts +++ b/packages/vite/rollup.dts.config.ts @@ -1,5 +1,6 @@ import { readFileSync } from 'node:fs' import { fileURLToPath } from 'node:url' +import { findStaticImports } from 'mlly' import { type Plugin, defineConfig } from 'rollup' import dts from 'rollup-plugin-dts' @@ -28,12 +29,34 @@ const multilineCommentsRE = /\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\//g const singlelineCommentsRE = /\/\/[^/].*/g const licenseCommentsRE = /MIT License|MIT license|BSD license/ const consecutiveNewlinesRE = /\n{2,}/g +const identifierWithTrailingDollarRE = /\b(\w+)\$\d+\b/g + +/** + * Replace specific identifiers with a more readable name, grouped by + * the module that imports the identifer as a named import alias + */ +const identifierReplacements: Record> = { + rollup: { + Plugin$1: 'rollup.Plugin', + TransformResult$2: 'rollup.TransformResult', + }, + esbuild: { + TransformResult$1: 'esbuild_TransformResult', + TransformOptions$1: 'esbuild_TransformOptions', + BuildOptions$1: 'esbuild_BuildOptions', + }, + 'node:https': { + Server$1: 'HttpsServer', + ServerOptions$1: 'HttpsServerOptions', + }, +} /** * Patch the types files before passing to dts plugin * 1. Resolve `dep-types/*` and `types/*` imports * 2. Validate unallowed dependency imports - * 3. Clean unnecessary comments + * 3. Replace confusing type names + * 4. Clean unnecessary comments */ function patchTypes(): Plugin { return { @@ -56,8 +79,8 @@ function patchTypes(): Plugin { } }, renderChunk(code, chunk) { - const deps = new Set(Object.keys(pkg.dependencies)) // Validate that chunk imports do not import dev deps + const deps = new Set(Object.keys(pkg.dependencies)) for (const id of chunk.imports) { if ( !id.startsWith('./') && @@ -72,13 +95,79 @@ function patchTypes(): Plugin { } } + // Rollup deduplicate type names with a trailing `$1` or `$2`, which can be + // confusing when showed in autocompletions. Try to replace with a better name + const imports = findStaticImports(code) + for (const modName in identifierReplacements) { + const imp = imports.find( + (imp) => imp.specifier === modName && imp.imports.includes('{'), + ) + // Validate that `identifierReplacements` is not outdated if there's no match + if (!imp) { + this.warn( + `${chunk.fileName} does not import "${modName}" for replacement`, + ) + process.exitCode = 1 + continue + } + + const replacements = identifierReplacements[modName] + for (const id in replacements) { + // Validate that `identifierReplacements` is not outdated if there's no match + if (!imp.imports.includes(id)) { + this.warn( + `${chunk.fileName} does not import "${id}" from "${modName}" for replacement`, + ) + process.exitCode = 1 + continue + } + + const betterId = replacements[id] + const regexEscapedId = escapeRegex(id) + // If the better id accesses a namespace, the existing `Foo as Foo$1` + // named import cannot be replaced with `Foo as Namespace.Foo`, so we + // pre-emptively remove the whole named import + if (betterId.includes('.')) { + code = code.replace( + new RegExp(`\\b\\w+\\b as ${regexEscapedId},?\\s?`), + '', + ) + } + code = code.replace( + new RegExp(`\\b${regexEscapedId}\\b`, 'g'), + betterId, + ) + } + } + const unreplacedIds = unique( + Array.from(code.matchAll(identifierWithTrailingDollarRE), (m) => m[0]), + ) + if (unreplacedIds.length) { + const unreplacedStr = unreplacedIds.map((id) => `\n- ${id}`).join('') + this.warn( + `${chunk.fileName} contains confusing identifier names${unreplacedStr}`, + ) + process.exitCode = 1 + } + // Clean unnecessary comments - return code + code = code .replace(singlelineCommentsRE, '') .replace(multilineCommentsRE, (m) => { return licenseCommentsRE.test(m) ? '' : m }) .replace(consecutiveNewlinesRE, '\n\n') + + return code }, } } + +const escapeRegexRE = /[-/\\^$*+?.()|[\]{}]/g +function escapeRegex(str: string): string { + return str.replace(escapeRegexRE, '\\$&') +} + +function unique(arr: T[]): T[] { + return Array.from(new Set(arr)) +}