fix(vite, webpack): omit magic keys when import of same name is detected (#18733)

This commit is contained in:
Daniel Roe 2023-02-03 03:55:58 -08:00 committed by GitHub
parent 5eaeb4f83d
commit 03d6737089
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 46 additions and 0 deletions

View File

@ -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"} ::ReadMore{link="/docs/getting-started/data-fetching"}
:: ::

View File

@ -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"} :ReadMore{link="/docs/getting-started/data-fetching"}
::LinkExample{link="/docs/examples/composables/use-fetch"} ::LinkExample{link="/docs/examples/composables/use-fetch"}

View File

@ -36,4 +36,8 @@ watch(count, (newCount) => {
</script> </script>
``` ```
::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"} :ReadMore{link="/docs/getting-started/data-fetching#uselazyasyncdata"}

View File

@ -40,4 +40,8 @@ watch(posts, (newPosts) => {
</script> </script>
``` ```
::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"} :ReadMore{link="/docs/getting-started/data-fetching#uselazyfetch"}

View File

@ -18,5 +18,9 @@ useState<T>(key: string, init?: () => T | Ref<T>): Ref<T>
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. 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"} ::ReadMore{link="/docs/getting-started/state-management"}
:: ::

View File

@ -7,6 +7,7 @@ import MagicString from 'magic-string'
import { hash } from 'ohash' import { hash } from 'ohash'
import type { CallExpression } from 'estree' import type { CallExpression } from 'estree'
import { parseQuery, parseURL } from 'ufo' import { parseQuery, parseURL } from 'ufo'
import { findStaticImports, parseStaticImport } from 'mlly'
export interface ComposableKeysOptions { export interface ComposableKeysOptions {
sourcemap: boolean sourcemap: boolean
@ -32,6 +33,7 @@ export const composableKeysPlugin = createUnplugin((options: ComposableKeysOptio
const { 0: script = code, index: codeIndex = 0 } = code.match(/(?<=<script[^>]*>)[\S\s.]*?(?=<\/script>)/) || { index: 0, 0: code } const { 0: script = code, index: codeIndex = 0 } = code.match(/(?<=<script[^>]*>)[\S\s.]*?(?=<\/script>)/) || { index: 0, 0: code }
const s = new MagicString(code) const s = new MagicString(code)
// https://github.com/unjs/unplugin/issues/90 // https://github.com/unjs/unplugin/issues/90
let imports: Set<string> | undefined
let count = 0 let count = 0
const relativeID = isAbsolute(id) ? relative(options.rootDir, id) : id const relativeID = isAbsolute(id) ? relative(options.rootDir, id) : id
walk(this.parse(script, { walk(this.parse(script, {
@ -44,6 +46,9 @@ export const composableKeysPlugin = createUnplugin((options: ComposableKeysOptio
const name = 'name' in node.callee && node.callee.name const name = 'name' in node.callee && node.callee.name
if (!name || !keyedFunctions.includes(name) || node.arguments.length >= 4) { return } if (!name || !keyedFunctions.includes(name) || node.arguments.length >= 4) { return }
imports = imports || detectImportNames(script)
if (imports.has(name)) { return }
switch (name) { switch (name) {
case 'useState': case 'useState':
if (node.arguments.length >= 2 || stringTypes.includes(node.arguments[0]?.type)) { return } 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<string>()
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
}