mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 00:23:53 +00:00
wip
This commit is contained in:
parent
03058b5132
commit
3b51e4a148
@ -75,6 +75,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
emits: ['error'],
|
emits: ['error'],
|
||||||
async setup (props, { slots, expose, emit }) {
|
async setup (props, { slots, expose, emit }) {
|
||||||
|
console.log(slots.default?.toString())
|
||||||
let canTeleport = import.meta.server
|
let canTeleport = import.meta.server
|
||||||
const teleportKey = ref(0)
|
const teleportKey = ref(0)
|
||||||
const key = ref(0)
|
const key = ref(0)
|
||||||
|
@ -34,7 +34,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
// if there's already a teleport parent, we don't need to teleport or to render the wrapped component client side
|
// if there's already a teleport parent, we don't need to teleport or to render the wrapped component client side
|
||||||
if (!nuxtApp.ssrContext?.islandContext || !props.nuxtClient || inject(NuxtTeleportIslandSymbol, false)) { return () => slots.default?.() }
|
if (!nuxtApp.ssrContext?.islandContext || !props.nuxtClient || inject(NuxtTeleportIslandSymbol, false)) { return () => slots.default?.() }
|
||||||
|
|
||||||
provide(NuxtTeleportIslandSymbol, props.to)
|
provide(NuxtTeleportIslandSymbol, props.to)
|
||||||
const islandContext = nuxtApp.ssrContext!.islandContext!
|
const islandContext = nuxtApp.ssrContext!.islandContext!
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import type { VNode } from 'vue'
|
import type { VNode } from 'vue'
|
||||||
import { Teleport, createVNode, defineComponent, h, inject } from 'vue'
|
import { Teleport, createVNode, defineComponent, h, inject } from 'vue'
|
||||||
|
import consola from 'consola'
|
||||||
import { useNuxtApp } from '../nuxt'
|
import { useNuxtApp } from '../nuxt'
|
||||||
import { NuxtTeleportIslandSymbol } from './nuxt-teleport-island-component'
|
import { NuxtTeleportIslandSymbol } from './nuxt-teleport-island-component'
|
||||||
|
|
||||||
@ -20,10 +21,12 @@ export default defineComponent({
|
|||||||
*/
|
*/
|
||||||
props: {
|
props: {
|
||||||
type: Object as () => Array<any>,
|
type: Object as () => Array<any>,
|
||||||
|
default: () => [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup (props, { slots }) {
|
setup (props, { slots }) {
|
||||||
const nuxtApp = useNuxtApp()
|
const nuxtApp = useNuxtApp()
|
||||||
|
console.log(slots.default?.toString())
|
||||||
const islandContext = nuxtApp.ssrContext?.islandContext
|
const islandContext = nuxtApp.ssrContext?.islandContext
|
||||||
if (!islandContext) {
|
if (!islandContext) {
|
||||||
return () => slots.default?.()[0]
|
return () => slots.default?.()[0]
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
import { h } from 'vue'
|
import { createVNode, h } from 'vue'
|
||||||
import type { Component, RendererNode } from 'vue'
|
import type { Component, DefineComponent, RendererNode, VNode, renderSlot } from 'vue'
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
import { isString, isPromise, isArray, isObject } from '@vue/shared'
|
import { isString, isPromise, isArray, isObject } from '@vue/shared'
|
||||||
import type { RouteLocationNormalized } from 'vue-router'
|
import type { RouteLocationNormalized } from 'vue-router'
|
||||||
|
import NuxtTeleportIslandSlot from './nuxt-teleport-island-slot'
|
||||||
|
import NuxtTeleportClient from './nuxt-teleport-island-component'
|
||||||
|
import { useNuxtApp } from '#app'
|
||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
import { START_LOCATION } from '#build/pages'
|
import { START_LOCATION } from '#build/pages'
|
||||||
|
|
||||||
@ -155,3 +158,74 @@ function isStartFragment (element: RendererNode) {
|
|||||||
function isEndFragment (element: RendererNode) {
|
function isEndFragment (element: RendererNode) {
|
||||||
return element.nodeName === '#comment' && element.nodeValue === ']'
|
return element.nodeName === '#comment' && element.nodeValue === ']'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert a component to wrap all slots with a teleport
|
||||||
|
*/
|
||||||
|
export function withIslandTeleport (component: DefineComponent) {
|
||||||
|
if (import.meta.client) { return component }
|
||||||
|
return {
|
||||||
|
...component,
|
||||||
|
render: renderForIsland(component.render),
|
||||||
|
setup: setupForIsland(component.setup),
|
||||||
|
} as DefineComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* export
|
||||||
|
*/
|
||||||
|
|
||||||
|
function renderForIsland (render: any) {
|
||||||
|
if (!render) { return undefined }
|
||||||
|
|
||||||
|
return (ctx, _cache, $props, $setup, $data, $options) => {
|
||||||
|
|
||||||
|
const _ctx = {
|
||||||
|
...ctx,
|
||||||
|
$slots: {
|
||||||
|
...ctx.$slots,
|
||||||
|
...Object.keys(ctx.$slots).reduce((acc, key) => {
|
||||||
|
acc[key] = (...args: any) => {
|
||||||
|
return h(NuxtTeleportIslandSlot, {
|
||||||
|
name: key,
|
||||||
|
props: [args],
|
||||||
|
}, { default: () => ctx.$slots[key]?.(...args) })
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}, {}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for (const key in ctx.$slots) {
|
||||||
|
ctx.$slots[key] = (...args: any) => {
|
||||||
|
return h(NuxtTeleportIslandSlot, {
|
||||||
|
name: key,
|
||||||
|
props: [args],
|
||||||
|
}, { default: () => ctx.$slots[key]?.(...args) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('renderForIsland', _ctx, ctx, $setup)
|
||||||
|
return render(_ctx, _cache, $props, $setup, $data, $options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupForIsland (setup: (props, ctx) => any) {
|
||||||
|
if(!setup) { return}
|
||||||
|
return (props, ctx) => {
|
||||||
|
// const slots = Object.keys(ctx.slots).reduce((acc, key) => {
|
||||||
|
|
||||||
|
// return Object.assign(acc, {[key]: (...args: any) => {
|
||||||
|
// return createVNode(NuxtTeleportIslandSlot, {
|
||||||
|
// name: key,
|
||||||
|
// }, { default: () => ctx.slots[key]?.(...args) })
|
||||||
|
// }})
|
||||||
|
// }, {})
|
||||||
|
for(const key in ctx.slots) {
|
||||||
|
ctx.slots[key] = (...args: any) => {
|
||||||
|
return createVNode(NuxtTeleportIslandSlot, {
|
||||||
|
name: key,
|
||||||
|
}, { default: () => ctx.slots[key]?.(...args) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return setup?.(props, ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -71,31 +71,7 @@ export const islandsTransform = createUnplugin((options: ServerOnlyComponentTran
|
|||||||
const ast = parse(template[0])
|
const ast = parse(template[0])
|
||||||
await walk(ast, (node) => {
|
await walk(ast, (node) => {
|
||||||
if (node.type === ELEMENT_NODE) {
|
if (node.type === ELEMENT_NODE) {
|
||||||
if (node.name === 'slot') {
|
if (options.selectiveClient && ('nuxt-client' in node.attributes || ':nuxt-client' in node.attributes)) {
|
||||||
const { attributes, children, loc } = node
|
|
||||||
|
|
||||||
const slotName = attributes.name ?? 'default'
|
|
||||||
|
|
||||||
if (attributes.name) { delete attributes.name }
|
|
||||||
if (attributes['v-bind']) {
|
|
||||||
attributes._bind = extractAttributes(attributes, ['v-bind'])['v-bind']
|
|
||||||
}
|
|
||||||
const teleportAttributes = extractAttributes(attributes, ['v-if', 'v-else-if', 'v-else'])
|
|
||||||
const bindings = getPropsToString(attributes)
|
|
||||||
// add the wrapper
|
|
||||||
s.appendLeft(startingIndex + loc[0].start, `<NuxtTeleportSsrSlot${attributeToString(teleportAttributes)} name="${slotName}" :props="${bindings}">`)
|
|
||||||
|
|
||||||
if (children.length) {
|
|
||||||
// pass slot fallback to NuxtTeleportSsrSlot fallback
|
|
||||||
const attrString = attributeToString(attributes)
|
|
||||||
const slice = code.slice(startingIndex + loc[0].end, startingIndex + loc[1].start).replaceAll(/:?key="[^"]"/g, '')
|
|
||||||
s.overwrite(startingIndex + loc[0].start, startingIndex + loc[1].end, `<slot${attrString.replaceAll(EXTRACTED_ATTRS_RE, '')}/><template #fallback>${attributes['v-for'] ? wrapWithVForDiv(slice, attributes['v-for']) : slice}</template>`)
|
|
||||||
} else {
|
|
||||||
s.overwrite(startingIndex + loc[0].start, startingIndex + loc[0].end, code.slice(startingIndex + loc[0].start, startingIndex + loc[0].end).replaceAll(EXTRACTED_ATTRS_RE, ''))
|
|
||||||
}
|
|
||||||
|
|
||||||
s.appendRight(startingIndex + loc[1].end, '</NuxtTeleportSsrSlot>')
|
|
||||||
} else if (options.selectiveClient && ('nuxt-client' in node.attributes || ':nuxt-client' in node.attributes)) {
|
|
||||||
hasNuxtClient = true
|
hasNuxtClient = true
|
||||||
const { loc, attributes } = node
|
const { loc, attributes } = node
|
||||||
const attributeValue = attributes[':nuxt-client'] || attributes['nuxt-client'] || 'true'
|
const attributeValue = attributes[':nuxt-client'] || attributes['nuxt-client'] || 'true'
|
||||||
|
@ -41,6 +41,7 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => {
|
|||||||
const imports = new Set<string>()
|
const imports = new Set<string>()
|
||||||
const map = new Map<Component, string>()
|
const map = new Map<Component, string>()
|
||||||
const s = new MagicString(code)
|
const s = new MagicString(code)
|
||||||
|
imports.add(genImport(resolve(distDir, 'app/components/utils'), [{ name: 'withIslandTeleport' }]))
|
||||||
|
|
||||||
// replace `_resolveComponent("...")` to direct import
|
// replace `_resolveComponent("...")` to direct import
|
||||||
s.replace(/(?<=[ (])_?resolveComponent\(\s*["'](lazy-|Lazy(?=[A-Z]))?([^'"]*)["'][^)]*\)/g, (full: string, lazy: string, name: string) => {
|
s.replace(/(?<=[ (])_?resolveComponent\(\s*["'](lazy-|Lazy(?=[A-Z]))?([^'"]*)["'][^)]*\)/g, (full: string, lazy: string, name: string) => {
|
||||||
@ -59,6 +60,8 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => {
|
|||||||
if (isServerOnly) {
|
if (isServerOnly) {
|
||||||
imports.add(genImport(serverComponentRuntime, [{ name: 'createServerComponent' }]))
|
imports.add(genImport(serverComponentRuntime, [{ name: 'createServerComponent' }]))
|
||||||
imports.add(`const ${identifier} = createServerComponent(${JSON.stringify(component.pascalName)})`)
|
imports.add(`const ${identifier} = createServerComponent(${JSON.stringify(component.pascalName)})`)
|
||||||
|
imports.add(`const ${identifier}_converted = withIslandTeleport(${identifier})`)
|
||||||
|
identifier += '_converted'
|
||||||
if (!options.experimentalComponentIslands) {
|
if (!options.experimentalComponentIslands) {
|
||||||
logger.warn(`Standalone server components (\`${name}\`) are not yet supported without enabling \`experimental.componentIslands\`.`)
|
logger.warn(`Standalone server components (\`${name}\`) are not yet supported without enabling \`experimental.componentIslands\`.`)
|
||||||
}
|
}
|
||||||
@ -70,13 +73,14 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => {
|
|||||||
imports.add(genImport('#app/components/client-only', [{ name: 'createClientOnly' }]))
|
imports.add(genImport('#app/components/client-only', [{ name: 'createClientOnly' }]))
|
||||||
identifier += '_client'
|
identifier += '_client'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lazy) {
|
if (lazy) {
|
||||||
imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }]))
|
imports.add(genImport('vue', [{ name: 'defineAsyncComponent', as: '__defineAsyncComponent' }]))
|
||||||
identifier += '_lazy'
|
identifier += '_lazy'
|
||||||
imports.add(`const ${identifier} = __defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => c.${component.export ?? 'default'} || c)${isClientOnly ? '.then(c => createClientOnly(c))' : ''})`)
|
imports.add(`const ${identifier} = __defineAsyncComponent(${genDynamicImport(component.filePath, { interopDefault: false })}.then(c => withIslandTeleport(c.${component.export ?? 'default'} || c))${isClientOnly ? '.then(c => createClientOnly(c))' : ''})`)
|
||||||
} else {
|
} else {
|
||||||
imports.add(genImport(component.filePath, [{ name: component._raw ? 'default' : component.export, as: identifier }]))
|
imports.add(genImport(component.filePath, [{ name: component._raw ? 'default' : component.export, as: identifier }]))
|
||||||
|
imports.add(`const ${identifier}_converted = withIslandTeleport(${identifier})`)
|
||||||
|
identifier += '_converted'
|
||||||
|
|
||||||
if (isClientOnly) {
|
if (isClientOnly) {
|
||||||
imports.add(`const ${identifier}_wrapped = createClientOnly(${identifier})`)
|
imports.add(`const ${identifier}_wrapped = createClientOnly(${identifier})`)
|
||||||
|
@ -238,9 +238,9 @@ export default defineNuxtModule<ComponentsOptions>({
|
|||||||
|
|
||||||
if (nuxt.options.experimental.componentIslands) {
|
if (nuxt.options.experimental.componentIslands) {
|
||||||
const selectiveClient = typeof nuxt.options.experimental.componentIslands === 'object' && nuxt.options.experimental.componentIslands.selectiveClient
|
const selectiveClient = typeof nuxt.options.experimental.componentIslands === 'object' && nuxt.options.experimental.componentIslands.selectiveClient
|
||||||
|
writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), 'export const paths = {}')
|
||||||
|
|
||||||
if (isClient && selectiveClient) {
|
if (isClient && selectiveClient) {
|
||||||
writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), 'export const paths = {}')
|
|
||||||
if (!nuxt.options.dev) {
|
if (!nuxt.options.dev) {
|
||||||
config.plugins.push(componentsChunkPlugin.vite({
|
config.plugins.push(componentsChunkPlugin.vite({
|
||||||
getComponents,
|
getComponents,
|
||||||
|
@ -2,6 +2,7 @@ import { defineComponent, getCurrentInstance, h, ref } from 'vue'
|
|||||||
import NuxtIsland from '#app/components/nuxt-island'
|
import NuxtIsland from '#app/components/nuxt-island'
|
||||||
import { useRoute } from '#app/composables/router'
|
import { useRoute } from '#app/composables/router'
|
||||||
import { isPrerendered } from '#app/composables/payload'
|
import { isPrerendered } from '#app/composables/payload'
|
||||||
|
import { withIslandTeleport } from '#app/components/utils'
|
||||||
|
|
||||||
/* @__NO_SIDE_EFFECTS__ */
|
/* @__NO_SIDE_EFFECTS__ */
|
||||||
export const createServerComponent = (name: string) => {
|
export const createServerComponent = (name: string) => {
|
||||||
@ -17,9 +18,9 @@ export const createServerComponent = (name: string) => {
|
|||||||
expose({
|
expose({
|
||||||
refresh: () => islandRef.value?.refresh(),
|
refresh: () => islandRef.value?.refresh(),
|
||||||
})
|
})
|
||||||
|
console.log(slots.default?.toString())
|
||||||
return () => {
|
return () => {
|
||||||
return h(NuxtIsland, {
|
return h( withIslandTeleport(NuxtIsland), {
|
||||||
name,
|
name,
|
||||||
lazy: props.lazy,
|
lazy: props.lazy,
|
||||||
props: attrs,
|
props: attrs,
|
||||||
|
@ -33,6 +33,7 @@ import type { NuxtPayload, NuxtSSRContext } from '#app'
|
|||||||
import { appHead, appId, appRootAttrs, appRootTag, appTeleportAttrs, appTeleportTag, componentIslands, multiApp } from '#internal/nuxt.config.mjs'
|
import { appHead, appId, appRootAttrs, appRootTag, appTeleportAttrs, appTeleportTag, componentIslands, multiApp } from '#internal/nuxt.config.mjs'
|
||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
import { buildAssetsURL, publicAssetsURL } from '#internal/nuxt/paths'
|
import { buildAssetsURL, publicAssetsURL } from '#internal/nuxt/paths'
|
||||||
|
import consola from 'consola'
|
||||||
|
|
||||||
// @ts-expect-error private property consumed by vite-generated url helpers
|
// @ts-expect-error private property consumed by vite-generated url helpers
|
||||||
globalThis.__buildAssetsURL = buildAssetsURL
|
globalThis.__buildAssetsURL = buildAssetsURL
|
||||||
@ -473,6 +474,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
|||||||
// TODO: remove for v4
|
// TODO: remove for v4
|
||||||
islandHead.link = islandHead.link || []
|
islandHead.link = islandHead.link || []
|
||||||
islandHead.style = islandHead.style || []
|
islandHead.style = islandHead.style || []
|
||||||
|
consola.log('teleports', ssrContext.teleports)
|
||||||
|
|
||||||
const islandResponse: NuxtIslandResponse = {
|
const islandResponse: NuxtIslandResponse = {
|
||||||
id: islandContext.id,
|
id: islandContext.id,
|
||||||
@ -655,7 +657,7 @@ function getServerComponentHTML (body: string): string {
|
|||||||
|
|
||||||
const SSR_SLOT_TELEPORT_MARKER = /^uid=([^;]*);slot=(.*)$/
|
const SSR_SLOT_TELEPORT_MARKER = /^uid=([^;]*);slot=(.*)$/
|
||||||
const SSR_CLIENT_TELEPORT_MARKER = /^uid=([^;]*);client=(.*)$/
|
const SSR_CLIENT_TELEPORT_MARKER = /^uid=([^;]*);client=(.*)$/
|
||||||
const SSR_CLIENT_SLOT_MARKER = /^island-slot=[^;]*;(.*)$/
|
const SSR_CLIENT_SLOT_MARKER = /^island-slot=[^;]*$/
|
||||||
|
|
||||||
function getSlotIslandResponse (ssrContext: NuxtSSRContext): NuxtIslandResponse['slots'] {
|
function getSlotIslandResponse (ssrContext: NuxtSSRContext): NuxtIslandResponse['slots'] {
|
||||||
if (!ssrContext.islandContext || !Object.keys(ssrContext.islandContext.slots).length) { return undefined }
|
if (!ssrContext.islandContext || !Object.keys(ssrContext.islandContext.slots).length) { return undefined }
|
||||||
@ -668,11 +670,12 @@ function getSlotIslandResponse (ssrContext: NuxtSSRContext): NuxtIslandResponse[
|
|||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
const logger = consola
|
||||||
|
|
||||||
|
logger.wrapConsole()
|
||||||
function getClientIslandResponse (ssrContext: NuxtSSRContext): NuxtIslandResponse['components'] {
|
function getClientIslandResponse (ssrContext: NuxtSSRContext): NuxtIslandResponse['components'] {
|
||||||
if (!ssrContext.islandContext || !Object.keys(ssrContext.islandContext.components).length) { return undefined }
|
if (!ssrContext.islandContext || !Object.keys(ssrContext.islandContext.components).length) { return undefined }
|
||||||
const response: NuxtIslandResponse['components'] = {}
|
const response: NuxtIslandResponse['components'] = {}
|
||||||
|
|
||||||
for (const clientUid in ssrContext.islandContext.components) {
|
for (const clientUid in ssrContext.islandContext.components) {
|
||||||
// remove teleport anchor to avoid hydration issues
|
// remove teleport anchor to avoid hydration issues
|
||||||
const html = ssrContext.teleports?.[clientUid].replaceAll('<!--teleport start anchor-->', '') || ''
|
const html = ssrContext.teleports?.[clientUid].replaceAll('<!--teleport start anchor-->', '') || ''
|
||||||
@ -688,7 +691,6 @@ function getClientIslandResponse (ssrContext: NuxtSSRContext): NuxtIslandRespons
|
|||||||
function getComponentSlotTeleport (teleports: Record<string, string>) {
|
function getComponentSlotTeleport (teleports: Record<string, string>) {
|
||||||
const entries = Object.entries(teleports)
|
const entries = Object.entries(teleports)
|
||||||
const slots: Record<string, string> = {}
|
const slots: Record<string, string> = {}
|
||||||
|
|
||||||
for (const [key, value] of entries) {
|
for (const [key, value] of entries) {
|
||||||
const match = key.match(SSR_CLIENT_SLOT_MARKER)
|
const match = key.match(SSR_CLIENT_SLOT_MARKER)
|
||||||
if (match) {
|
if (match) {
|
||||||
|
1
test/fixtures/basic/nuxt.config.ts
vendored
1
test/fixtures/basic/nuxt.config.ts
vendored
@ -238,6 +238,7 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
features: {
|
features: {
|
||||||
|
devLogs: false,
|
||||||
inlineStyles: id => !!id && !id.includes('assets.vue'),
|
inlineStyles: id => !!id && !id.includes('assets.vue'),
|
||||||
},
|
},
|
||||||
experimental: {
|
experimental: {
|
||||||
|
93
test/fixtures/basic/pages/islands.vue
vendored
93
test/fixtures/basic/pages/islands.vue
vendored
@ -1,4 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
const islandProps = ref({
|
const islandProps = ref({
|
||||||
bool: true,
|
bool: true,
|
||||||
number: 100,
|
number: 100,
|
||||||
@ -15,102 +16,14 @@ const count = ref(0)
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
Pure island component:
|
Pure island component:
|
||||||
<div class="box">
|
|
||||||
<NuxtIsland
|
|
||||||
name="PureComponent"
|
|
||||||
:props="islandProps"
|
|
||||||
/>
|
|
||||||
<div id="wrapped-client-only">
|
|
||||||
<ClientOnly>
|
|
||||||
<NuxtIsland
|
|
||||||
name="PureComponent"
|
|
||||||
:props="islandProps"
|
|
||||||
/>
|
|
||||||
</ClientOnly>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
id="increase-pure-component"
|
|
||||||
@click="islandProps.number++"
|
|
||||||
>
|
|
||||||
Increase
|
|
||||||
</button>
|
|
||||||
<hr>
|
|
||||||
Route island component:
|
|
||||||
<div
|
|
||||||
v-if="routeIslandVisible"
|
|
||||||
class="box"
|
|
||||||
>
|
|
||||||
<NuxtIsland
|
|
||||||
name="RouteComponent"
|
|
||||||
:context="{ url: '/test' }"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
v-else
|
|
||||||
id="show-route"
|
|
||||||
@click="routeIslandVisible = true"
|
|
||||||
>
|
|
||||||
Show
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<p>async .server component</p>
|
|
||||||
<AsyncServerComponent :count="count">
|
<AsyncServerComponent :count="count">
|
||||||
<div id="slot-in-server">
|
<div id="slot-in-server">
|
||||||
Slot with in .server component
|
Slot with in .server component
|
||||||
</div>
|
</div>
|
||||||
</AsyncServerComponent>
|
</AsyncServerComponent>
|
||||||
<div>
|
|
||||||
Async component (1000ms):
|
|
||||||
<div>
|
|
||||||
<NuxtIsland
|
|
||||||
name="LongAsyncComponent"
|
|
||||||
:props="{ count }"
|
|
||||||
>
|
|
||||||
<div>Interactive testing slot</div>
|
|
||||||
<div id="first-sugar-counter">
|
|
||||||
<Counter :multiplier="testCount" />
|
|
||||||
</div>
|
|
||||||
<template #test="scoped">
|
|
||||||
<div id="test-slot">
|
|
||||||
Slot with name test - scoped data {{ scoped }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #hello="scoped">
|
|
||||||
<div id="test-slot">
|
|
||||||
Slot with name hello - scoped data {{ scoped }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</NuxtIsland>
|
|
||||||
<button
|
|
||||||
id="update-server-components"
|
|
||||||
@click="count++"
|
|
||||||
>
|
|
||||||
add +1 to count
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p>Island with props mounted client side</p>
|
|
||||||
<button
|
|
||||||
id="show-island"
|
|
||||||
@click="showIslandSlot = true"
|
|
||||||
>
|
|
||||||
Show Interactive island
|
|
||||||
</button>
|
|
||||||
<div id="island-mounted-client-side">
|
|
||||||
<NuxtIsland
|
|
||||||
v-if="showIslandSlot"
|
|
||||||
name="LongAsyncComponent"
|
|
||||||
:props="{ count }"
|
|
||||||
>
|
|
||||||
<div>Interactive testing slot post SSR</div>
|
|
||||||
<Counter :multiplier="testCount" />
|
|
||||||
</NuxtIsland>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<server-with-client />
|
|
||||||
<ServerWithNestedClient />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user