diff --git a/napi/angular-compiler/README.md b/napi/angular-compiler/README.md index 1e4d74d7c..bf36c0083 100644 --- a/napi/angular-compiler/README.md +++ b/napi/angular-compiler/README.md @@ -286,7 +286,7 @@ type-checking against your library. ```typescript // vite.config.ts — Angular library build import { angular } from '@oxc-angular/vite' -import dts from 'rolldown-plugin-dts' // or vite-plugin-dts / tsdown +import { dts } from 'rolldown-plugin-dts' export default defineConfig({ plugins: [angular({ compilationMode: 'partial' }), dts()], @@ -295,11 +295,16 @@ export default defineConfig({ ``` The plugin does **not** generate the base `.d.ts` itself — a declaration -generator (`rolldown-plugin-dts`, `vite-plugin-dts`, `tsdown`, or `tsc`) must -produce them. The Angular members are then spliced into those files during -`generateBundle`. The injected members reference `i0` (the `@angular/core` -namespace), and the plugin adds `import * as i0 from "@angular/core";` to any -`.d.ts` it augments. +generator must produce them in the bundle, as `rolldown-plugin-dts` and +`tsdown` (`dts: true`) do. The Angular members are then spliced into those +files during `generateBundle`. The injected members reference `i0` (the +`@angular/core` namespace), and the plugin adds +`import * as i0 from "@angular/core";` to any `.d.ts` it augments. + +Declarations written outside the bundle are not augmented: `vite-plugin-dts` +and `tsc` write their files themselves, and tsdown builds the `.d.cts` of a +`cjs` format in a separate pass without user plugins. Use `format: 'esm'` with +tsdown. ## Vite Plugin Architecture diff --git a/napi/angular-compiler/test/dts.test.ts b/napi/angular-compiler/test/dts.test.ts index 3337a997a..762fa369b 100644 --- a/napi/angular-compiler/test/dts.test.ts +++ b/napi/angular-compiler/test/dts.test.ts @@ -526,6 +526,48 @@ describe('angular() dts plugin (#104)', () => { expect(out).toContain('static ɵcmp: i0.ɵɵComponentDeclaration { + const { transform, dts } = getPlugins('partial') + await runTransform(transform) + + const js = 'export class LibButtonComponent {}\n' + const bundle = { + 'index.d.mts': { + type: 'chunk' as const, + fileName: 'index.d.mts', + code: 'export declare class LibButtonComponent {\n}\n', + }, + 'index.mjs': { type: 'chunk' as const, fileName: 'index.mjs', code: js }, + } + await runGenerateBundle(dts, bundle) + + const out = bundle['index.d.mts'].code + expect(out).toContain('import * as i0 from "@angular/core";') + expect(out).toContain('static ɵfac: i0.ɵɵFactoryDeclaration { + const { transform, dts } = getPlugins('partial') + await runTransform(transform) + + // The shape rolldown-plugin-dts gives a chunk shared by several entries. + const bundle = { + 'shared-abc.d.mts': { + type: 'chunk' as const, + fileName: 'shared-abc.d.mts', + code: 'declare class LibButtonComponent {\n}\nexport { LibButtonComponent as t };\n', + }, + } + await runGenerateBundle(dts, bundle) + + const out = bundle['shared-abc.d.mts'].code + expect(out).toContain('import * as i0 from "@angular/core";') + expect(out).toContain('static ɵcmp: i0.ɵɵComponentDeclaration { const { transform, dts } = getPlugins('full') await runTransform(transform) diff --git a/napi/angular-compiler/vite-plugin/index.ts b/napi/angular-compiler/vite-plugin/index.ts index 0b4230fef..c49d0e203 100644 --- a/napi/angular-compiler/vite-plugin/index.ts +++ b/napi/angular-compiler/vite-plugin/index.ts @@ -1777,16 +1777,25 @@ export function angular(options: PluginOptions = {}): Plugin[] { const declarations = Array.from(byClassName.values()) for (const file of Object.values(bundle)) { - if (file.type !== 'asset') continue if (!/\.d\.[cm]?ts$/.test(file.fileName)) continue - const source = - typeof file.source === 'string' - ? file.source - : Buffer.from(file.source).toString('utf-8') + // rolldown-plugin-dts (and so tsdown) emits declarations as + // chunks; generators that call `emitFile` emit them as assets. + let source: string + if (file.type === 'chunk') { + source = file.code + } else { + source = + typeof file.source === 'string' + ? file.source + : Buffer.from(file.source).toString('utf-8') + } const augmented = injectDtsDeclarations(source, declarations) - if (augmented !== source) { + if (augmented === source) continue + if (file.type === 'chunk') { + file.code = augmented + } else { file.source = augmented } }