mirror of
https://github.com/nuxt/nuxt.git
synced 2025-03-09 03:03:18 +00:00
Merge branch 'main' into patch-21
This commit is contained in:
commit
1f196a57cd
2
.github/workflows/check-links.yml
vendored
2
.github/workflows/check-links.yml
vendored
@ -28,7 +28,7 @@ jobs:
|
|||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||||
|
|
||||||
- name: Lychee link checker
|
- name: Lychee link checker
|
||||||
uses: lycheeverse/lychee-action@c053181aa0c3d17606addfe97a9075a32723548a # for v1.8.0
|
uses: lycheeverse/lychee-action@1e92115388e88fdc331019d99c8ab8dfe97ddd13 # for v1.8.0
|
||||||
with:
|
with:
|
||||||
# arguments with file types to check
|
# arguments with file types to check
|
||||||
args: >-
|
args: >-
|
||||||
|
@ -122,7 +122,7 @@ const { data, error } = await useAsyncData(`user:${id}`, () => {
|
|||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
The `useAsyncData` composable is a great way to wrap and wait for multiple `useFetch` to be done, and then retrieve the results of each.
|
The `useAsyncData` composable is a great way to wrap and wait for multiple `$fetch` requests to be completed, and then process the results.
|
||||||
|
|
||||||
```vue
|
```vue
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
@ -33,7 +33,7 @@ Discover all the available options in the **Nuxt configuration** documentation.
|
|||||||
|
|
||||||
To ensure your configuration is up to date, Nuxt will make a full restart when detecting changes in the main configuration file, the [`.env`](/docs/guide/directory-structure/env), [`.nuxtignore`](/docs/guide/directory-structure/nuxtignore) and `.nuxtrc` dotfiles.
|
To ensure your configuration is up to date, Nuxt will make a full restart when detecting changes in the main configuration file, the [`.env`](/docs/guide/directory-structure/env), [`.nuxtignore`](/docs/guide/directory-structure/nuxtignore) and `.nuxtrc` dotfiles.
|
||||||
|
|
||||||
The `.nuxtrc` file is a file that can be used to configure Nuxt with a fla syntax, it is based on [`unjs/rc9`](https://github.com/unjs/rc9).
|
The `.nuxtrc` file can be used to configure Nuxt with a flat syntax. It is based on [`unjs/rc9`](https://github.com/unjs/rc9).
|
||||||
|
|
||||||
``` [.nuxtrc]
|
``` [.nuxtrc]
|
||||||
ssr=false
|
ssr=false
|
||||||
|
@ -9,7 +9,7 @@ links:
|
|||||||
---
|
---
|
||||||
|
|
||||||
```bash [Terminal]
|
```bash [Terminal]
|
||||||
npx nuxi build [--prerender] [--dotenv] [--log-level] [rootDir]
|
npx nuxi build [--prerender] [--preset] [--dotenv] [--log-level] [rootDir]
|
||||||
```
|
```
|
||||||
|
|
||||||
The `build` command creates a `.output` directory with all your application, server and dependencies ready for production.
|
The `build` command creates a `.output` directory with all your application, server and dependencies ready for production.
|
||||||
@ -18,9 +18,14 @@ Option | Default | Description
|
|||||||
-------------------------|-----------------|------------------
|
-------------------------|-----------------|------------------
|
||||||
`rootDir` | `.` | The root directory of the application to bundle.
|
`rootDir` | `.` | The root directory of the application to bundle.
|
||||||
`--prerender` | `false` | Pre-render every route of your application. (**note:** This is an experimental flag. The behavior might be changed.)
|
`--prerender` | `false` | Pre-render every route of your application. (**note:** This is an experimental flag. The behavior might be changed.)
|
||||||
|
`--preset` | - | Set a [Nitro preset](https://nitro.unjs.io/deploy#changing-the-deployment-preset)
|
||||||
`--dotenv` | `.` | Point to another `.env` file to load, **relative** to the root directory.
|
`--dotenv` | `.` | Point to another `.env` file to load, **relative** to the root directory.
|
||||||
`--log-level` | `info` | Specify build-time logging level, allowing `silent` \| `info` \| `verbose`.
|
`--log-level` | `info` | Specify build-time logging level, allowing `silent` \| `info` \| `verbose`.
|
||||||
|
|
||||||
::note
|
::note
|
||||||
This command sets `process.env.NODE_ENV` to `production`.
|
This command sets `process.env.NODE_ENV` to `production`.
|
||||||
::
|
::
|
||||||
|
|
||||||
|
::note
|
||||||
|
`--prerender` will always set the `preset` to `static`
|
||||||
|
::
|
||||||
|
10
package.json
10
package.json
@ -37,7 +37,7 @@
|
|||||||
"@nuxt/schema": "workspace:*",
|
"@nuxt/schema": "workspace:*",
|
||||||
"@nuxt/vite-builder": "workspace:*",
|
"@nuxt/vite-builder": "workspace:*",
|
||||||
"@nuxt/webpack-builder": "workspace:*",
|
"@nuxt/webpack-builder": "workspace:*",
|
||||||
"rollup": "^4.14.1",
|
"rollup": "^4.14.2",
|
||||||
"nuxt": "workspace:*",
|
"nuxt": "workspace:*",
|
||||||
"vite": "5.2.8",
|
"vite": "5.2.8",
|
||||||
"vue": "3.4.21",
|
"vue": "3.4.21",
|
||||||
@ -45,7 +45,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "9.0.0",
|
"@eslint/js": "9.0.0",
|
||||||
"@nuxt/eslint-config": "0.3.4",
|
"@nuxt/eslint-config": "0.3.6",
|
||||||
"@nuxt/kit": "workspace:*",
|
"@nuxt/kit": "workspace:*",
|
||||||
"@nuxt/test-utils": "3.12.0",
|
"@nuxt/test-utils": "3.12.0",
|
||||||
"@nuxt/webpack-builder": "workspace:*",
|
"@nuxt/webpack-builder": "workspace:*",
|
||||||
@ -77,17 +77,17 @@
|
|||||||
"nuxt-content-twoslash": "0.0.10",
|
"nuxt-content-twoslash": "0.0.10",
|
||||||
"ofetch": "1.3.4",
|
"ofetch": "1.3.4",
|
||||||
"pathe": "1.1.2",
|
"pathe": "1.1.2",
|
||||||
"playwright-core": "1.43.0",
|
"playwright-core": "1.43.1",
|
||||||
"rimraf": "5.0.5",
|
"rimraf": "5.0.5",
|
||||||
"semver": "7.6.0",
|
"semver": "7.6.0",
|
||||||
"std-env": "3.7.0",
|
"std-env": "3.7.0",
|
||||||
"typescript": "5.4.4",
|
"typescript": "5.4.5",
|
||||||
"ufo": "1.5.3",
|
"ufo": "1.5.3",
|
||||||
"vitest": "1.4.0",
|
"vitest": "1.4.0",
|
||||||
"vitest-environment-nuxt": "1.0.0",
|
"vitest-environment-nuxt": "1.0.0",
|
||||||
"vue": "3.4.21",
|
"vue": "3.4.21",
|
||||||
"vue-router": "4.3.0",
|
"vue-router": "4.3.0",
|
||||||
"vue-tsc": "2.0.11"
|
"vue-tsc": "2.0.13"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@8.15.6",
|
"packageManager": "pnpm@8.15.6",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -66,9 +66,9 @@
|
|||||||
"@nuxt/telemetry": "^2.5.4",
|
"@nuxt/telemetry": "^2.5.4",
|
||||||
"@nuxt/ui-templates": "^1.3.3",
|
"@nuxt/ui-templates": "^1.3.3",
|
||||||
"@nuxt/vite-builder": "workspace:*",
|
"@nuxt/vite-builder": "workspace:*",
|
||||||
"@unhead/dom": "^1.9.4",
|
"@unhead/dom": "^1.9.5",
|
||||||
"@unhead/ssr": "^1.9.4",
|
"@unhead/ssr": "^1.9.5",
|
||||||
"@unhead/vue": "^1.9.4",
|
"@unhead/vue": "^1.9.5",
|
||||||
"@vue/shared": "^3.4.21",
|
"@vue/shared": "^3.4.21",
|
||||||
"acorn": "8.11.3",
|
"acorn": "8.11.3",
|
||||||
"c12": "^1.10.0",
|
"c12": "^1.10.0",
|
||||||
|
@ -507,9 +507,12 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
|||||||
|
|
||||||
if (nitro.options.static) {
|
if (nitro.options.static) {
|
||||||
nitro.hooks.hook('prerender:routes', (routes) => {
|
nitro.hooks.hook('prerender:routes', (routes) => {
|
||||||
for (const route of [nuxt.options.ssr ? '/' : '/index.html', '/200.html', '/404.html']) {
|
for (const route of ['/200.html', '/404.html']) {
|
||||||
routes.add(route)
|
routes.add(route)
|
||||||
}
|
}
|
||||||
|
if (!nuxt.options.ssr) {
|
||||||
|
routes.add('/index.html')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ export function getNameFromPath (path: string, relativeTo?: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function hasSuffix (path: string, suffix: string) {
|
export function hasSuffix (path: string, suffix: string) {
|
||||||
return basename(path).replace(extname(path), '').endsWith(suffix)
|
return basename(path, extname(path)).endsWith(suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveComponentNameSegments (fileName: string, prefixParts: string[]) {
|
export function resolveComponentNameSegments (fileName: string, prefixParts: string[]) {
|
||||||
|
@ -3,7 +3,6 @@ import { mkdir, readFile } from 'node:fs/promises'
|
|||||||
import { addBuildPlugin, addComponent, addPlugin, addTemplate, addTypeTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, findPath, logger, updateTemplates, useNitro } from '@nuxt/kit'
|
import { addBuildPlugin, addComponent, addPlugin, addTemplate, addTypeTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, findPath, logger, updateTemplates, useNitro } from '@nuxt/kit'
|
||||||
import { dirname, join, relative, resolve } from 'pathe'
|
import { dirname, join, relative, resolve } from 'pathe'
|
||||||
import { genImport, genObjectFromRawEntries, genString } from 'knitwork'
|
import { genImport, genObjectFromRawEntries, genString } from 'knitwork'
|
||||||
import { joinURL } from 'ufo'
|
|
||||||
import type { Nuxt, NuxtApp, NuxtPage } from 'nuxt/schema'
|
import type { Nuxt, NuxtApp, NuxtPage } from 'nuxt/schema'
|
||||||
import { createRoutesContext } from 'unplugin-vue-router'
|
import { createRoutesContext } from 'unplugin-vue-router'
|
||||||
import { resolveOptions } from 'unplugin-vue-router/options'
|
import { resolveOptions } from 'unplugin-vue-router/options'
|
||||||
@ -18,8 +17,6 @@ import type { PageMetaPluginOptions } from './plugins/page-meta'
|
|||||||
import { PageMetaPlugin } from './plugins/page-meta'
|
import { PageMetaPlugin } from './plugins/page-meta'
|
||||||
import { RouteInjectionPlugin } from './plugins/route-injection'
|
import { RouteInjectionPlugin } from './plugins/route-injection'
|
||||||
|
|
||||||
const OPTIONAL_PARAM_RE = /^\/?:.*(\?|\(\.\*\)\*)$/
|
|
||||||
|
|
||||||
export default defineNuxtModule({
|
export default defineNuxtModule({
|
||||||
meta: {
|
meta: {
|
||||||
name: 'pages',
|
name: 'pages',
|
||||||
@ -266,36 +263,14 @@ export default defineNuxtModule({
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
nuxt.hook('nitro:init', (nitro) => {
|
nuxt.hook('app:resolve', (app) => {
|
||||||
if (nuxt.options.dev || !nitro.options.static || nuxt.options.router.options.hashMode) { return }
|
const nitro = useNitro()
|
||||||
// Prerender all non-dynamic page routes when generating app
|
if (nitro.options.prerender.crawlLinks) {
|
||||||
const prerenderRoutes = new Set<string>()
|
app.plugins.push({
|
||||||
nuxt.hook('pages:extend', (pages) => {
|
src: resolve(runtimeDir, 'plugins/prerender.server'),
|
||||||
prerenderRoutes.clear()
|
mode: 'server',
|
||||||
const processPages = (pages: NuxtPage[], currentPath = '/') => {
|
})
|
||||||
for (const page of pages) {
|
}
|
||||||
// Add root of optional dynamic paths and catchalls
|
|
||||||
if (OPTIONAL_PARAM_RE.test(page.path) && !page.children?.length) { prerenderRoutes.add(currentPath) }
|
|
||||||
// Skip dynamic paths
|
|
||||||
if (page.path.includes(':')) { continue }
|
|
||||||
const route = joinURL(currentPath, page.path)
|
|
||||||
prerenderRoutes.add(route)
|
|
||||||
if (page.children) { processPages(page.children, route) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
processPages(pages)
|
|
||||||
})
|
|
||||||
nuxt.hook('nitro:build:before', (nitro) => {
|
|
||||||
if (nitro.options.prerender.routes.length) {
|
|
||||||
for (const route of nitro.options.prerender.routes) {
|
|
||||||
// Skip default route value as we only generate it if it is already
|
|
||||||
// in the detected routes from `~/pages`.
|
|
||||||
if (route === '/') { continue }
|
|
||||||
prerenderRoutes.add(route)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nitro.options.prerender.routes = Array.from(prerenderRoutes)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
nuxt.hook('imports:extend', (imports) => {
|
nuxt.hook('imports:extend', (imports) => {
|
||||||
|
45
packages/nuxt/src/pages/runtime/plugins/prerender.server.ts
Normal file
45
packages/nuxt/src/pages/runtime/plugins/prerender.server.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import type { RouteRecordRaw } from 'vue-router'
|
||||||
|
import { joinURL } from 'ufo'
|
||||||
|
|
||||||
|
import { defineNuxtPlugin } from '#app/nuxt'
|
||||||
|
import { prerenderRoutes } from '#app/composables/ssr'
|
||||||
|
// @ts-expect-error virtual file
|
||||||
|
import _routes from '#build/routes'
|
||||||
|
// @ts-expect-error virtual file
|
||||||
|
import routerOptions from '#build/router.options'
|
||||||
|
|
||||||
|
let routes: string[]
|
||||||
|
|
||||||
|
export default defineNuxtPlugin(async () => {
|
||||||
|
if (!import.meta.server || !import.meta.prerender || routerOptions.hashMode) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (routes && !routes.length) { return }
|
||||||
|
|
||||||
|
routes ||= Array.from(processRoutes(await routerOptions.routes?.(_routes) ?? _routes))
|
||||||
|
const batch = routes.splice(0, 10)
|
||||||
|
prerenderRoutes(batch)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Implementation
|
||||||
|
|
||||||
|
const OPTIONAL_PARAM_RE = /^\/?:.*(\?|\(\.\*\)\*)$/
|
||||||
|
|
||||||
|
function processRoutes (routes: RouteRecordRaw[], currentPath = '/', routesToPrerender = new Set<string>()) {
|
||||||
|
for (const route of routes) {
|
||||||
|
// Add root of optional dynamic paths and catchalls
|
||||||
|
if (OPTIONAL_PARAM_RE.test(route.path) && !route.children?.length) {
|
||||||
|
routesToPrerender.add(currentPath)
|
||||||
|
}
|
||||||
|
// Skip dynamic paths
|
||||||
|
if (route.path.includes(':')) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const fullPath = joinURL(currentPath, route.path)
|
||||||
|
routesToPrerender.add(fullPath)
|
||||||
|
if (route.children) {
|
||||||
|
processRoutes(route.children, fullPath, routesToPrerender)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return routesToPrerender
|
||||||
|
}
|
@ -38,12 +38,12 @@
|
|||||||
"@types/file-loader": "5.0.4",
|
"@types/file-loader": "5.0.4",
|
||||||
"@types/pug": "2.0.10",
|
"@types/pug": "2.0.10",
|
||||||
"@types/sass-loader": "8.0.8",
|
"@types/sass-loader": "8.0.8",
|
||||||
"@unhead/schema": "1.9.4",
|
"@unhead/schema": "1.9.5",
|
||||||
"@vitejs/plugin-vue": "5.0.4",
|
"@vitejs/plugin-vue": "5.0.4",
|
||||||
"@vitejs/plugin-vue-jsx": "3.1.0",
|
"@vitejs/plugin-vue-jsx": "3.1.0",
|
||||||
"@vue/compiler-core": "3.4.21",
|
"@vue/compiler-core": "3.4.21",
|
||||||
"@vue/compiler-sfc": "3.4.21",
|
"@vue/compiler-sfc": "3.4.21",
|
||||||
"@vue/language-core": "2.0.11",
|
"@vue/language-core": "2.0.13",
|
||||||
"c12": "1.10.0",
|
"c12": "1.10.0",
|
||||||
"esbuild-loader": "4.1.0",
|
"esbuild-loader": "4.1.0",
|
||||||
"h3": "1.11.1",
|
"h3": "1.11.1",
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
"@nuxt/friendly-errors-webpack-plugin": "^2.6.0",
|
"@nuxt/friendly-errors-webpack-plugin": "^2.6.0",
|
||||||
"@nuxt/kit": "workspace:*",
|
"@nuxt/kit": "workspace:*",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"css-loader": "^7.1.0",
|
"css-loader": "^7.1.1",
|
||||||
"css-minimizer-webpack-plugin": "^6.0.0",
|
"css-minimizer-webpack-plugin": "^6.0.0",
|
||||||
"cssnano": "^6.1.2",
|
"cssnano": "^6.1.2",
|
||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
@ -63,7 +63,7 @@
|
|||||||
"vue-bundle-renderer": "^2.0.0",
|
"vue-bundle-renderer": "^2.0.0",
|
||||||
"vue-loader": "^17.4.2",
|
"vue-loader": "^17.4.2",
|
||||||
"webpack": "^5.91.0",
|
"webpack": "^5.91.0",
|
||||||
"webpack-bundle-analyzer": "^4.10.1",
|
"webpack-bundle-analyzer": "^4.10.2",
|
||||||
"webpack-dev-middleware": "^7.2.1",
|
"webpack-dev-middleware": "^7.2.1",
|
||||||
"webpack-hot-middleware": "^2.26.1",
|
"webpack-hot-middleware": "^2.26.1",
|
||||||
"webpack-virtual-modules": "^0.6.1",
|
"webpack-virtual-modules": "^0.6.1",
|
||||||
|
879
pnpm-lock.yaml
879
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -75,7 +75,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
|||||||
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"527k"`)
|
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"527k"`)
|
||||||
|
|
||||||
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
||||||
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot('"75.6k"')
|
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"75.9k"`)
|
||||||
|
|
||||||
const packages = modules.files
|
const packages = modules.files
|
||||||
.filter(m => m.endsWith('package.json'))
|
.filter(m => m.endsWith('package.json'))
|
||||||
|
Loading…
Reference in New Issue
Block a user