diff --git a/examples/ts/src/dynamic.ts b/examples/ts/src/dynamic.ts new file mode 100644 index 0000000..12cf4f6 --- /dev/null +++ b/examples/ts/src/dynamic.ts @@ -0,0 +1,3 @@ +export interface DynamicImportType { + a: number +} diff --git a/examples/ts/src/dynamic2.ts b/examples/ts/src/dynamic2.ts new file mode 100644 index 0000000..d3801a7 --- /dev/null +++ b/examples/ts/src/dynamic2.ts @@ -0,0 +1,3 @@ +export interface DynamicImportType2 { + a: number +} diff --git a/examples/ts/src/index.ts b/examples/ts/src/index.ts index 98dfba6..a9fa206 100644 --- a/examples/ts/src/index.ts +++ b/examples/ts/src/index.ts @@ -2,6 +2,9 @@ import data from './data.json' import type { TestBase } from '@/test' +export const dy: import('./dynamic').DynamicImportType = { a: 1 } +export const dy1: import('./dynamic2').DynamicImportType2 = { a: 1 } + export interface Test extends TestBase { count: number } diff --git a/examples/ts/vite.config.ts b/examples/ts/vite.config.ts index 0121229..816d289 100644 --- a/examples/ts/vite.config.ts +++ b/examples/ts/vite.config.ts @@ -27,8 +27,11 @@ export default defineConfig({ // aliasesExclude: [/^@components/], staticImport: true, // insertTypesEntry: true, - rollupTypes: true, - declarationOnly: true + rollupTypes: false, + declarationOnly: true, + compilerOptions: { + declarationMap: true + } }) ] }) diff --git a/examples/vue/components/BothScripts.vue b/examples/vue/components/BothScripts.vue index e3af182..29bc9d5 100644 --- a/examples/vue/components/BothScripts.vue +++ b/examples/vue/components/BothScripts.vue @@ -30,7 +30,7 @@ defineExpose({ inc }) export interface BothScriptsProps { /** comment */ - tag: string + tag: string, count: number } diff --git a/examples/vue/package.json b/examples/vue/package.json index 9b317a5..0b6880d 100644 --- a/examples/vue/package.json +++ b/examples/vue/package.json @@ -5,7 +5,7 @@ "private": true, "scripts": { "build": "DEBUG=\"vite-plugin-dts:bundle\" vite build", - "tsc": "vue-tsc --declaration --emitDeclarationOnly --outDir tsc-dist" + "tsc": "vue-tsc --declaration --emitDeclarationOnly --declarationMap --outDir tsc-dist" }, "dependencies": { "vue": "^3.4.32" diff --git a/src/plugin.ts b/src/plugin.ts index 76f74ad..83cd230 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -543,15 +543,31 @@ export function dtsPlugin(options: PluginOptions = {}): import('vite').Plugin { bundleDebug('emit output patch') const currentDir = host.getCurrentDirectory() + const declarationFiles = new Map() + const mapFiles = new Map() + const prependMappings = new Map() + + for (const [filePath, content] of outputFiles.entries()) { + if (filePath.endsWith('.map')) { + mapFiles.set(filePath, content) + } else { + declarationFiles.set(filePath, content) + } + } await runParallel( cpus().length, - Array.from(outputFiles.entries()), + Array.from(declarationFiles.entries()), async ([filePath, content]) => { - const isMapFile = filePath.endsWith('.map') - const baseDir = dirname(filePath) + const newFilePath = resolve( + outDir, + relative( + entryRoot, + cleanVueFileName ? filePath.replace('.vue.d.ts', '.d.ts') : filePath + ) + ) - if (!isMapFile && content) { + if (content) { const result = transformCode({ filePath, content, @@ -564,8 +580,22 @@ export function dtsPlugin(options: PluginOptions = {}): import('vite').Plugin { content = result.content declareModules.push(...result.declareModules) + + if (result.diffLineCount) { + prependMappings.set(`${newFilePath}.map`, ';'.repeat(result.diffLineCount)) + } } + await writeOutput(newFilePath, content, outDir) + } + ) + + await runParallel( + cpus().length, + Array.from(mapFiles.entries()), + async ([filePath, content]) => { + const baseDir = dirname(filePath) + filePath = resolve( outDir, relative( @@ -574,22 +604,25 @@ export function dtsPlugin(options: PluginOptions = {}): import('vite').Plugin { ) ) - if (isMapFile) { - try { - const sourceMap: { sources: string[] } = JSON.parse(content) + try { + const sourceMap: { sources: string[], mappings: string } = JSON.parse(content) - sourceMap.sources = sourceMap.sources.map(source => { - return normalizePath( - relative( - dirname(filePath), - resolve(currentDir, relative(publicRoot, baseDir), source) - ) + sourceMap.sources = sourceMap.sources.map(source => { + return normalizePath( + relative( + dirname(filePath), + resolve(currentDir, relative(publicRoot, baseDir), source) ) - }) - content = JSON.stringify(sourceMap) - } catch (e) { - logger.warn(`${logPrefix} ${yellow('Processing source map fail:')} ${filePath}`) + ) + }) + + if (prependMappings.has(filePath)) { + sourceMap.mappings = `${prependMappings.get(filePath)}${sourceMap.mappings}` } + + content = JSON.stringify(sourceMap) + } catch (e) { + logger.warn(`${logPrefix} ${yellow('Processing source map fail:')} ${filePath}`) } await writeOutput(filePath, content, outDir) diff --git a/src/transform.ts b/src/transform.ts index 0215981..fb53dfe 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -105,11 +105,13 @@ export function transformCode(options: { } let indexCount = 0 + let importCount = 0 walkSourceFile(ast, (node, parent) => { if (ts.isImportDeclaration(node)) { if (!node.importClause) { options.clearPureImport && s.remove(node.pos, node.end) + ++importCount } else if ( ts.isStringLiteral(node.moduleSpecifier) && (node.importClause.name || @@ -137,6 +139,7 @@ export function transformCode(options: { } s.remove(node.pos, node.end) + ++importCount } return false @@ -234,11 +237,13 @@ export function transformCode(options: { prependImports += `import { ${Array.from(importSet).join(', ')} } from '${libName}';\n` }) - s.prepend(prependImports) + s.trimStart('\n').prepend(prependImports) return { content: s.toString(), - declareModules + declareModules, + diffLineCount: + importMap.size && importCount < importMap.size ? importMap.size - importCount : null } } diff --git a/tests/transform.spec.ts b/tests/transform.spec.ts index c0f470a..2ff8fa3 100644 --- a/tests/transform.spec.ts +++ b/tests/transform.spec.ts @@ -68,7 +68,7 @@ describe('transform tests', () => { expect( transformCode(options('import { Type } from "./test";\nconst test: import("./test").Test;')) .content - ).toEqual("import { Type, Test } from './test';\n\nconst test: Test;") + ).toEqual("import { Type, Test } from './test';\nconst test: Test;") expect( transformCode(options("const a: import('foo').A<{ b: import('foo').B }>"))