mirror of
https://github.com/nuxt/nuxt.git
synced 2025-02-23 17:10:07 +00:00
Merge branches 'feat/unhead-v2' and 'main' of github.com:nuxt/nuxt into feat/unhead-v2
This commit is contained in:
commit
f49b907cdd
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -236,7 +236,7 @@ jobs:
|
||||
path: packages
|
||||
|
||||
- name: Run benchmarks
|
||||
uses: CodSpeedHQ/action@513a19673a831f139e8717bf45ead67e47f00044 # v3.2.0
|
||||
uses: CodSpeedHQ/action@da7c57859a7a565a3a92789ac64c41aca031ca1f # v3.3.0
|
||||
with:
|
||||
run: pnpm vitest bench
|
||||
token: ${{ secrets.CODSPEED_TOKEN }}
|
||||
|
@ -120,7 +120,7 @@ interface MetaObject {
|
||||
}
|
||||
```
|
||||
|
||||
See [unhead/types](https://github.com/unjs/unhead/blob/main/packages/unhead/src/types/schema/head.ts) for more detailed types.
|
||||
See [@unhead/vue](https://github.com/unjs/unhead/blob/main/packages/vue/src/types/schema.ts) for more detailed types.
|
||||
|
||||
## Features
|
||||
|
||||
|
@ -53,6 +53,26 @@ export default defineNuxtConfig({
|
||||
})
|
||||
```
|
||||
|
||||
::tip
|
||||
You can override a layer's alias by specifying it in the options next to the layer source.
|
||||
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
extends: [
|
||||
[
|
||||
'github:my-themes/awesome',
|
||||
{
|
||||
meta: {
|
||||
name: 'my-awesome-theme',
|
||||
},
|
||||
},
|
||||
],
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
Nuxt uses [unjs/c12](https://c12.unjs.io) and [unjs/giget](https://giget.unjs.io) for extending remote layers. Check the documentation for more information and all available options.
|
||||
|
||||
::read-more{to="/docs/guide/going-further/layers"}
|
||||
|
@ -136,6 +136,6 @@ Before mounting the Vue application, Nuxt calls the [`app:beforeMount`](/docs/ap
|
||||
After mounting the Vue application, Nuxt calls the [`app:mounted`](/docs/api/advanced/hooks#app-hooks-runtime) hook.
|
||||
::
|
||||
|
||||
### Step 6: Vue Lifecycle
|
||||
### Step 5: Vue Lifecycle
|
||||
|
||||
Unlike on the server, the browser executes the full [Vue lifecycle](https://vuejs.org/guide/essentials/lifecycle).
|
||||
|
@ -11,9 +11,9 @@ The hooking system is powered by [unjs/hookable](https://github.com/unjs/hookabl
|
||||
|
||||
These hooks are available for [Nuxt Modules](/docs/guide/going-further/modules) and build context.
|
||||
|
||||
### Within `nuxt.config`
|
||||
### Within `nuxt.config.ts`
|
||||
|
||||
```js [nuxt.config]
|
||||
```js [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
hooks: {
|
||||
close: () => { }
|
||||
|
@ -52,4 +52,4 @@ const WhitelistAttributes = {
|
||||
}
|
||||
```
|
||||
|
||||
See [SafeInputPlugin](https://github.com/unjs/unhead/blob/main/packages/unhead/src/plugins/safe.ts) for more detailed types.
|
||||
See [@unhead/vue](https://github.com/unjs/unhead/blob/main/packages/vue/src/types/safeSchema.ts) for more detailed types.
|
||||
|
@ -35,7 +35,7 @@ interface MetaObject {
|
||||
}
|
||||
```
|
||||
|
||||
See [unhead/types](https://github.com/unjs/unhead/blob/main/packages/unhead/src/types/schema/head.ts) for more detailed types.
|
||||
See [@unhead/vue](https://github.com/unjs/unhead/blob/main/packages/vue/src/types/schema.ts) for more detailed types.
|
||||
|
||||
::note
|
||||
The properties of `useHead` can be dynamic, accepting `ref`, `computed` and `reactive` properties. `meta` parameter can also accept a function returning an object to make the entire object reactive.
|
||||
|
16
package.json
16
package.json
@ -45,7 +45,7 @@
|
||||
"@nuxt/schema": "workspace:*",
|
||||
"@nuxt/vite-builder": "workspace:*",
|
||||
"@nuxt/webpack-builder": "workspace:*",
|
||||
"@types/node": "22.13.1",
|
||||
"@types/node": "22.13.2",
|
||||
"@unhead/vue": "2.0.0-alpha.13",
|
||||
"@vue/compiler-core": "3.5.13",
|
||||
"@vue/compiler-dom": "3.5.13",
|
||||
@ -81,14 +81,14 @@
|
||||
"@testing-library/vue": "8.1.0",
|
||||
"@types/babel__core": "7.20.5",
|
||||
"@types/babel__helper-plugin-utils": "7.10.3",
|
||||
"@types/node": "22.13.1",
|
||||
"@types/node": "22.13.2",
|
||||
"@types/semver": "7.5.8",
|
||||
"@unhead/vue": "2.0.0-alpha.13",
|
||||
"@vitest/coverage-v8": "3.0.5",
|
||||
"@vue/test-utils": "2.4.6",
|
||||
"acorn": "8.14.0",
|
||||
"autoprefixer": "10.4.20",
|
||||
"case-police": "0.7.2",
|
||||
"case-police": "1.0.0",
|
||||
"changelogen": "0.5.7",
|
||||
"consola": "3.4.0",
|
||||
"cssnano": "7.0.6",
|
||||
@ -96,14 +96,14 @@
|
||||
"devalue": "5.1.1",
|
||||
"eslint": "9.20.1",
|
||||
"eslint-plugin-no-only-tests": "3.3.0",
|
||||
"eslint-plugin-perfectionist": "4.8.0",
|
||||
"eslint-plugin-perfectionist": "4.9.0",
|
||||
"eslint-typegen": "1.0.0",
|
||||
"estree-walker": "3.0.3",
|
||||
"h3": "npm:h3-nightly@1.14.0-20250122-114730-3f9e703",
|
||||
"happy-dom": "17.0.4",
|
||||
"happy-dom": "17.1.0",
|
||||
"installed-check": "9.3.0",
|
||||
"jiti": "2.4.2",
|
||||
"knip": "5.44.0",
|
||||
"knip": "5.44.1",
|
||||
"magic-string": "0.30.17",
|
||||
"markdownlint-cli": "0.44.0",
|
||||
"memfs": "4.17.0",
|
||||
@ -111,7 +111,7 @@
|
||||
"nuxt": "workspace:*",
|
||||
"nuxt-content-twoslash": "0.1.2",
|
||||
"ofetch": "1.4.1",
|
||||
"pathe": "2.0.2",
|
||||
"pathe": "2.0.3",
|
||||
"pkg-pr-new": "0.0.39",
|
||||
"playwright-core": "1.50.1",
|
||||
"rollup": "4.34.6",
|
||||
@ -120,7 +120,7 @@
|
||||
"std-env": "3.8.0",
|
||||
"tinyexec": "0.3.2",
|
||||
"tinyglobby": "0.2.10",
|
||||
"ts-blank-space": "0.5.1",
|
||||
"ts-blank-space": "0.6.0",
|
||||
"typescript": "5.7.3",
|
||||
"ufo": "1.5.4",
|
||||
"unbuild": "3.3.1",
|
||||
|
@ -38,7 +38,7 @@
|
||||
"klona": "^2.0.6",
|
||||
"mlly": "^1.7.4",
|
||||
"ohash": "^1.1.4",
|
||||
"pathe": "^2.0.2",
|
||||
"pathe": "^2.0.3",
|
||||
"pkg-types": "^1.3.1",
|
||||
"scule": "^1.3.0",
|
||||
"semver": "^7.7.1",
|
||||
|
@ -2,6 +2,7 @@ import { pathToFileURL } from 'node:url'
|
||||
import { readPackageJSON, resolvePackageJSON } from 'pkg-types'
|
||||
import type { Nuxt, NuxtConfig } from '@nuxt/schema'
|
||||
import { resolve } from 'pathe'
|
||||
import { withTrailingSlash } from 'ufo'
|
||||
import { importModule, tryImportModule } from '../internal/esm'
|
||||
import { runWithNuxtContext } from '../context'
|
||||
import type { LoadNuxtConfigOptions } from './config'
|
||||
@ -22,23 +23,23 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
|
||||
// Apply dev as config override
|
||||
opts.overrides.dev = !!opts.dev
|
||||
|
||||
const rootDir = withTrailingSlash(pathToFileURL(opts.cwd!).href)
|
||||
|
||||
const nearestNuxtPkg = await Promise.all(['nuxt-nightly', 'nuxt']
|
||||
.map(pkg => resolvePackageJSON(pkg, { url: opts.cwd }).catch(() => null)))
|
||||
.map(pkg => resolvePackageJSON(pkg, { url: rootDir }).catch(() => null)))
|
||||
.then(r => (r.filter(Boolean) as string[]).sort((a, b) => b.length - a.length)[0])
|
||||
if (!nearestNuxtPkg) {
|
||||
throw new Error(`Cannot find any nuxt version from ${opts.cwd}`)
|
||||
}
|
||||
const pkg = await readPackageJSON(nearestNuxtPkg)
|
||||
|
||||
const rootDir = pathToFileURL(opts.cwd!).href
|
||||
|
||||
const { loadNuxt } = await importModule<typeof import('nuxt')>((pkg as any)._name || pkg.name, { paths: rootDir })
|
||||
const nuxt = await loadNuxt(opts)
|
||||
return nuxt
|
||||
}
|
||||
|
||||
export async function buildNuxt (nuxt: Nuxt): Promise<any> {
|
||||
const rootDir = pathToFileURL(nuxt.options.rootDir).href
|
||||
const rootDir = withTrailingSlash(pathToFileURL(nuxt.options.rootDir).href)
|
||||
|
||||
const { build } = await tryImportModule<typeof import('nuxt')>('nuxt-nightly', { paths: rootDir }) || await importModule<typeof import('nuxt')>('nuxt', { paths: rootDir })
|
||||
return runWithNuxtContext(nuxt, () => build(nuxt))
|
||||
|
33
packages/kit/test/load-nuxt.test.ts
Normal file
33
packages/kit/test/load-nuxt.test.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { mkdir, rm, writeFile } from 'node:fs/promises'
|
||||
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
||||
import { join, normalize } from 'pathe'
|
||||
import { withoutTrailingSlash } from 'ufo'
|
||||
import { x } from 'tinyexec'
|
||||
|
||||
import { loadNuxt } from '../src'
|
||||
|
||||
const repoRoot = withoutTrailingSlash(normalize(fileURLToPath(new URL('../../../', import.meta.url))))
|
||||
|
||||
describe('loadNuxt', () => {
|
||||
const tempDir = join(repoRoot, 'temp')
|
||||
|
||||
beforeAll(async () => {
|
||||
await mkdir(join(tempDir, 'nuxt'), { recursive: true })
|
||||
await writeFile(join(tempDir, 'package.json'), '{"dependencies":{"nuxt":"file:./nuxt"}}')
|
||||
await writeFile(join(tempDir, 'nuxt', 'package.json'), '{"name":"nuxt","type":"module","exports":{".":"./index.js"}}')
|
||||
await writeFile(join(tempDir, 'nuxt', 'index.js'), 'export const loadNuxt = (opts) => ({ name: "it me" })')
|
||||
await x('npm', ['install'], { nodeOptions: { cwd: tempDir } })
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await rm(tempDir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
it('respects correct directory', async () => {
|
||||
const nuxt = await loadNuxt({ cwd: tempDir })
|
||||
expect(nuxt).toStrictEqual({
|
||||
name: 'it me',
|
||||
})
|
||||
})
|
||||
})
|
@ -102,7 +102,7 @@
|
||||
"ofetch": "^1.4.1",
|
||||
"ohash": "^1.1.4",
|
||||
"on-change": "^5.0.1",
|
||||
"pathe": "^2.0.2",
|
||||
"pathe": "^2.0.3",
|
||||
"perfect-debounce": "^1.0.0",
|
||||
"pkg-types": "^1.3.1",
|
||||
"radix3": "^1.1.2",
|
||||
|
@ -49,7 +49,19 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||
.map(m => m.entryPath!),
|
||||
)
|
||||
|
||||
const sharedDirs = new Set<string>()
|
||||
const isNuxtV4 = nuxt.options.future?.compatibilityVersion === 4
|
||||
if (isNuxtV4 && (nuxt.options.nitro.imports !== false && nuxt.options.imports.scan !== false)) {
|
||||
for (const layer of nuxt.options._layers) {
|
||||
// Layer disabled scanning for itself
|
||||
if (layer.config?.imports?.scan === false) {
|
||||
continue
|
||||
}
|
||||
|
||||
sharedDirs.add(resolve(layer.config.rootDir, 'shared', 'utils'))
|
||||
sharedDirs.add(resolve(layer.config.rootDir, 'shared', 'types'))
|
||||
}
|
||||
}
|
||||
|
||||
const nitroConfig: NitroConfig = defu(nuxt.options.nitro, {
|
||||
debug: nuxt.options.debug ? nuxt.options.debug.nitro : false,
|
||||
@ -68,12 +80,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||
},
|
||||
imports: {
|
||||
autoImport: nuxt.options.imports.autoImport as boolean,
|
||||
dirs: isNuxtV4
|
||||
? [
|
||||
resolve(nuxt.options.rootDir, 'shared', 'utils'),
|
||||
resolve(nuxt.options.rootDir, 'shared', 'types'),
|
||||
]
|
||||
: [],
|
||||
dirs: [...sharedDirs],
|
||||
imports: [
|
||||
{
|
||||
as: '__buildAssetsURL',
|
||||
|
57
packages/nuxt/test/shared-dir-config.test.ts
Normal file
57
packages/nuxt/test/shared-dir-config.test.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { normalize } from 'pathe'
|
||||
import type { NuxtConfig } from '@nuxt/schema'
|
||||
import { loadNuxt } from '../src'
|
||||
|
||||
const fixtureDir = normalize(fileURLToPath(new URL('../../../test/fixtures/basic', import.meta.url)))
|
||||
|
||||
describe('loadNuxt', () => {
|
||||
it('does not add shared directories to nitro auto-imports in v3', async () => {
|
||||
const importDirs = await getNitroImportDirs({ future: { compatibilityVersion: 3 as any } })
|
||||
expect(normalizePaths(importDirs)).toMatchInlineSnapshot(`[]`)
|
||||
})
|
||||
it('adds shared directories for layers to nitro auto-imports in v4', async () => {
|
||||
const importDirs = await getNitroImportDirs({ future: { compatibilityVersion: 4 } })
|
||||
expect(normalizePaths(importDirs)).toMatchInlineSnapshot(`
|
||||
[
|
||||
"<rootDir>/shared/utils",
|
||||
"<rootDir>/shared/types",
|
||||
"<rootDir>/extends/bar/shared/utils",
|
||||
"<rootDir>/extends/bar/shared/types",
|
||||
"<rootDir>/extends/node_modules/foo/shared/utils",
|
||||
"<rootDir>/extends/node_modules/foo/shared/types",
|
||||
"<rootDir>/layers/bar/shared/utils",
|
||||
"<rootDir>/layers/bar/shared/types",
|
||||
]
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
function normalizePaths (arr: unknown[]) {
|
||||
const normalized = []
|
||||
for (const dir of arr) {
|
||||
normalized.push(typeof dir === 'string' ? dir.replace(fixtureDir, '<rootDir>') : dir)
|
||||
}
|
||||
return normalized
|
||||
}
|
||||
|
||||
async function getNitroImportDirs (overrides?: NuxtConfig) {
|
||||
const importDirs: unknown[] = []
|
||||
const nuxt = await loadNuxt({
|
||||
cwd: fixtureDir,
|
||||
ready: true,
|
||||
overrides: {
|
||||
...overrides,
|
||||
hooks: {
|
||||
'nitro:config' (config) {
|
||||
if (config.imports) {
|
||||
importDirs.push(...config.imports.dirs || [])
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
await nuxt.close()
|
||||
return importDirs
|
||||
}
|
@ -49,7 +49,7 @@
|
||||
"magic-string": "^0.30.17",
|
||||
"memfs": "^4.17.0",
|
||||
"ohash": "^1.1.4",
|
||||
"pathe": "^2.0.2",
|
||||
"pathe": "^2.0.3",
|
||||
"pify": "^6.1.0",
|
||||
"postcss": "^8.5.2",
|
||||
"postcss-import": "^16.1.0",
|
||||
|
@ -77,7 +77,7 @@
|
||||
"dependencies": {
|
||||
"consola": "^3.4.0",
|
||||
"defu": "^6.1.4",
|
||||
"pathe": "^2.0.2",
|
||||
"pathe": "^2.0.3",
|
||||
"std-env": "^3.8.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -175,10 +175,10 @@ export default defineResolvers({
|
||||
} satisfies NormalizedMetaObject)
|
||||
|
||||
// provides default charset and viewport if not set
|
||||
if (!resolved.meta.find(m => m.charset)?.charset) {
|
||||
if (!resolved.meta.find(m => m?.charset)?.charset) {
|
||||
resolved.meta.unshift({ charset: resolved.charset || 'utf-8' })
|
||||
}
|
||||
if (!resolved.meta.find(m => m.name === 'viewport')?.content) {
|
||||
if (!resolved.meta.find(m => m?.name === 'viewport')?.content) {
|
||||
resolved.meta.unshift({ name: 'viewport', content: resolved.viewport || 'width=device-width, initial-scale=1' })
|
||||
}
|
||||
|
||||
|
@ -19,12 +19,12 @@
|
||||
"devDependencies": {
|
||||
"@unocss/reset": "65.4.3",
|
||||
"beasties": "0.2.0",
|
||||
"html-validate": "9.2.1",
|
||||
"html-validate": "9.2.2",
|
||||
"htmlnano": "2.1.1",
|
||||
"jiti": "2.4.2",
|
||||
"knitwork": "1.2.0",
|
||||
"pathe": "2.0.2",
|
||||
"prettier": "3.5.0",
|
||||
"pathe": "2.0.3",
|
||||
"prettier": "3.5.1",
|
||||
"scule": "1.3.0",
|
||||
"svgo": "3.3.2",
|
||||
"tinyexec": "0.3.2",
|
||||
|
@ -47,7 +47,7 @@
|
||||
"knitwork": "^1.2.0",
|
||||
"magic-string": "^0.30.17",
|
||||
"mlly": "^1.7.4",
|
||||
"pathe": "^2.0.2",
|
||||
"pathe": "^2.0.3",
|
||||
"pkg-types": "^1.3.1",
|
||||
"postcss": "^8.5.2",
|
||||
"rollup-plugin-visualizer": "^5.14.0",
|
||||
|
@ -49,7 +49,7 @@
|
||||
"memfs": "^4.17.0",
|
||||
"mini-css-extract-plugin": "^2.9.2",
|
||||
"ohash": "^1.1.4",
|
||||
"pathe": "^2.0.2",
|
||||
"pathe": "^2.0.3",
|
||||
"pify": "^6.1.0",
|
||||
"postcss": "^8.5.2",
|
||||
"postcss-import": "^16.1.0",
|
||||
|
554
pnpm-lock.yaml
554
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -145,6 +145,7 @@ export async function getContributors () {
|
||||
'Authorization': `token ${process.env.GITHUB_TOKEN}`,
|
||||
},
|
||||
})
|
||||
if (!author) { continue }
|
||||
if (!contributors.some(c => c.username === author.login)) {
|
||||
contributors.push({ name: commit.author.name, username: author.login })
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user