Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
/nuxtPublic

fix(nuxt): invalidate module cache on composable export type changes#33671

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
Flo0806 wants to merge1 commit intonuxt:main
base:main
Choose a base branch
Loading
fromFlo0806:fix/composable-export-type-change-hmr
Open
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletionspackages/nuxt/src/imports/module.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -89,6 +89,69 @@ export default defineNuxtModule<Partial<ImportsOptions>>({
}

let ctx: Unimport
const viteServers = new Set<any>()

// Track all Vite servers (client + SSR)
nuxt.hook('vite:serverCreated', (server) => {
viteServers.add(server)
})

// Vite plugin to detect and handle export type changes BEFORE HMR
nuxt.hook('vite:configResolved', (viteConfig) => {
if (!viteConfig.plugins) { return }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Shouldnt we initialise the list here and push the plugin in anyway?

Copy link
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

viteConfig.plugins? I guess no. Because it isreadonly and thevite:configResolved hook is called after Vite's config resolution, which always includes a plugins array. The early return is defensive programming - ifplugins doesn't exist, something is fundamentally wrong with the Vite setup and we shouldn't proceed.

viteConfig.plugins.push({
name: 'nuxt:composables-hmr',
handleHotUpdate: async (hmrContext) => {
// Only handle composable files
if (!composablesDirs.some(dir => hmrContext.file.startsWith(dir + '/'))) {
return
}

// Get current imports to compare
const currentImports = await ctx.getImports()
const oldImports = currentImports.filter(i => i.from === hmrContext.file)

// Scan the updated file
const newImports = await scanDirExports([hmrContext.file], {
fileFilter: file => !isIgnored(file),
})

// Check if export type changed (default ↔ named)
let exportTypeChanged = false
for (const newImport of newImports) {
const oldImport = oldImports.find(i => (i.as || i.name) === (newImport.as || newImport.name))
if (oldImport && oldImport.name !== newImport.name) {
exportTypeChanged = true
break
}
}

Comment on lines +119 to +128

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

⚠️ Potential issue |🟠 Major

Detection misses default↔named switches when the alias changes

Line 120: if the export flips betweendefault and named while you also rename the symbol (e.g.export default function useKey()export function useKeyRenamed()),oldImport is never found soexportTypeChanged staysfalse. The module cache is left untouched and the original(…).default is not a function crash still reproduces. Please deriveexportTypeChanged from the presence of aname === 'default' entry before versus after (and only fall back to the alias comparison when that check is inconclusive) so we catch these alias-renaming cases as well. Otherwise the fix remains incomplete.

if (exportTypeChanged) {
// Invalidate module cache recursively in all Vite servers (client + SSR)
for (const server of viteServers) {
const visited = new Set()
const invalidateRecursively = (mod: any) => {
if (!mod || visited.has(mod)) { return }
visited.add(mod)
mod.importers.forEach((importer: any) => invalidateRecursively(importer))
server.moduleGraph.invalidateModule(mod)
}

const modules = server.moduleGraph.getModulesByFile(hmrContext.file)
if (modules) {
modules.forEach((mod: any) => invalidateRecursively(mod))
}
}

// Trigger full reload - the changed export type cannot be handled with HMR
hmrContext.server.ws.send({ type: 'full-reload', path: '*' })
return []
}

return
},
})
})

// initialise unimport only after all modules
// have had a chance to register their hooks
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp