mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 23:22:02 +00:00
feat(nuxt3): create root component (#750)
This commit is contained in:
parent
b35b111032
commit
9cb9bb651e
@ -32,7 +32,7 @@ export default () => {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```vue [pages/index.vue]
|
```vue [app.vue]
|
||||||
<script setup>
|
<script setup>
|
||||||
const { data } = await useAsyncData('count', () => $fetch('/api/count'))
|
const { data } = await useAsyncData('count', () => $fetch('/api/count'))
|
||||||
</script>
|
</script>
|
||||||
@ -68,7 +68,7 @@ Available options:
|
|||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
```vue [pages/index.vue]
|
```vue [app.vue]
|
||||||
<script setup>
|
<script setup>
|
||||||
const { data } = await useFetch('/api/count')
|
const { data } = await useFetch('/api/count')
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "example-pages",
|
"name": "example-use-async-data",
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"nuxt3": "latest"
|
"nuxt3": "latest"
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "example-meta",
|
"name": "example-use-meta",
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"nuxt3": "latest"
|
"nuxt3": "latest"
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "example-wasm",
|
|
||||||
"private": true,
|
|
||||||
"devDependencies": {
|
|
||||||
"nuxt3": "latest"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"dev": "nuxt dev",
|
|
||||||
"build": "nuxt build",
|
|
||||||
"start": "node .output/server/index.mjs"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "example-async-data",
|
"name": "example-with-pages",
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"nuxt3": "latest"
|
"nuxt3": "latest"
|
@ -1,5 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
Hello Nuxt+Vite!
|
|
||||||
</div>
|
|
||||||
</template>
|
|
@ -1,5 +0,0 @@
|
|||||||
import { defineNuxtConfig } from 'nuxt3'
|
|
||||||
|
|
||||||
export default defineNuxtConfig({
|
|
||||||
vite: true
|
|
||||||
})
|
|
@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "example-with-vue-content-loader",
|
|
||||||
"private": true,
|
|
||||||
"devDependencies": {
|
|
||||||
"nuxt3": "latest",
|
|
||||||
"vue": "^3",
|
|
||||||
"vue-content-loader": "^2.0.0"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"dev": "nuxt dev",
|
|
||||||
"build": "nuxt build",
|
|
||||||
"start": "node .output/server/index.mjs"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="profile">
|
|
||||||
<ContentLoader v-if="pending" width="400" height="60">
|
|
||||||
<rect
|
|
||||||
x="70"
|
|
||||||
y="15"
|
|
||||||
rx="4"
|
|
||||||
ry="4"
|
|
||||||
width="117"
|
|
||||||
height="6.4"
|
|
||||||
/>
|
|
||||||
<rect
|
|
||||||
x="70"
|
|
||||||
y="35"
|
|
||||||
rx="3"
|
|
||||||
ry="3"
|
|
||||||
width="85"
|
|
||||||
height="6.4"
|
|
||||||
/>
|
|
||||||
<circle cx="30" cy="30" r="30" />
|
|
||||||
</ContentLoader>
|
|
||||||
<div v-else>
|
|
||||||
<img :src="data.avatar" height="55" width="55">
|
|
||||||
<div>
|
|
||||||
{{ data.text }}
|
|
||||||
<br>
|
|
||||||
{{ data.text }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { ContentLoader } from 'vue-content-loader'
|
|
||||||
export default defineNuxtComponent({
|
|
||||||
components: { ContentLoader },
|
|
||||||
setup () {
|
|
||||||
const { data, pending } = useAsyncData(
|
|
||||||
'time',
|
|
||||||
() =>
|
|
||||||
new Promise(resolve =>
|
|
||||||
setTimeout(
|
|
||||||
() =>
|
|
||||||
resolve({
|
|
||||||
text: 'finally done',
|
|
||||||
avatar:
|
|
||||||
'https://images.unsplash.com/photo-1517365830460-955ce3ccd263?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=256&h=256&q=80'
|
|
||||||
}),
|
|
||||||
2500
|
|
||||||
)
|
|
||||||
),
|
|
||||||
{ defer: true, server: false }
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
|
||||||
data,
|
|
||||||
pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.profile {
|
|
||||||
width: 400px;
|
|
||||||
height: 60px;
|
|
||||||
}
|
|
||||||
.profile img {
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
.profile > div {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "example-with-vite",
|
"name": "example-with-wasm",
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"nuxt3": "latest"
|
"nuxt3": "latest"
|
@ -49,7 +49,8 @@ export interface NuxtPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface NuxtApp {
|
export interface NuxtApp {
|
||||||
main?: string
|
mainComponent?: string
|
||||||
|
rootComponent?: string
|
||||||
dir: string
|
dir: string
|
||||||
extensions: string[]
|
extensions: string[]
|
||||||
plugins: NuxtPlugin[]
|
plugins: NuxtPlugin[]
|
||||||
|
5
packages/nuxt3/src/app/components/nuxt-root.vue
Normal file
5
packages/nuxt3/src/app/components/nuxt-root.vue
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<template>
|
||||||
|
<Suspense>
|
||||||
|
<App />
|
||||||
|
</Suspense>
|
||||||
|
</template>
|
@ -4,7 +4,9 @@ import '#build/css'
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import _plugins from '#build/plugins'
|
import _plugins from '#build/plugins'
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import App from '#build/app'
|
import RootComponent from '#build/root-component.mjs'
|
||||||
|
// @ts-ignore
|
||||||
|
import AppComponent from '#build/app-component.mjs'
|
||||||
|
|
||||||
let entry: Function
|
let entry: Function
|
||||||
|
|
||||||
@ -12,7 +14,8 @@ const plugins = normalizePlugins(_plugins)
|
|||||||
|
|
||||||
if (process.server) {
|
if (process.server) {
|
||||||
entry = async function createNuxtAppServer (ssrContext: CreateOptions['ssrContext'] = {}) {
|
entry = async function createNuxtAppServer (ssrContext: CreateOptions['ssrContext'] = {}) {
|
||||||
const app = createApp(App)
|
const app = createApp(RootComponent)
|
||||||
|
app.component('App', AppComponent)
|
||||||
|
|
||||||
const nuxt = createNuxtApp({ app, ssrContext })
|
const nuxt = createNuxtApp({ app, ssrContext })
|
||||||
|
|
||||||
@ -35,7 +38,8 @@ if (process.client) {
|
|||||||
|
|
||||||
entry = async function initApp () {
|
entry = async function initApp () {
|
||||||
const isSSR = Boolean(window.__NUXT__?.serverRendered)
|
const isSSR = Boolean(window.__NUXT__?.serverRendered)
|
||||||
const app = isSSR ? createSSRApp(App) : createApp(App)
|
const app = isSSR ? createSSRApp(RootComponent) : createApp(RootComponent)
|
||||||
|
app.component('App', AppComponent)
|
||||||
|
|
||||||
const nuxt = createNuxtApp({ app })
|
const nuxt = createNuxtApp({ app })
|
||||||
|
|
||||||
|
@ -8,10 +8,18 @@ type TemplateContext = {
|
|||||||
app: NuxtApp;
|
app: NuxtApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const appTemplate = {
|
// TODO: Use an alias
|
||||||
filename: 'app.mjs',
|
export const appComponentTemplate = {
|
||||||
|
filename: 'app-component.mjs',
|
||||||
getContents (ctx: TemplateContext) {
|
getContents (ctx: TemplateContext) {
|
||||||
return `export { default } from '${ctx.app.main}'`
|
return `export { default } from '${ctx.app.mainComponent}'`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: Use an alias
|
||||||
|
export const rootComponentTemplate = {
|
||||||
|
filename: 'root-component.mjs',
|
||||||
|
getContents (ctx: TemplateContext) {
|
||||||
|
return `export { default } from '${ctx.app.rootComponent}'`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,13 +59,16 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Resolve main (app.vue)
|
// Resolve main (app.vue)
|
||||||
if (!app.main) {
|
if (!app.mainComponent) {
|
||||||
app.main = tryResolvePath('~/App', resolveOptions) || tryResolvePath('~/app', resolveOptions)
|
app.mainComponent = tryResolvePath('~/App', resolveOptions) || tryResolvePath('~/app', resolveOptions)
|
||||||
}
|
}
|
||||||
if (!app.main) {
|
if (!app.mainComponent) {
|
||||||
app.main = resolve(nuxt.options.appDir, 'components/nuxt-welcome.vue')
|
app.mainComponent = resolve(nuxt.options.appDir, 'components/nuxt-welcome.vue')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default root component
|
||||||
|
app.rootComponent = resolve(nuxt.options.appDir, 'components/nuxt-root.vue')
|
||||||
|
|
||||||
// Resolve plugins
|
// Resolve plugins
|
||||||
app.plugins = [
|
app.plugins = [
|
||||||
...nuxt.options.plugins,
|
...nuxt.options.plugins,
|
||||||
|
@ -15,7 +15,7 @@ export async function build (nuxt: Nuxt) {
|
|||||||
nuxt.hook('builder:watch', async (event, path) => {
|
nuxt.hook('builder:watch', async (event, path) => {
|
||||||
if (event !== 'change' && /app|plugins/i.test(path)) {
|
if (event !== 'change' && /app|plugins/i.test(path)) {
|
||||||
if (path.match(/app/i)) {
|
if (path.match(/app/i)) {
|
||||||
app.main = null
|
app.mainComponent = null
|
||||||
}
|
}
|
||||||
await generateApp(nuxt, app)
|
await generateApp(nuxt, app)
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,12 @@ export default defineNuxtModule({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add default layout for pages
|
|
||||||
nuxt.hook('app:resolve', (app) => {
|
nuxt.hook('app:resolve', (app) => {
|
||||||
if (app.main.includes('nuxt-welcome')) {
|
// Remove default root with Suspense
|
||||||
app.main = resolve(runtimeDir, 'app.vue')
|
app.rootComponent = resolve(runtimeDir, 'root.vue')
|
||||||
|
// Add default layout for pages
|
||||||
|
if (app.mainComponent.includes('nuxt-welcome')) {
|
||||||
|
app.mainComponent = resolve(runtimeDir, 'app.vue')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
3
packages/nuxt3/src/pages/runtime/root.vue
Normal file
3
packages/nuxt3/src/pages/runtime/root.vue
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<template>
|
||||||
|
<App />
|
||||||
|
</template>
|
@ -1,5 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<NuxtPage />
|
<img src="~/assets/logo.svg">
|
||||||
|
<br>
|
||||||
|
Hello Nuxt 3
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default defineNuxtComponent({
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<img src="~/assets/logo.svg">
|
|
||||||
<br>
|
|
||||||
Hello Nuxt 3
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default defineNuxtComponent({
|
|
||||||
})
|
|
||||||
</script>
|
|
49
yarn.lock
49
yarn.lock
@ -9199,14 +9199,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"example-async-data@workspace:examples/async-data":
|
|
||||||
version: 0.0.0-use.local
|
|
||||||
resolution: "example-async-data@workspace:examples/async-data"
|
|
||||||
dependencies:
|
|
||||||
nuxt3: latest
|
|
||||||
languageName: unknown
|
|
||||||
linkType: soft
|
|
||||||
|
|
||||||
"example-hello-world@workspace:examples/hello-world":
|
"example-hello-world@workspace:examples/hello-world":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "example-hello-world@workspace:examples/hello-world"
|
resolution: "example-hello-world@workspace:examples/hello-world"
|
||||||
@ -9215,17 +9207,9 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"example-meta@workspace:examples/meta":
|
"example-use-async-data@workspace:examples/use-async-data":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "example-meta@workspace:examples/meta"
|
resolution: "example-use-async-data@workspace:examples/use-async-data"
|
||||||
dependencies:
|
|
||||||
nuxt3: latest
|
|
||||||
languageName: unknown
|
|
||||||
linkType: soft
|
|
||||||
|
|
||||||
"example-pages@workspace:examples/pages":
|
|
||||||
version: 0.0.0-use.local
|
|
||||||
resolution: "example-pages@workspace:examples/pages"
|
|
||||||
dependencies:
|
dependencies:
|
||||||
nuxt3: latest
|
nuxt3: latest
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
@ -9239,17 +9223,17 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"example-use-state@workspace:examples/use-state":
|
"example-use-meta@workspace:examples/use-meta":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "example-use-state@workspace:examples/use-state"
|
resolution: "example-use-meta@workspace:examples/use-meta"
|
||||||
dependencies:
|
dependencies:
|
||||||
nuxt3: latest
|
nuxt3: latest
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"example-wasm@workspace:examples/wasm":
|
"example-use-state@workspace:examples/use-state":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "example-wasm@workspace:examples/wasm"
|
resolution: "example-use-state@workspace:examples/use-state"
|
||||||
dependencies:
|
dependencies:
|
||||||
nuxt3: latest
|
nuxt3: latest
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
@ -9271,21 +9255,19 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"example-with-vite@workspace:examples/with-vite":
|
"example-with-pages@workspace:examples/with-pages":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "example-with-vite@workspace:examples/with-vite"
|
resolution: "example-with-pages@workspace:examples/with-pages"
|
||||||
dependencies:
|
dependencies:
|
||||||
nuxt3: latest
|
nuxt3: latest
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"example-with-vue-content-loader@workspace:examples/with-vue-content-loader":
|
"example-with-wasm@workspace:examples/with-wasm":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "example-with-vue-content-loader@workspace:examples/with-vue-content-loader"
|
resolution: "example-with-wasm@workspace:examples/with-wasm"
|
||||||
dependencies:
|
dependencies:
|
||||||
nuxt3: latest
|
nuxt3: latest
|
||||||
vue: ^3
|
|
||||||
vue-content-loader: ^2.0.0
|
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
@ -19251,15 +19233,6 @@ fsevents@~2.3.2:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"vue-content-loader@npm:^2.0.0":
|
|
||||||
version: 2.0.0
|
|
||||||
resolution: "vue-content-loader@npm:2.0.0"
|
|
||||||
peerDependencies:
|
|
||||||
vue: ^3
|
|
||||||
checksum: 92efefe9e2aa4760a1e60ecfa2358bbc9a613f89a0e90a52cecef5a315ac247cb439d0cff58cab6891ef9fec900a9e232b96ed8d7e7dc051b00eb5f0ee0bd407
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"vue-eslint-parser@npm:^7.10.0":
|
"vue-eslint-parser@npm:^7.10.0":
|
||||||
version: 7.11.0
|
version: 7.11.0
|
||||||
resolution: "vue-eslint-parser@npm:7.11.0"
|
resolution: "vue-eslint-parser@npm:7.11.0"
|
||||||
@ -19405,7 +19378,7 @@ fsevents@~2.3.2:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"vue@npm:3.2.20, vue@npm:^3, vue@npm:^3.2.20":
|
"vue@npm:3.2.20, vue@npm:^3.2.20":
|
||||||
version: 3.2.20
|
version: 3.2.20
|
||||||
resolution: "vue@npm:3.2.20"
|
resolution: "vue@npm:3.2.20"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
Loading…
Reference in New Issue
Block a user