diff --git a/docs/3.api/1.composables/use-async-data.md b/docs/3.api/1.composables/use-async-data.md index c0de175710..47e8fc5f3f 100644 --- a/docs/3.api/1.composables/use-async-data.md +++ b/docs/3.api/1.composables/use-async-data.md @@ -80,5 +80,9 @@ const { data, pending, error, refresh } = await useAsyncData( ) ``` +::alert{type=warning} +`useAsyncData` is a reserved function name transformed by the compiler, so you should not name your own function `useAsyncData`. +:: + ::ReadMore{link="/docs/getting-started/data-fetching"} :: diff --git a/docs/3.api/1.composables/use-fetch.md b/docs/3.api/1.composables/use-fetch.md index e3c6039d6d..fb61ad4649 100644 --- a/docs/3.api/1.composables/use-fetch.md +++ b/docs/3.api/1.composables/use-fetch.md @@ -122,6 +122,10 @@ const { data, pending, error, refresh } = await useFetch('/api/auth/login', { }) ``` +::alert{type=warning} +`useFetch` is a reserved function name transformed by the compiler, so you should not name your own function `useFetch`. +:: + :ReadMore{link="/docs/getting-started/data-fetching"} ::LinkExample{link="/docs/examples/composables/use-fetch"} diff --git a/docs/3.api/1.composables/use-lazy-async-data.md b/docs/3.api/1.composables/use-lazy-async-data.md index 9fee43cf90..0180dbe7b0 100644 --- a/docs/3.api/1.composables/use-lazy-async-data.md +++ b/docs/3.api/1.composables/use-lazy-async-data.md @@ -36,4 +36,8 @@ watch(count, (newCount) => { ``` +::alert{type=warning} +`useLazyAsyncData` is a reserved function name transformed by the compiler, so you should not name your own function `useLazyAsyncData`. +:: + :ReadMore{link="/docs/getting-started/data-fetching#uselazyasyncdata"} diff --git a/docs/3.api/1.composables/use-lazy-fetch.md b/docs/3.api/1.composables/use-lazy-fetch.md index 3cbf849699..f910cf2746 100644 --- a/docs/3.api/1.composables/use-lazy-fetch.md +++ b/docs/3.api/1.composables/use-lazy-fetch.md @@ -40,4 +40,8 @@ watch(posts, (newPosts) => { ``` +::alert{type=warning} +`useLazyFetch` is a reserved function name transformed by the compiler, so you should not name your own function `useLazyFetch`. +:: + :ReadMore{link="/docs/getting-started/data-fetching#uselazyfetch"} diff --git a/docs/3.api/1.composables/use-state.md b/docs/3.api/1.composables/use-state.md index 4d25efca37..6939fcea0a 100644 --- a/docs/3.api/1.composables/use-state.md +++ b/docs/3.api/1.composables/use-state.md @@ -18,5 +18,9 @@ useState(key: string, init?: () => T | Ref): Ref Because the data inside `useState` will be serialized to JSON, it is important that it does not contain anything that cannot be serialized, such as classes, functions or symbols. :: +::alert{type=warning} +`useState` is a reserved function name transformed by the compiler, so you should not name your own function `useState`. +:: + ::ReadMore{link="/docs/getting-started/state-management"} :: diff --git a/packages/vite/src/plugins/composable-keys.ts b/packages/vite/src/plugins/composable-keys.ts index 41cb8cf592..4489078407 100644 --- a/packages/vite/src/plugins/composable-keys.ts +++ b/packages/vite/src/plugins/composable-keys.ts @@ -7,6 +7,7 @@ import MagicString from 'magic-string' import { hash } from 'ohash' import type { CallExpression } from 'estree' import { parseQuery, parseURL } from 'ufo' +import { findStaticImports, parseStaticImport } from 'mlly' export interface ComposableKeysOptions { sourcemap: boolean @@ -32,6 +33,7 @@ export const composableKeysPlugin = createUnplugin((options: ComposableKeysOptio const { 0: script = code, index: codeIndex = 0 } = code.match(/(?<=]*>)[\S\s.]*?(?=<\/script>)/) || { index: 0, 0: code } const s = new MagicString(code) // https://github.com/unjs/unplugin/issues/90 + let imports: Set | undefined let count = 0 const relativeID = isAbsolute(id) ? relative(options.rootDir, id) : id walk(this.parse(script, { @@ -44,6 +46,9 @@ export const composableKeysPlugin = createUnplugin((options: ComposableKeysOptio const name = 'name' in node.callee && node.callee.name if (!name || !keyedFunctions.includes(name) || node.arguments.length >= 4) { return } + imports = imports || detectImportNames(script) + if (imports.has(name)) { return } + switch (name) { case 'useState': if (node.arguments.length >= 2 || stringTypes.includes(node.arguments[0]?.type)) { return } @@ -80,3 +85,24 @@ export const composableKeysPlugin = createUnplugin((options: ComposableKeysOptio } } }) + +const NUXT_IMPORT_RE = /nuxt|#app|#imports/ + +function detectImportNames (code: string) { + const imports = findStaticImports(code) + const names = new Set() + for (const i of imports) { + if (NUXT_IMPORT_RE.test(i.specifier)) { continue } + const { namedImports, defaultImport, namespacedImport } = parseStaticImport(i) + for (const name in namedImports || {}) { + names.add(namedImports![name]) + } + if (defaultImport) { + names.add(defaultImport) + } + if (namespacedImport) { + names.add(namespacedImport) + } + } + return names +}