docs(app): improve framework hydration (#2780)

Co-authored-by: Sébastien Chopin <seb@nuxt.com>
This commit is contained in:
Benjamin Canac
2024-11-26 18:23:26 +01:00
committed by GitHub
parent 15ca2f5701
commit e7995e7a0b
7 changed files with 78 additions and 21 deletions

View File

@@ -167,4 +167,11 @@ provide('navigation', filteredNavigation)
:root { :root {
--ui-container: var(--container-8xl); --ui-container: var(--container-8xl);
} }
html[data-framework="nuxt"] .vue-only {
display: none;
}
html[data-framework="vue"] .nuxt-only {
display: none;
}
</style> </style>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
const { framework, frameworks } = useSharedData() const { frameworks } = useSharedData()
</script> </script>
<template> <template>
@@ -12,7 +12,6 @@ const { framework, frameworks } = useSharedData()
<UButton <UButton
color="neutral" color="neutral"
variant="outline" variant="outline"
v-bind="frameworks.find(f => f.value === framework)"
block block
trailing-icon="i-lucide-chevron-down" trailing-icon="i-lucide-chevron-down"
:class="[open && 'bg-[var(--ui-bg-elevated)]']" :class="[open && 'bg-[var(--ui-bg-elevated)]']"
@@ -20,6 +19,14 @@ const { framework, frameworks } = useSharedData()
trailingIcon: ['transition-transform duration-200', open ? 'rotate-180' : undefined].filter(Boolean).join(' ') trailingIcon: ['transition-transform duration-200', open ? 'rotate-180' : undefined].filter(Boolean).join(' ')
}" }"
class="-mx-2 w-[calc(100%+1rem)]" class="-mx-2 w-[calc(100%+1rem)]"
/> >
<template #leading>
<UIcon v-for="framework in frameworks" :key="framework.value" :name="framework.icon" :class="`${framework.value}-only`" class="shrink-0 size-5" />
</template>
<span v-for="framework in frameworks" :key="framework.value" :class="`${framework.value}-only`">
{{ framework.label }}
</span>
</UButton>
</UDropdownMenu> </UDropdownMenu>
</template> </template>

View File

@@ -56,16 +56,18 @@ const component = computed(() => {
} }
}) })
const { data: ast } = await useAsyncData(`component-theme-${name}-${framework.value}`, async () => { const { data: ast } = await useAsyncData(`component-theme-${name}`, async () => {
const md = ` const md = `
::code-collapse ::code-collapse{class="nuxt-only"}
${framework.value === 'nuxt'
? `
\`\`\`ts [app.config.ts] \`\`\`ts [app.config.ts]
export default defineAppConfig(${json5.stringify(component.value, null, 2).replace(/,([ |\t\n]+[}|\])])/g, '$1')}) export default defineAppConfig(${json5.stringify(component.value, null, 2).replace(/,([ |\t\n]+[}|\])])/g, '$1')})
\`\`\`\ \`\`\`\
`
: ` ::
::code-collapse{class="vue-only"}
\`\`\`ts [vite.config.ts] \`\`\`ts [vite.config.ts]
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
@@ -81,7 +83,7 @@ export default defineConfig({
] ]
}) })
\`\`\` \`\`\`
`}
:: ::
${strippedCompoundVariants.value ${strippedCompoundVariants.value

View File

@@ -1,7 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
const { framework } = useSharedData() import { Slot } from 'radix-vue'
</script> </script>
<template> <template>
<slot :name="framework" /> <Slot class="nuxt-only">
<slot name="nuxt" />
</Slot>
<Slot class="vue-only">
<slot name="vue" />
</Slot>
</template> </template>

View File

@@ -4,11 +4,10 @@ import icons from '../../../../src/theme/icons'
const { framework } = useSharedData() const { framework } = useSharedData()
const { data: ast } = await useAsyncData(`icons-theme-${framework.value}`, async () => { const { data: ast } = await useAsyncData(`icons-theme`, async () => {
const md = ` const md = `
::code-collapse ::code-collapse{class="nuxt-only"}
${framework.value === 'nuxt'
? `
\`\`\`ts [app.config.ts] \`\`\`ts [app.config.ts]
export default defineAppConfig(${json5.stringify({ export default defineAppConfig(${json5.stringify({
ui: { ui: {
@@ -16,8 +15,11 @@ export default defineAppConfig(${json5.stringify({
} }
}, null, 2).replace(/,([ |\t\n]+[}|\])])/g, '$1')}) }, null, 2).replace(/,([ |\t\n]+[}|\])])/g, '$1')})
\`\`\`\ \`\`\`\
`
: ` ::
::code-collapse{class="vue-only"}
\`\`\`ts [vite.config.ts] \`\`\`ts [vite.config.ts]
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
@@ -37,7 +39,7 @@ export default defineConfig({
] ]
}) })
\`\`\` \`\`\`
`}
:: ::
` `

View File

@@ -0,0 +1,35 @@
export default defineNuxtPlugin({
enforce: 'post',
setup() {
const { framework } = useSharedData()
if (import.meta.client) {
useHead({
htmlAttrs: {
'data-framework': framework
}
})
}
if (import.meta.server) {
useHead({
script: [{
innerHTML: `
function getCookie(name) {
var value = '; ' + window.document.cookie;
var parts = value.split('; ' + name + '=');
if (parts.length === 2) {
return parts.pop()?.split(';').shift();
}
}
var framework = getCookie('nuxt-ui-framework');
document.documentElement.setAttribute('data-framework', framework || 'nuxt');
`.replace(/\s+/g, ' '),
type: 'text/javascript',
tagPriority: -1
}]
})
}
}
})

View File

@@ -102,8 +102,7 @@ export default defineNuxtConfig({
exclude: [ exclude: [
'/components/*', '/components/*',
'/getting-started/*', '/getting-started/*',
'/composables/*', '/composables/*'
'/api/*'
] ]
} }
} }