mirror of
https://github.com/nuxt/nuxt.git
synced 2025-02-28 07:44:19 +00:00
refactor: build plugin with prop based approach
This commit is contained in:
parent
897b067e19
commit
91abe21fbf
@ -139,84 +139,84 @@ export default defineNuxtConfig({
|
||||
})
|
||||
```
|
||||
|
||||
Nuxt has reserved component prefixes that will handle this delayed hydration for you, that extend dynamic imports. By prefixing your component with `LazyVisible`, Nuxt will automatically handle your component and delay its hydration until it will be on screen.
|
||||
Nuxt has reserved component properties that will handle this delayed hydration for you, that extend dynamic imports. By using the `hydrate:visible` prop, Nuxt will automatically handle your component and delay its hydration until it will be on screen.
|
||||
|
||||
```vue [pages/index.vue]
|
||||
<template>
|
||||
<div>
|
||||
<LazyVisibleMyComponent />
|
||||
<LazyMyComponent hydrate:visible />
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
If you need the component to load as soon as possible, but not block the critical rendering path, you can use the `LazyIdle` prefix, which would handle your component's hydration whenever the browser goes idle.
|
||||
If you need the component to load as soon as possible, but not block the critical rendering path, you can use the `hdrate:idle` prop, which would handle your component's hydration whenever the browser goes idle.
|
||||
|
||||
```vue [pages/index.vue]
|
||||
<template>
|
||||
<div>
|
||||
<LazyIdleMyComponent />
|
||||
<LazyMyComponent hydrate:idle />
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
If you would like the component to load after certain events occur, like a click or a mouse over, you can use the `LazyEvent` prefix, which would only trigger the hydration when those events occur.
|
||||
If you would like the component to load after certain events occur, like a click or a mouse over, you can use the `hydrate:event` prop, which would only trigger the hydration when those events occur.
|
||||
|
||||
```vue [pages/index.vue]
|
||||
<template>
|
||||
<div>
|
||||
<LazyEventMyComponent />
|
||||
<LazyMyComponent hydrate:event />
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
If you would like to load the component when the window matches a media query, you can use the `LazyMedia` prefix:
|
||||
If you would like to load the component when the window matches a media query, you can use the `hydrate:media` prop:
|
||||
|
||||
```vue [pages/index.vue]
|
||||
<template>
|
||||
<div>
|
||||
<LazyMediaMyComponent />
|
||||
<LazyMyComponent hydrate:media />
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
If you would like to never hydrate a component, use the `LazyNever` prefix:
|
||||
If you would like to never hydrate a component, use the `hydrate:never` prop:
|
||||
|
||||
```vue [pages/index.vue]
|
||||
<template>
|
||||
<div>
|
||||
<LazyNeverMyComponent />
|
||||
<LazyMyComponent hydrate:never />
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
If you would like to hydrate a component after a certain amount of time, use the `LazyTime` prefix:
|
||||
If you would like to hydrate a component after a certain amount of time, use the `hydrate:time` prop:
|
||||
|
||||
```vue [pages/index.vue]
|
||||
<template>
|
||||
<div>
|
||||
<LazyTimeMyComponent />
|
||||
<LazyMyComponent hydrate:time />
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
If you would like to hydrate a component once a promise is fulfilled, use the `LazyPromise` prefix:
|
||||
If you would like to hydrate a component once a promise is fulfilled, use the `hydrate:promise` prefix:
|
||||
|
||||
```vue [pages/index.vue]
|
||||
<template>
|
||||
<div>
|
||||
<LazyPromiseMyComponent />
|
||||
<LazyMyComponent hydrate:promise />
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
Nuxt's delayed hydration system is highly flexible, allowing each developer to build upon it and implement their own hydration strategy.
|
||||
If you have highly specific hydration triggers that aren't covered by the default strategies, or you want to have conditional hydration, you can use the general purpose `LazyIf` prefix:
|
||||
If you have highly specific hydration triggers that aren't covered by the default strategies, or you want to have conditional hydration, you can use the general purpose `hydrate:if` prop:
|
||||
|
||||
```vue [pages/index.vue]
|
||||
<template>
|
||||
<div>
|
||||
<button @click="myFunction">Click me to start the custom hydration strategy</button>
|
||||
<LazyIfMyComponent :hydrate="myCondition" />
|
||||
<LazyMyComponent :hydrate:if="myCondition" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
@ -230,18 +230,18 @@ function myFunction() {
|
||||
|
||||
### Custom hydration triggers
|
||||
|
||||
If you would like to override the default hydration triggers when dealing with delayed hydration, like changing the timeout, the options for the intersection observer, or the events to trigger the hydration, you can do so by supplying a `hydrate` prop to your lazy components.
|
||||
If you would like to override the default hydration triggers when dealing with delayed hydration, like changing the timeout, the options for the intersection observer, or the events to trigger the hydration, you can do so by supplying a value to the respetive props of your lazy components.
|
||||
|
||||
```vue [pages/index.vue]
|
||||
<template>
|
||||
<div>
|
||||
<LazyIdleMyComponent :hydrate="3000" />
|
||||
<LazyVisibleMyComponent :hydrate="{threshold: 0.2}" />
|
||||
<LazyEventMyComponent :hydrate="['click','mouseover']" />
|
||||
<LazyMediaMyComponent hydrate="(max-width: 500px)" />
|
||||
<LazyIfMyComponent :hydrate="someCondition" />
|
||||
<LazyTimeMyComponent :hydrate="3000" />
|
||||
<LazyPromiseMyComponent :hydrate="promise" />
|
||||
<LazyMyComponent :hydrate:idle="3000" />
|
||||
<LazyMyComponent :hydrate:visible="{threshold: 0.2}" />
|
||||
<LazyMyComponent :hydrate:event="['click','mouseover']" />
|
||||
<LazyMyComponent hydrate:media="(max-width: 500px)" />
|
||||
<LazyMyComponent :hydrate:if="someCondition" />
|
||||
<LazyMyComponent :hydrate:time="3000" />
|
||||
<LazyMyComponent :hydrate:promise="promise" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -255,14 +255,6 @@ const promise = Promise.resolve(42)
|
||||
Read more about using `LazyMedia` components and the accepted values.
|
||||
::
|
||||
|
||||
::important
|
||||
If your components begin with a reserved delayed hydration prefix like Visible/Idle/Event, they will not have delayed hydration by default. This is made to ensure you have full control over all your components and prevent breaking dynamic imports for those components.
|
||||
|
||||
This also means you would need to explicitly add the prefix to those components for if you'd like for them to have delayed hydration.
|
||||
|
||||
For example, if you have a component named `IdleBar` and you'd like it to be delayed based on network idle time, you would need to use it like `<LazyIdleIdleBar>` and not `<LazyIdleBar>` to make it a delayed hydration component. Otherwise, it would be treated as a regular [dynamic import](/docs/guide/directory-structure/components#dynamic-imports)
|
||||
::
|
||||
|
||||
### Listening to hydration events
|
||||
|
||||
All delayed hydration components have a `@hydrated` event that is fired whenever they are hydrated. You can listen to this event to trigger some action that depends on the component:
|
||||
@ -270,7 +262,7 @@ All delayed hydration components have a `@hydrated` event that is fired whenever
|
||||
```vue [pages/index.vue]
|
||||
<template>
|
||||
<div>
|
||||
<LazyVisibleMyComponent @hydrated="onHydrate" />
|
||||
<LazyMyComponent hydrate:visible @hydrated="onHydrate" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -287,19 +279,19 @@ Delayed hydration has many performance benefits, but in order to gain the most o
|
||||
|
||||
1. Avoid delayed hydration components as much as possible for in-viewport content - delayed hydration is best for content that is not immediately available and requires some interaction to get to. If it is present on screen and is meant to be available for use immediately, using it as a normal component would provide better performance and loading times. Use this feature sparingly to avoid hurting the user experience, as there are only a few cases that warrant delayed hydration for on-screen content.
|
||||
|
||||
2. Delayed hydration with conditional rendering - when using `v-if` with delayed hydration components, note that `v-if` takes precedence. That means, the component will be hydrated when the `v-if` is truthy, as that will render exclusively on the client. If you need to render the component only when the condition is true, use a regular async component (`<LazyMyComponent />`) with a `v-if`. If you need it to hydrate when the condition is fulfilled, use a delayed hydration prefix with the `hydrate` prop.
|
||||
2. Delayed hydration with conditional rendering - when using `v-if` with delayed hydration components, note that `v-if` takes precedence. That means, the component will be hydrated when the `v-if` is truthy, as that will render exclusively on the client. If you need to render the component only when the condition is true, use a regular async component (`<LazyMyComponent />`) with a `v-if`. If you need it to hydrate when the condition is fulfilled, use a delayed hydration prop.
|
||||
|
||||
3. Delayed hydration with a shared state - when using multiple components (for example, in a `v-for`) with the same `v-model`, where some components might get hydrated before others (for example, progressively increasing media queries), if one of the components updates the model, note that it will trigger hydration for all components with that same model. That is because Vue's reactivity system triggers an update for all the parts of the app that depend on that state, forcing hydration in the process. Props are unaffected by this. Try to avoid multiple components with the same model if that is not an intended side effect.
|
||||
|
||||
4. Use each hydration strategy for its intended use case - each hydration strategy has built-in optimizations specifically designed for that strategy's purpose. Using them incorrectly could hurt performance and user experience. Examples include:
|
||||
|
||||
- Using `LazyIf` for always/never hydrated components (`:hydrate="true"`/`:hydrate="false"`) - you can use a regular component/`LazyNever` respectively, which would provide better performance for each use case. Keep `LazyIf` for components that could get hydrated, but might not get hydrated immediately.
|
||||
- Using `hydrate:if` for always/never hydrated components (`:hydrate:if="true"`/`:hydrate:if="false"`) - you can use a regular component/`hydrate:never` respectively, which would provide better performance for each use case. Keep `LazyIf` for components that could get hydrated, but might not get hydrated immediately.
|
||||
|
||||
- Using `LazyTime` as an alternative to `LazyIdle` - while these strategies share similarities, they are meant for different purposes. `LazyTime` is specifically designed to hydrate a component immediately after a certain amount of time has passed. `LazyIdle`, on the other hand, is meant to provide a limit for the browser to handle the hydration whenever it's idle. If you use `LazyTime` for idle-based hydration, the browser might handle the component's hydration while handling other, potentially more important components at the same time. This could slow down the hydration for all components being handled.
|
||||
- Using `hydrate:time` as an alternative to `hydrate:idle` - while these strategies share similarities, they are meant for different purposes. `hydrate:time` is specifically designed to hydrate a component immediately after a certain amount of time has passed. `hydrate:idle`, on the other hand, is meant to provide a limit for the browser to handle the hydration whenever it's idle. If you use `hydrate:time` for idle-based hydration, the browser might handle the component's hydration while handling other, potentially more important components at the same time. This could slow down the hydration for all components being handled.
|
||||
|
||||
- \[ADVANCED\] Using only `LazyIf` to manually implement existing hydration strategies - while an option, using only `LazyIf` in stead of relying on the built-in supported strategies could impact the overall memory consumption and performance.
|
||||
For example, in stead of handling promises manually and setting a boolean indicator for when the promise was fulfilled, which would then get passed to `LazyIf`, using `LazyPromise` directly would handle it without requiring another ref, reducing the complexity and the amount of work Vue's reactivity system would need to handle and track.
|
||||
Always remember that while `LazyIf` allows for implementation of custom, highly-tailored hydration strategies, it should mainly be used when either pure conditional hydration is required (for example, hydration of a component when a separate button is clicked), or when no built-in strategy matches your specific use case, due to the internal optimizations each existing hydration strategy has.
|
||||
- \[ADVANCED\] Using only `hydrate:if` to manually implement existing hydration strategies - while an option, using only `hydrate:if` in stead of relying on the built-in supported strategies could impact the overall memory consumption and performance.
|
||||
For example, in stead of handling promises manually and setting a boolean indicator for when the promise was fulfilled, which would then get passed to `hydrate:if`, using `hydrate:promise` directly would handle it without requiring another ref, reducing the complexity and the amount of work Vue's reactivity system would need to handle and track.
|
||||
Always remember that while `hydrate:if` allows for implementation of custom, highly-tailored hydration strategies, it should mainly be used when either pure conditional hydration is required (for example, hydration of a component when a separate button is clicked), or when no built-in strategy matches your specific use case, due to the internal optimizations each existing hydration strategy has.
|
||||
|
||||
## Direct Imports
|
||||
|
||||
|
@ -13,6 +13,7 @@ import { ComponentsChunkPlugin, IslandsTransformPlugin } from './plugins/islands
|
||||
import { TransformPlugin } from './plugins/transform'
|
||||
import { TreeShakeTemplatePlugin } from './plugins/tree-shake'
|
||||
import { ComponentNamePlugin } from './plugins/component-names'
|
||||
import { DelayedHydrationPlugin } from './plugins/delayed-hydration'
|
||||
|
||||
const isPureObjectOrString = (val: any) => (!Array.isArray(val) && typeof val === 'object') || typeof val === 'string'
|
||||
const isDirectory = (p: string) => { try { return statSync(p).isDirectory() } catch { return false } }
|
||||
@ -223,13 +224,17 @@ export default defineNuxtModule<ComponentsOptions>({
|
||||
addBuildPlugin(ClientFallbackAutoIdPlugin({ sourcemap: !!nuxt.options.sourcemap.server, rootDir: nuxt.options.rootDir }), { client: false })
|
||||
}
|
||||
|
||||
const clientDelayedComponentRuntime = await findPath(join(distDir, 'components/runtime/client-delayed-component')) ?? join(distDir, 'components/runtime/client-delayed-component')
|
||||
const sharedLoaderOptions = {
|
||||
getComponents,
|
||||
serverComponentRuntime,
|
||||
transform: typeof nuxt.options.components === 'object' && !Array.isArray(nuxt.options.components) ? nuxt.options.components.transform : undefined,
|
||||
experimentalComponentIslands: !!nuxt.options.experimental.componentIslands,
|
||||
clientDelayedComponentRuntime,
|
||||
}
|
||||
if (nuxt.options.experimental.delayedHydration) {
|
||||
addBuildPlugin(DelayedHydrationPlugin({ sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client }))
|
||||
}
|
||||
|
||||
addBuildPlugin(LoaderPlugin({ ...sharedLoaderOptions, sourcemap: !!nuxt.options.sourcemap.client, mode: 'client' }), { server: false })
|
||||
addBuildPlugin(LoaderPlugin({ ...sharedLoaderOptions, sourcemap: !!nuxt.options.sourcemap.server, mode: 'server' }), { client: false })
|
||||
|
||||
|
35
packages/nuxt/src/components/plugins/delayed-hydration.ts
Normal file
35
packages/nuxt/src/components/plugins/delayed-hydration.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { createUnplugin } from 'unplugin'
|
||||
import { logger } from '@nuxt/kit'
|
||||
import MagicString from 'magic-string'
|
||||
import { isVue } from '../../core/utils'
|
||||
|
||||
export const DelayedHydrationPlugin = (options: { sourcemap: boolean }) => createUnplugin(() => {
|
||||
const DELAYED_HYDRATION_RE = /<(?:Lazy([A-Z]\w*)|lazy-[\w-]+)\b([^>]+)hydrate:(\w+)(="([^"]+)")?([^>]*(?:(?<=\/)|>[\s\S]+?<\/Lazy[A-Z]\w*|lazy-[\w-]+))>/g
|
||||
const types = new Map([['time', 'Time'], ['promise', 'Promise'], ['if', 'If'], ['event', 'Event'], ['visible', 'Visible'], ['media', 'Media'], ['never', 'Never'], ['idle', 'Idle']])
|
||||
const correctVals = new Map([['time', 'number'], ['promise', 'Promise'], ['event', 'string | string[]'], ['visible', 'IntersectionObserverInit'], ['media', 'string'], ['idle', 'number']])
|
||||
return {
|
||||
name: 'nuxt:delayed-hydration',
|
||||
enforce: 'pre',
|
||||
transformInclude (id) {
|
||||
return isVue(id)
|
||||
},
|
||||
transform (code, id) {
|
||||
const s = new MagicString(code)
|
||||
s.replace(DELAYED_HYDRATION_RE, (_, comp, pre, type, selfOrValue, val, post) => {
|
||||
const shouldDefault = type !== 'if' && (val === 'true' || val === 'false')
|
||||
if (!types.has(type)) { logger.warn(`Unexpected hydration strategy \`${type}\` when parsing \`${_}\` in \`${id}\`, this will default to visibility. For custom strategies, please use \`v-hydrate:if\` in stead.`) }
|
||||
if (type === 'never' && selfOrValue) { logger.warn('`hydrate:never` does not accept any value. It is meant to be used as is, and the value will not affect its runtime behavior.') }
|
||||
if (shouldDefault) { logger.warn(`Invalid value `${val}` for \`hydrate:${type}\` when parsing \`${_}\` in \`${id}\`. The prop is not meant to be assigned a boolean, but used as is or given ${type === 'never' ? 'no value' : `a value of type \`${correctVals.get(type) ?? 'unknown'}\``}. This will not affect runtime behavior and the defaults will be used in stead.`) }
|
||||
return `<Lazy${types.get(type) ?? 'Visible'}${comp}${pre}${type == 'never' || shouldDefault ? '' : `:hydrate="${val}"`}${post}>`
|
||||
})
|
||||
if (s.hasChanged()) {
|
||||
return {
|
||||
code: s.toString(),
|
||||
map: options.sourcemap
|
||||
? s.generateMap({ hires: true })
|
||||
: undefined,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
@ -12,6 +12,7 @@ interface LoaderOptions {
|
||||
getComponents (): Component[]
|
||||
mode: 'server' | 'client'
|
||||
serverComponentRuntime: string
|
||||
clientDelayedComponentRuntime: string
|
||||
sourcemap?: boolean
|
||||
transform?: ComponentsOptions['transform']
|
||||
experimentalComponentIslands?: boolean
|
||||
@ -21,7 +22,6 @@ const REPLACE_COMPONENT_TO_DIRECT_IMPORT_RE = /(?<=[ (])_?resolveComponent\(\s*[
|
||||
export const LoaderPlugin = (options: LoaderOptions) => createUnplugin(() => {
|
||||
const exclude = options.transform?.exclude || []
|
||||
const include = options.transform?.include || []
|
||||
const clientDelayedComponentRuntime = resolve(distDir, 'components/runtime/client-delayed-component')
|
||||
const nuxt = tryUseNuxt()
|
||||
|
||||
return {
|
||||
@ -43,7 +43,6 @@ export const LoaderPlugin = (options: LoaderOptions) => createUnplugin(() => {
|
||||
const imports = new Set<string>()
|
||||
const map = new Map<Component, string>()
|
||||
const s = new MagicString(code)
|
||||
const nuxt = tryUseNuxt()
|
||||
// replace `_resolveComponent("...")` to direct import
|
||||
s.replace(REPLACE_COMPONENT_TO_DIRECT_IMPORT_RE, (full: string, lazy: string, modifier: string, name: string) => {
|
||||
const normalComponent = findComponent(components, name, options.mode)
|
||||
@ -85,31 +84,31 @@ export const LoaderPlugin = (options: LoaderOptions) => createUnplugin(() => {
|
||||
switch (modifier) {
|
||||
case 'Visible':
|
||||
case 'visible-':
|
||||
imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyIOComponent' }]))
|
||||
imports.add(genImport(options.clientDelayedComponentRuntime, [{ name: 'createLazyIOComponent' }]))
|
||||
identifier += '_delayedIO'
|
||||
imports.add(`const ${identifier} = createLazyIOComponent(${dynamicImport})`)
|
||||
break
|
||||
case 'Event':
|
||||
case 'event-':
|
||||
imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyEventComponent' }]))
|
||||
imports.add(genImport(options.clientDelayedComponentRuntime, [{ name: 'createLazyEventComponent' }]))
|
||||
identifier += '_delayedEvent'
|
||||
imports.add(`const ${identifier} = createLazyEventComponent(${dynamicImport})`)
|
||||
break
|
||||
case 'Idle':
|
||||
case 'idle-':
|
||||
imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyNetworkComponent' }]))
|
||||
imports.add(genImport(options.clientDelayedComponentRuntime, [{ name: 'createLazyNetworkComponent' }]))
|
||||
identifier += '_delayedNetwork'
|
||||
imports.add(`const ${identifier} = createLazyNetworkComponent(${dynamicImport})`)
|
||||
break
|
||||
case 'Media':
|
||||
case 'media-':
|
||||
imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyMediaComponent' }]))
|
||||
imports.add(genImport(options.clientDelayedComponentRuntime, [{ name: 'createLazyMediaComponent' }]))
|
||||
identifier += '_delayedMedia'
|
||||
imports.add(`const ${identifier} = createLazyMediaComponent(${dynamicImport})`)
|
||||
break
|
||||
case 'If':
|
||||
case 'if-':
|
||||
imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyIfComponent' }]))
|
||||
imports.add(genImport(options.clientDelayedComponentRuntime, [{ name: 'createLazyIfComponent' }]))
|
||||
identifier += '_delayedIf'
|
||||
imports.add(`const ${identifier} = createLazyIfComponent(${dynamicImport})`)
|
||||
break
|
||||
@ -121,13 +120,13 @@ export const LoaderPlugin = (options: LoaderOptions) => createUnplugin(() => {
|
||||
break
|
||||
case 'Time':
|
||||
case 'time-':
|
||||
imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyTimeComponent' }]))
|
||||
imports.add(genImport(options.clientDelayedComponentRuntime, [{ name: 'createLazyTimeComponent' }]))
|
||||
identifier += '_delayedTime'
|
||||
imports.add(`const ${identifier} = createLazyTimeComponent(${dynamicImport})`)
|
||||
break
|
||||
case 'Promise':
|
||||
case 'promise-':
|
||||
imports.add(genImport(clientDelayedComponentRuntime, [{ name: 'createLazyPromiseComponent' }]))
|
||||
imports.add(genImport(options.clientDelayedComponentRuntime, [{ name: 'createLazyPromiseComponent' }]))
|
||||
identifier += '_delayedPromise'
|
||||
imports.add(`const ${identifier} = createLazyPromiseComponent(${dynamicImport})`)
|
||||
break
|
||||
|
@ -117,22 +117,14 @@ export const componentsTypeTemplate = {
|
||||
]
|
||||
})
|
||||
const islandType = 'type IslandComponent<T extends DefineComponent> = T & DefineComponent<{}, {refresh: () => Promise<void>}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, SlotsType<{ fallback: { error: unknown } }>>'
|
||||
const delayedType = 'type DelayedComponent<T> = DefineComponent<{hydrate?: T},{},{},{},{},{},{},{hydrated: void}>'
|
||||
const delayedType = `type TypeWithDefault<T> = boolean | T\ntype HydrationStrategy = "idle" | "event" | "promise" | "if" | "visible" | "time" | "never"\ntype HydrationMap = { idle: number, event: string | string[], promise: Promise<unknown>, if: boolean | unknown, visible: IntersectionObserverInit, time: number, never: boolean }\ntype DelayedComponent<T extends DefineComponent> = T & DefineComponent<{[K in keyof HydrationMap as \`hydrate:$\{K}\`]?: TypeWithDefault<HydrationMap[K]>},{},{},{},{},{},{hydrated: void},{},{},{},{},{},{},{},{hydrate:{}}>`
|
||||
return `
|
||||
import type { DefineComponent, SlotsType } from 'vue'
|
||||
${nuxt.options.experimental.componentIslands ? islandType : ''}
|
||||
${nuxt.options.experimental.delayedHydration ? delayedType : ''}
|
||||
interface _GlobalComponents {
|
||||
${componentTypes.map(([pascalName, type]) => ` '${pascalName}': ${type}`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => ` 'Lazy${pascalName}': ${type}`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => ` 'LazyIdle${pascalName}': ${type} & DelayedComponent<number>`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => ` 'LazyTime${pascalName}': ${type} & DelayedComponent<number>`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => ` 'LazyPromise${pascalName}': ${type} & DelayedComponent<Promise<unknown>>`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => ` 'LazyVisible${pascalName}': ${type} & DelayedComponent<IntersectionObserverInit>`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => ` 'LazyEvent${pascalName}': ${type} & DelayedComponent<keyof HTMLElementEventMap | Array<keyof HTMLElementEventMap>>`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => ` 'LazyMedia${pascalName}': ${type} & DelayedComponent<string>`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => ` 'LazyIf${pascalName}': ${type} & DelayedComponent<unknown>`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => ` 'LazyNever${pascalName}': ${type}`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => ` 'Lazy${pascalName}': DelayedComponent<${type}>`).join('\n')}
|
||||
}
|
||||
|
||||
declare module 'vue' {
|
||||
@ -140,15 +132,7 @@ declare module 'vue' {
|
||||
}
|
||||
|
||||
${componentTypes.map(([pascalName, type]) => `export const ${pascalName}: ${type}`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => `export const Lazy${pascalName}: ${type}`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => `export const LazyIdle${pascalName}: ${type} & DelayedComponent<number>`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => `export const LazyTime${pascalName}: ${type} & DelayedComponent<number>`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => `export const LazyPromise${pascalName}: ${type} & DelayedComponent<Promise<unknown>>`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => `export const LazyVisible${pascalName}: ${type} & DelayedComponent<IntersectionObserverInit>`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => `export const LazyEvent${pascalName}: ${type} & DelayedComponent<keyof HTMLElementEventMap | Array<keyof HTMLElementEventMap>>`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => `export const LazyMedia${pascalName}: ${type} & DelayedComponent<string>`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => `export const LazyIf${pascalName}: ${type} & DelayedComponent<unknown>`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => `export const LazyNever${pascalName}: ${type}`).join('\n')}
|
||||
${componentTypes.map(([pascalName, type]) => `export const Lazy${pascalName}: DelayedComponent<${type}>`).join('\n')}
|
||||
|
||||
export const componentNames: string[]
|
||||
`
|
||||
|
@ -3,28 +3,34 @@
|
||||
<LazyNCompAll message="lazy-named-comp-all" />
|
||||
<LazyNCompClient message="lazy-named-comp-client" />
|
||||
<LazyNCompServer message="lazy-named-comp-server" />
|
||||
<LazyEventDelayedEvent id="lazyevent" />
|
||||
<LazyEventView />
|
||||
<LazyVisibleDelayedVisible />
|
||||
<LazyNeverDelayedNever />
|
||||
<LazyEventDelayedEvent
|
||||
id="lazyevent2"
|
||||
:hydrate="createEventLoader(['click'])"
|
||||
<LazyDelayedEvent
|
||||
id="lazyevent"
|
||||
hydrate:event
|
||||
/>
|
||||
<LazyEventView />
|
||||
<LazyDelayedVisible hydrate:visible />
|
||||
<LazyDelayedNever hydrate:never />
|
||||
<LazyDelayedEvent
|
||||
id="lazyevent2"
|
||||
:hydrate:event="['click']"
|
||||
/>
|
||||
<LazyDelayedCondition
|
||||
id="lazycondition"
|
||||
hydrate:if
|
||||
/>
|
||||
<LazyIfDelayedCondition id="lazycondition" />
|
||||
<button
|
||||
id="conditionbutton"
|
||||
@click="state++"
|
||||
/>
|
||||
<LazyIfDelayedCondition
|
||||
<LazyDelayedCondition
|
||||
id="lazycondition2"
|
||||
:hydrate="state > 1"
|
||||
:hydrate:if="state > 1"
|
||||
/>
|
||||
<LazyIdleDelayedNetwork />
|
||||
<LazyDelayedNetwork hydrate:idle />
|
||||
<div style="height:3000px">
|
||||
This is a very tall div
|
||||
</div>
|
||||
<LazyVisibleDelayedVisible />
|
||||
<LazyDelayedVisible hydrate:visible />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<LazyEventDelayedModel
|
||||
<LazyDelayedModel
|
||||
hydrate:event
|
||||
v-model="model"
|
||||
@hydrated="log"
|
||||
/>
|
||||
|
@ -5,11 +5,11 @@ const prImmediate = Promise.resolve(42)
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<LazyPromiseDelayedPromise
|
||||
:hydrate="pr"
|
||||
<LazyDelayedPromise
|
||||
:hydrate:promise="pr"
|
||||
/>
|
||||
<LazyPromiseDelayedPromise
|
||||
:hydrate="prImmediate"
|
||||
<LazyDelayedPromise
|
||||
:hydrate:promise="prImmediate"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<LazyTimeDelayedTime />
|
||||
<LazyTimeDelayedTime
|
||||
:hydrate="500"
|
||||
<LazyDelayedTime hydrate:time />
|
||||
<LazyDelayedTime
|
||||
:hydrate:time="500"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
Loading…
Reference in New Issue
Block a user