mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 13:45:18 +00:00
feat(nuxt3): support lazy and custom-resolved components (#3814)
This commit is contained in:
parent
7458dd1aa6
commit
29078bba74
@ -47,6 +47,39 @@ If you have a component in nested directories such as:
|
|||||||
For clarity, we recommend that the component's file name matches its name. (So, in the example above, you could rename `Button.vue` to be `BaseFooButton.vue`.)
|
For clarity, we recommend that the component's file name matches its name. (So, in the example above, you could rename `Button.vue` to be `BaseFooButton.vue`.)
|
||||||
::
|
::
|
||||||
|
|
||||||
|
## Dynamic components
|
||||||
|
|
||||||
|
If you want to use the Vue `<component :is="someComputedComponent">` syntax, then you will need to use the `resolveComponent` helper provided by Vue.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<component :is="clickable ? MyButton : 'div'" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const MyButton = resolveComponent('MyButton')
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, though not recommended, you can register all your components globally, which will create async chunks for all your components and make them available throughout your application.
|
||||||
|
|
||||||
|
```diff
|
||||||
|
import { defineNuxtConfig } from 'nuxt3'
|
||||||
|
|
||||||
|
export default defineNuxtConfig({
|
||||||
|
components: {
|
||||||
|
+ global: true,
|
||||||
|
+ dirs: ['~/components']
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
::alert{type=info}
|
||||||
|
The `global` option can also be set per component directory.
|
||||||
|
::
|
||||||
|
|
||||||
## Dynamic Imports
|
## Dynamic Imports
|
||||||
|
|
||||||
To dynamically import a component (also known as lazy-loading a component) all you need to do is add the `Lazy` prefix to the component's name.
|
To dynamically import a component (also known as lazy-loading a component) all you need to do is add the `Lazy` prefix to the component's name.
|
||||||
|
@ -104,6 +104,7 @@ export const vuePreset = defineUnimportPreset({
|
|||||||
// Component
|
// Component
|
||||||
'defineComponent',
|
'defineComponent',
|
||||||
'defineAsyncComponent',
|
'defineAsyncComponent',
|
||||||
|
'resolveComponent',
|
||||||
'getCurrentInstance',
|
'getCurrentInstance',
|
||||||
'h',
|
'h',
|
||||||
'inject',
|
'inject',
|
||||||
|
@ -2,7 +2,7 @@ import { pathToFileURL } from 'url'
|
|||||||
import { createUnplugin } from 'unplugin'
|
import { createUnplugin } from 'unplugin'
|
||||||
import { parseQuery, parseURL } from 'ufo'
|
import { parseQuery, parseURL } from 'ufo'
|
||||||
import { Component } from '@nuxt/schema'
|
import { Component } from '@nuxt/schema'
|
||||||
import { genImport } from 'knitwork'
|
import { genDynamicImport, genImport } from 'knitwork'
|
||||||
import MagicString from 'magic-string'
|
import MagicString from 'magic-string'
|
||||||
import { pascalCase } from 'scule'
|
import { pascalCase } from 'scule'
|
||||||
|
|
||||||
@ -37,13 +37,19 @@ function transform (code: string, id: string, components: Component[]) {
|
|||||||
const s = new MagicString(code)
|
const s = new MagicString(code)
|
||||||
|
|
||||||
// replace `_resolveComponent("...")` to direct import
|
// replace `_resolveComponent("...")` to direct import
|
||||||
s.replace(/ _resolveComponent\("(.*?)"\)/g, (full, name) => {
|
s.replace(/(?<=[ (])_?resolveComponent\(["'](lazy-|Lazy)?([^'"]*?)["']\)/g, (full, lazy, name) => {
|
||||||
const component = findComponent(components, name)
|
const component = findComponent(components, name)
|
||||||
if (component) {
|
if (component) {
|
||||||
const identifier = map.get(component) || `__nuxt_component_${num++}`
|
const identifier = map.get(component) || `__nuxt_component_${num++}`
|
||||||
map.set(component, identifier)
|
map.set(component, identifier)
|
||||||
imports.add(genImport(component.filePath, [{ name: component.export, as: identifier }]))
|
if (lazy) {
|
||||||
return ` ${identifier}`
|
// Nuxt will auto-import `defineAsyncComponent` for us
|
||||||
|
imports.add(`const ${identifier}_lazy = defineAsyncComponent(${genDynamicImport(component.filePath)})`)
|
||||||
|
return `${identifier}_lazy`
|
||||||
|
} else {
|
||||||
|
imports.add(genImport(component.filePath, [{ name: component.export, as: identifier }]))
|
||||||
|
return identifier
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// no matched
|
// no matched
|
||||||
return full
|
return full
|
||||||
|
@ -51,6 +51,7 @@ export const componentsTypeTemplate = {
|
|||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
${options.components.map(c => ` '${c.pascalName}': typeof ${genDynamicImport(isAbsolute(c.filePath) ? relative(join(options.buildDir, 'types'), c.filePath) : c.filePath, { wrapper: false })}['${c.export}']`).join(',\n')}
|
${options.components.map(c => ` '${c.pascalName}': typeof ${genDynamicImport(isAbsolute(c.filePath) ? relative(join(options.buildDir, 'types'), c.filePath) : c.filePath, { wrapper: false })}['${c.export}']`).join(',\n')}
|
||||||
|
${options.components.map(c => ` 'Lazy${c.pascalName}': typeof ${genDynamicImport(isAbsolute(c.filePath) ? relative(join(options.buildDir, 'types'), c.filePath) : c.filePath, { wrapper: false })}['${c.export}']`).join(',\n')}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export {}
|
export {}
|
||||||
|
@ -9,6 +9,8 @@ export default {
|
|||||||
* @see [Nuxt 3](https://v3.nuxtjs.org/docs/directory-structure/components) and
|
* @see [Nuxt 3](https://v3.nuxtjs.org/docs/directory-structure/components) and
|
||||||
* [Nuxt 2](https://nuxtjs.org/docs/directory-structure/components/) documentation
|
* [Nuxt 2](https://nuxtjs.org/docs/directory-structure/components/) documentation
|
||||||
* @type {boolean | typeof import('../src/types/components').ComponentsOptions | typeof import('../src/types/components').ComponentsOptions['dirs']}
|
* @type {boolean | typeof import('../src/types/components').ComponentsOptions | typeof import('../src/types/components').ComponentsOptions['dirs']}
|
||||||
|
* @version 2
|
||||||
|
* @version 3
|
||||||
*/
|
*/
|
||||||
components: {
|
components: {
|
||||||
$resolve: (val, get) => {
|
$resolve: (val, get) => {
|
||||||
@ -27,6 +29,7 @@ export default {
|
|||||||
*
|
*
|
||||||
* @see [Nuxt 3 documentation](https://v3.nuxtjs.org/docs/directory-structure/composables)
|
* @see [Nuxt 3 documentation](https://v3.nuxtjs.org/docs/directory-structure/composables)
|
||||||
* @type {typeof import('../src/types/imports').AutoImportsOptions}
|
* @type {typeof import('../src/types/imports').AutoImportsOptions}
|
||||||
|
* @version 3
|
||||||
*/
|
*/
|
||||||
autoImports: {
|
autoImports: {
|
||||||
global: false,
|
global: false,
|
||||||
|
Loading…
Reference in New Issue
Block a user