Skip to content

Commit 35ac99a

Browse files
authored
fix: search through all matching import declaration for findImportSpecifier (#167)
1 parent dee4f82 commit 35ac99a

File tree

2 files changed

+38
-10
lines changed

2 files changed

+38
-10
lines changed

src/plugins/hydration.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,13 @@ export const InjectHydrationPlugin = createUnplugin(() => {
127127

128128
/**
129129
* Finds an import specifier for a given imported name from specified package names.
130+
* Searches through all matching import declarations since there can be multiple imports from the same package.
131+
*
132+
* Like
133+
* ```ts
134+
* import { ref } from 'vue'
135+
* import { defineComponent } from 'vue'
136+
* ```
130137
*/
131138
function findImportSpecifier(
132139
importDecl: ImportDeclaration[],
@@ -135,16 +142,18 @@ function findImportSpecifier(
135142
callback?: (specifier: ImportSpecifier, nextSpecifier?: ImportDeclarationSpecifier) => void,
136143
) {
137144
const names = Array.isArray(pkgNames) ? pkgNames : [pkgNames]
138-
const decl = importDecl.find(imp => names.includes(imp.source.value))
139-
if (!decl) {
140-
return
141-
}
142-
for (let i = 0; i < decl.specifiers.length; i++) {
143-
const specifier = decl.specifiers[i]!
144-
if (specifier.type === 'ImportSpecifier' && specifier.imported.type === 'Identifier' && specifier.imported.name === importedName) {
145-
callback?.(specifier, decl.specifiers[i + 1])
146-
return specifier
147-
}
145+
146+
const allSpecifiers = importDecl
147+
.filter(imp => names.includes(imp.source.value))
148+
.flatMap(decl => decl.specifiers.map((spec, i) => ({ spec, next: decl.specifiers[i + 1] })))
149+
150+
const match = allSpecifiers.find(({ spec }) =>
151+
spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier' && spec.imported.name === importedName,
152+
)
153+
154+
if (match) {
155+
callback?.(match.spec as ImportSpecifier, match.next)
156+
return match.spec as ImportSpecifier
148157
}
149158
}
150159

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,25 @@ describe('InjectHydrationPlugin', () => {
130130
))
131131
expect(result.code).not.toContain(`import { defineNuxtComponent as _defineNuxtComponent } from '#app'`)
132132
})
133+
134+
it('should find defineComponent when split across multiple import declarations', async () => {
135+
const code = `import { ref } from 'vue'\nimport { defineComponent } from 'vue'\n${exportDefineComponent}`
136+
const result = await modifyImportPluginTransform(code, 'test.ts')
137+
expect(result.code).toContain(importDefineComponent.trim())
138+
expect(result.code).not.toContain(`import { defineComponent } from 'vue'`)
139+
expect(result.code).toContain(`import { ref } from 'vue'`)
140+
})
141+
142+
it('should find aliased defineComponent when split across multiple import declarations', async () => {
143+
const code = `import { ref } from 'vue'\nimport { defineComponent as _defineComponent } from 'vue'\nexport default _defineComponent({})`
144+
const result = await modifyImportPluginTransform(code, 'test.ts')
145+
expect(result.code).toContain(genImport(
146+
'@nuxt/hints/runtime/hydration/component',
147+
[{ name: 'defineComponent', as: '_defineComponent' }],
148+
))
149+
expect(result.code).not.toContain(`import { defineComponent as _defineComponent } from 'vue'`)
150+
expect(result.code).toContain(`import { ref } from 'vue'`)
151+
})
133152
})
134153

135154
describe('inject-hydration-composable', () => {

0 commit comments

Comments
 (0)