diff --git a/README.md b/README.md index 9aaf358c..f3b867f8 100644 --- a/README.md +++ b/README.md @@ -465,6 +465,17 @@ Components({ types: [ /* ... */ ], + + // Save component information into a JSON file for other tools to consume. + // Provide a filepath to save the JSON file. + // When set to `true`, it will save to `./.components-info.json` + dumpComponentsInfo: false, + + // The mode for syncing the components.d.ts and .components-info.json file. + // 'append': only append the new components to the existing files. + // 'overwrite': overwrite the whole existing files with the current components. + // 'default': use 'append' strategy when using dev server, 'overwrite' strategy when using build. + syncMode: 'default', }) ``` diff --git a/src/core/context.ts b/src/core/context.ts index 5f5e04a1..3cc91bbf 100644 --- a/src/core/context.ts +++ b/src/core/context.ts @@ -29,6 +29,7 @@ export class Context { private _componentUsageMap: Record> = {} private _componentCustomMap: Record = {} private _directiveCustomMap: Record = {} + private _removeUnused = false private _server: ViteDevServer | undefined root = process.cwd() @@ -42,6 +43,7 @@ export class Context { this.options = resolveOptions(rawOptions, this.root) this.sourcemap = rawOptions.sourcemap ?? true this.generateDeclaration = throttle(500, this._generateDeclaration.bind(this), { noLeading: false }) + this._removeUnused = this.options.syncMode === 'overwrite' if (this.options.dumpComponentsInfo) { const dumpComponentsInfo = this.options.dumpComponentsInfo === true @@ -78,6 +80,7 @@ export class Context { return this._server = server + this._removeUnused = this.options.syncMode !== 'append' this.setupWatcher(server.watcher) } @@ -299,7 +302,7 @@ export class Context { this._searched = true } - _generateDeclaration(removeUnused = !this._server) { + _generateDeclaration(removeUnused = this._removeUnused) { if (!this.options.dts) return @@ -307,11 +310,11 @@ export class Context { return writeDeclaration(this, this.options.dts, removeUnused) } - generateDeclaration(removeUnused = !this._server): void { + generateDeclaration(removeUnused = this._removeUnused): void { this._generateDeclaration(removeUnused) } - _generateComponentsJson(removeUnused = !this._server) { + _generateComponentsJson(removeUnused = this._removeUnused) { if (!Object.keys(this._componentNameMap).length) return @@ -319,7 +322,7 @@ export class Context { return writeComponentsJson(this, removeUnused) } - generateComponentsJson(removeUnused = !this._server): void { + generateComponentsJson(removeUnused = this._removeUnused): void { this._generateComponentsJson(removeUnused) } diff --git a/src/core/options.ts b/src/core/options.ts index 699062bc..b55c06a8 100644 --- a/src/core/options.ts +++ b/src/core/options.ts @@ -25,6 +25,7 @@ export const defaultOptions: Omit, 'include' | 'exclude' | 'ex sourcemap: true, dumpComponentsInfo: false, + syncMode: 'default', prefix: '', } diff --git a/src/types.ts b/src/types.ts index bce2a70c..3f1cb578 100644 --- a/src/types.ts +++ b/src/types.ts @@ -220,6 +220,16 @@ export interface Options { * @default false */ dumpComponentsInfo?: boolean | string + + /** + * The mode for syncing the components.d.ts and .components-info.json file. + * - `append`: only append the new components to the existing files. + * - `overwrite`: overwrite the whole existing files with the current components. + * - `default`: use `append` strategy when using dev server, `overwrite` strategy when using build. + * + * @default 'default' + */ + syncMode?: 'default' | 'append' | 'overwrite' } export type ResolvedOptions = Omit< diff --git a/test/__snapshots__/dts.test.ts.snap b/test/__snapshots__/dts.test.ts.snap index 1359bad0..19a4dc66 100644 --- a/test/__snapshots__/dts.test.ts.snap +++ b/test/__snapshots__/dts.test.ts.snap @@ -150,7 +150,7 @@ declare module 'vue' { " `; -exports[`dts > writeDeclaration - keep unused 1`] = ` +exports[`dts > writeDeclaration - append 1`] = ` "/* eslint-disable */ // @ts-nocheck // Generated by unplugin-vue-components @@ -175,6 +175,28 @@ declare module 'vue' { " `; +exports[`dts > writeDeclaration - overwrite 1`] = ` +"/* eslint-disable */ +// @ts-nocheck +// Generated by unplugin-vue-components +// Read more: https://github.com/vuejs/core/pull/3399 +// biome-ignore lint: disable +export {} + +/* prettier-ignore */ +declare module 'vue' { + export interface GlobalComponents { + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + TestComp: typeof import('test/component/TestComp')['default'] + } + export interface GlobalDirectives { + vLoading: typeof import('test/directive/Loading')['default'] + } +} +" +`; + exports[`dts > writeDeclaration 1`] = ` "/* eslint-disable */ // @ts-nocheck diff --git a/test/dts.test.ts b/test/dts.test.ts index aa8715d1..35f0e064 100644 --- a/test/dts.test.ts +++ b/test/dts.test.ts @@ -48,8 +48,8 @@ const _directive_loading = _resolveDirective("loading")` expect(await readFile(filepath, 'utf-8')).matchSnapshot() }) - it('writeDeclaration - keep unused', async () => { - const filepath = path.resolve(__dirname, 'tmp/dts-keep-unused.d.ts') + it.each(['append', 'overwrite'] as const)('writeDeclaration - %s', async (syncMode) => { + const filepath = path.resolve(__dirname, 'tmp/dts-test-sync-mode.d.ts') await writeFile( filepath, ` @@ -70,18 +70,16 @@ declare module 'vue' { resolvers: resolver, directives: true, dts: filepath, + syncMode, }) const code = ` const _component_test_comp = _resolveComponent("test-comp") const _directive_loading = _resolveDirective("loading")` await ctx.transform(code, '') - await ctx._generateDeclaration(false) + await ctx._generateDeclaration() const contents = await readFile(filepath, 'utf-8') expect(contents).matchSnapshot() - expect(contents).not.toContain('OldComp') - expect(contents).not.toContain('comment') - expect(contents).toContain('vSome') }) it('components only', async () => {