Skip to content

Commit bb8c343

Browse files
authored
fix: remove import specifiers with correct end offset (#162)
1 parent 54ed45e commit bb8c343

File tree

2 files changed

+47
-19
lines changed

2 files changed

+47
-19
lines changed

src/plugins/hydration.ts

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { genImport } from 'knitwork'
22
import MagicString from 'magic-string'
33
import { resolve } from 'node:path'
4-
import { parseSync, type ImportDeclaration } from 'oxc-parser'
4+
import { parseSync, type ImportDeclaration, type ImportDeclarationSpecifier, type ImportSpecifier } from 'oxc-parser'
55
import { createUnplugin } from 'unplugin'
66
import { distDir } from '../dirs'
77

@@ -31,23 +31,31 @@ export const InjectHydrationPlugin = createUnplugin(() => {
3131
const hasDefineComponent = DEFINE_COMPONENT_RE.test(code)
3232
const hasDefineNuxtComponent = DEFINE_NUXT_COMPONENT_RE.test(code)
3333

34-
const defineComponentImport = findImportSpecifier(imports as ImportDeclaration[], 'defineComponent', ['vue', '#imports'])
34+
const defineComponentImport = findImportSpecifier(
35+
imports,
36+
'defineComponent',
37+
['vue', '#imports'],
38+
(specifier, nextSpecifier) => {
39+
m.remove(
40+
specifier.start,
41+
nextSpecifier?.start ?? specifier.end,
42+
)
43+
},
44+
)
3545
const defineComponentAlias = defineComponentImport?.local.name || 'defineComponent'
36-
if (defineComponentImport) {
37-
m.remove(
38-
defineComponentImport.start,
39-
defineComponentImport.end,
40-
)
41-
}
4246

43-
const defineNuxtComponentImport = findImportSpecifier(imports as ImportDeclaration[], 'defineNuxtComponent', ['#app/composables/component', '#imports', '#app', 'nuxt/app'])
47+
const defineNuxtComponentImport = findImportSpecifier(
48+
imports,
49+
'defineNuxtComponent',
50+
['#app/composables/component', '#imports', '#app', 'nuxt/app'],
51+
(specifier, next) => {
52+
m.remove(
53+
specifier.start,
54+
next?.start ?? specifier.end,
55+
)
56+
},
57+
)
4458
const defineNuxtComponentAlias = defineNuxtComponentImport?.local.name || 'defineNuxtComponent'
45-
if (defineNuxtComponentImport) {
46-
m.remove(
47-
defineNuxtComponentImport.start,
48-
defineNuxtComponentImport.end,
49-
)
50-
}
5159

5260
const importsToAdd = new Set([
5361
hasDefineComponent
@@ -121,11 +129,24 @@ export const InjectHydrationPlugin = createUnplugin(() => {
121129
/**
122130
* Finds an import specifier for a given imported name from specified package names.
123131
*/
124-
function findImportSpecifier(importDecl: ImportDeclaration[], importedName: string, pkgNames: string | string[]) {
132+
function findImportSpecifier(
133+
importDecl: ImportDeclaration[],
134+
importedName: string,
135+
pkgNames: string | string[],
136+
callback?: (specifier: ImportSpecifier, nextSpecifier?: ImportDeclarationSpecifier) => void,
137+
) {
125138
const names = Array.isArray(pkgNames) ? pkgNames : [pkgNames]
126-
return importDecl.find(imp => names.includes(imp.source.value))?.specifiers.find((specifier) => {
127-
return specifier.type === 'ImportSpecifier' && specifier.imported.type === 'Identifier' && specifier.imported.name === importedName
128-
})
139+
const decl = importDecl.find(imp => names.includes(imp.source.value))
140+
if (!decl) {
141+
return
142+
}
143+
for (let i = 0; i < decl.specifiers.length; i++) {
144+
const specifier = decl.specifiers[i]!
145+
if (specifier.type === 'ImportSpecifier' && specifier.imported.type === 'Identifier' && specifier.imported.name === importedName) {
146+
callback?.(specifier, decl.specifiers[i + 1])
147+
return specifier
148+
}
149+
}
129150
}
130151

131152
function normalizePath(path: string) {

test/unit/hydration/vite-plugin.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ describe('InjectHydrationPlugin', () => {
9292
expect(result.code).not.toContain('import { defineNuxtComponent } from \'#imports\'')
9393
})
9494

95+
it('should replace defineComponent with correct offsets', async () => {
96+
const code = `import { useModel, defineComponent, createVNode } from '#imports'\n${exportDefineComponent}`
97+
const result = await modifyImportPluginTransform(code, 'test.ts')
98+
expect(result.code).toContain(importDefineComponent.trim())
99+
expect(result.code).toContain('import { useModel, createVNode } from \'#imports\'')
100+
})
101+
95102
it('should inject import if defineComponent is used but not imported', async () => {
96103
const code = `${exportDefineComponent}`
97104
const result = await modifyImportPluginTransform(code, 'test.ts')

0 commit comments

Comments
 (0)