Merge branch 'main' into fix/21721-spa-loading

This commit is contained in:
Nikolay 2024-11-27 01:09:12 +07:00 committed by GitHub
commit 86db10ea88
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
59 changed files with 2195 additions and 2120 deletions

View File

@ -1,4 +1,4 @@
FROM node:lts@sha256:de4c8be8232b7081d8846360d73ce6dbff33c6636f2259cd14d82c0de1ac3ff2
FROM node:lts@sha256:5c76d05034644fa8ecc9c2aa84e0a83cd981d0ef13af5455b87b9adf5b216561
RUN apt-get update && \
apt-get install -fy libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdbus-1-3 libdrm2 libxkbcommon0 libatspi2.0-0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libasound2 && \

View File

@ -46,7 +46,7 @@ jobs:
run: pnpm build
- name: Run benchmarks
uses: CodSpeedHQ/action@fa1dcde8d58f2ab0b407a6a24d6cc5a8c1444a8c # v3.1.0
uses: CodSpeedHQ/action@513a19673a831f139e8717bf45ead67e47f00044 # v3.2.0
with:
run: pnpm vitest bench
token: ${{ secrets.CODSPEED_TOKEN }}

View File

@ -75,7 +75,7 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Initialize CodeQL
uses: github/codeql-action/init@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1
uses: github/codeql-action/init@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
with:
config: |
paths:
@ -91,7 +91,7 @@ jobs:
queries: +security-and-quality
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1
uses: github/codeql-action/analyze@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
with:
category: "/language:javascript-typescript"
@ -248,7 +248,7 @@ jobs:
TEST_PAYLOAD: ${{ matrix.payload }}
SKIP_BUNDLE_SIZE: ${{ github.event_name != 'push' || matrix.env == 'dev' || matrix.builder == 'webpack' || matrix.context == 'default' || matrix.payload == 'js' || runner.os == 'Windows' }}
- uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0
- uses: codecov/codecov-action@015f24e6818733317a2da2edd6290ab26238649a # v5.0.7
if: github.event_name != 'push' && matrix.env == 'built' && matrix.builder == 'vite' && matrix.context == 'default' && matrix.os == 'ubuntu-latest' && matrix.manifest == 'manifest-on'
with:
token: ${{ secrets.CODECOV_TOKEN }}

View File

@ -19,4 +19,4 @@ jobs:
- name: 'Checkout Repository'
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: 'Dependency Review'
uses: actions/dependency-review-action@4081bf99e2866ebe428fc0477b69eb4fcda7220a # v4.4.0
uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4.5.0

View File

@ -29,7 +29,7 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Lychee link checker
uses: lycheeverse/lychee-action@f81112d0d2814ded911bd23e3beaa9dda9093915 # for v1.8.0
uses: lycheeverse/lychee-action@4aa18b6ccdac05029fab067313a6a04f941e6494 # for v1.8.0
with:
# arguments with file types to check
args: >-

View File

@ -1,84 +0,0 @@
name: release-pr
on:
issue_comment:
types: [created]
env:
# 7 GiB by default on GitHub, setting to 6 GiB
NODE_OPTIONS: --max-old-space-size=6144
permissions:
contents: read
jobs:
release-pr:
if: github.repository == 'nuxt/nuxt' && github.event.issue.pull_request && github.event.comment.body == '/trigger release'
concurrency:
group: release
permissions:
id-token: write
pull-requests: write
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Ensure action is by maintainer
uses: octokit/request-action@dad4362715b7fb2ddedf9772c8670824af564f0d # v2.4.0
id: check_role
with:
route: GET /repos/nuxt/nuxt/collaborators/${{ github.event.comment.user.login }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get PR Info
id: pr
env:
PR_NUMBER: ${{ github.event.issue.number }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
COMMENT_AT: ${{ github.event.comment.created_at }}
run: |
pr="$(gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/"${GH_REPO}"/pulls/"${PR_NUMBER}")"
head_sha="$(echo "$pr" | jq -r .head.sha)"
updated_at="$(echo "$pr" | jq -r .updated_at)"
if [[ $(date -d "$updated_at" +%s) -gt $(date -d "$COMMENT_AT" +%s) ]]; then
exit 1
fi
echo "head_sha=$head_sha" >> "$GITHUB_OUTPUT"
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ steps.pr.outputs.head_sha }}
fetch-depth: 1
- run: corepack enable
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: 20
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm build
- name: Release Edge
run: ./scripts/release-edge.sh pr-${{ github.event.issue.number }}
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
NPM_CONFIG_PROVENANCE: true
- name: Post comment
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `:rocket: Release triggered! You can now install [nuxt@npm:nuxt-nightly@pr-${{ github.event.issue.number }}](https://www.npmjs.com/package/nuxt-nightly/v/pr-${{ github.event.issue.number }})`
})

View File

@ -68,7 +68,7 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1
uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
if: github.repository == 'nuxt/nuxt' && success()
with:
sarif_file: results.sarif

View File

@ -21,8 +21,8 @@ Or follow the steps below to set up a new Nuxt project on your computer.
<!-- markdownlint-disable-next-line MD001 -->
#### Prerequisites
- **Node.js** - [`v18.0.0`](https://nodejs.org/en) or newer
- **Text editor** - We recommend [Visual Studio Code](https://code.visualstudio.com/) with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (previously known as Volar)
- **Node.js** - [`18.x`](https://nodejs.org/en) or newer (but we recommend the [active LTS release](https://github.com/nodejs/release#release-schedule))
- **Text editor** - There is no IDE requirement, but we recommend [Visual Studio Code](https://code.visualstudio.com/) with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (previously known as Volar) or [WebStorm](https://www.jetbrains.com/webstorm/), which, along with [other JetBrains IDEs](https://www.jetbrains.com/ides/), offers great Nuxt support right out-of-the-box.
- **Terminal** - In order to run Nuxt commands
::note

View File

@ -139,7 +139,7 @@ If you only have a single layout in your application, we recommend using [`app.v
If you want to create more layouts and learn how to use them in your pages, find more information in the [Layouts section](/docs/guide/directory-structure/layouts).
## Advanced: Extending the HTML template
## Advanced: Extending the HTML Template
::note
If you only need to modify the `<head>`, you can refer to the [SEO and meta section](/docs/getting-started/seo-meta).

View File

@ -8,7 +8,7 @@ navigation.icon: i-ph-exclude-square
Nuxt leverages Vue's [`<Transition>`](https://vuejs.org/guide/built-ins/transition.html#the-transition-component) component to apply transitions between pages and layouts.
::
## Page transitions
## Page Transitions
You can enable page transitions to apply an automatic transition for all your [pages](/docs/guide/directory-structure/pages).
@ -113,7 +113,7 @@ Moving to the about page will add the 3d rotation effect:
<source src="https://res.cloudinary.com/nuxt/video/upload/v1665063233/nuxt3/nuxt3-page-transitions-cutom.mp4" type="video/mp4">
</video>
## Layout transitions
## Layout Transitions
You can enable layout transitions to apply an automatic transition for all your [layouts](/docs/guide/directory-structure/layouts).
@ -225,7 +225,7 @@ definePageMeta({
</script>
```
## Global settings
## Global Settings
You can customize these default transition names globally using `nuxt.config`.
@ -468,6 +468,6 @@ export default defineNuxtRouteMiddleware(to => {
})
```
### Known issues
### Known Issues
- If you perform data fetching within your page setup functions, that you may wish to reconsider using this feature for the moment. (By design, View Transitions completely freeze DOM updates whilst they are taking place.) We're looking at restrict the View Transition to the final moments before `<Suspense>` resolves, but in the interim you may want to consider carefully whether to adopt this feature if this describes you.

View File

@ -19,8 +19,7 @@ The minimal `package.json` of your Nuxt application should looks like:
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
},
"devDependencies": {
"@nuxt/devtools": "latest",
"dependencies": {
"nuxt": "latest",
"vue": "latest",
"vue-router": "latest"

View File

@ -41,6 +41,10 @@ Remote islands need `experimental.componentIslands` to be `'local+remote'` in yo
It is strongly discouraged to enable `dangerouslyLoadClientComponents` as you can't trust a remote server's javascript.
::
::note
By default, component islands are scanned from the `~/components/islands/` directory. So the `~/components/islands/MyIsland.vue` component could be rendered with `<NuxtIsland name="MyIsland" />`.
::
## Slots
Slots can be passed to an island component if declared.

View File

@ -1,7 +1,6 @@
---
title: "onPrehydrate"
description: "Use onPrehydrate to run a callback on the client immediately before
Nuxt hydrates the page."
description: "Use onPrehydrate to run a callback on the client immediately before Nuxt hydrates the page."
links:
- label: Source
icon: i-simple-icons-github

View File

@ -54,7 +54,7 @@ const { data } = await useAsyncData('todos', () => $fetch('/api/todos'))
const newTodo = ref('')
const previousTodos = ref([])
// Access to the cached value of useFetch in todos.vue
// Access to the cached value of useAsyncData in todos.vue
const { data: todos } = useNuxtData('todos')
const { data } = await useFetch('/api/addTodo', {

View File

@ -39,7 +39,7 @@ const title = ref('My title')
useSeoMeta({
title,
description: () => `description: ${title.value}`
description: () => `This is a description for the ${title.value} page`
})
</script>
```

View File

@ -41,8 +41,8 @@ In addition to the Nuxt framework, there are modules that are vital for the ecos
Module | Status | Nuxt Support | Repository | Description
------------------------------------|---------------------|--------------|------------|-------------------
[Scripts](https://scripts.nuxt.com) | Public Beta | 3.x | [nuxt/scripts](https://github.com/nuxt/scripts) | Easy 3rd party script management.
Auth Utils | Planned | 3.x | `nuxt/auth-utils` to be announced | The temporary repository [atinux/nuxt-auth-utils](https://github.com/atinux/nuxt-auth-utils) is available while awaiting its official integration into Nuxt via RFC.
A11y | Planned | 3.x | `nuxt/a11y` to be announced | Accessibility hinting and utilities [nuxt/nuxt#23255](https://github.com/nuxt/nuxt/issues/23255)
Auth | Planned | 3.x | `nuxt/auth` to be announced | Support is planned after session support.
Hints | Planned | 3.x | `nuxt/hints` to be announced | Guidance and suggestions for enhancing development practices.
## Release Cycle

View File

@ -72,8 +72,9 @@ export default createConfigForNuxt({
'error',
{
argsIgnorePattern: '^_',
destructuredArrayIgnorePattern: '^_',
ignoreRestSiblings: true,
varsIgnorePattern: '^_',
varsIgnorePattern: '',
},
],
'@typescript-eslint/triple-slash-reference': 'off',
@ -188,7 +189,6 @@ export default createConfigForNuxt({
},
},
// Sort rule keys in eslint config
// @ts-expect-error incorrect types 🤔
{
files: ['**/eslint.config.mjs'],
name: 'local/sort-eslint-config',

View File

@ -1,27 +1,60 @@
{
"$schema": "https://unpkg.com/knip@5/schema.json",
"ignoreBinaries": [
"prepack"
],
"ignoreWorkspaces": ["test/fixtures/basic"],
"ignoreDependencies": [
"bing",
"uno.css"
],
"workspaces": {
".": {
"entry": [
"scripts/*",
"test/*",
"test/fixtures/*"
"scripts/*"
]
},
"test/fixtures/*": {
"entry": [
"nuxt.config.{js,ts}",
"modules/*.ts",
"types.ts"
]
},
"packages/*": {
"entry": [
"src/index.ts",
"src/runtime/**/*.ts"
"src/runtime/**/*.{js,ts,mjs}"
]
},
"packages/nuxt": {
"entry": [
"src/app/**/*.ts",
"src/app/*.ts",
"src/*/runtime/**/*.ts",
"src/*/runtime/**/*.{ts,js}",
"src/core/templates.ts",
"src/index.ts"
]
},
"packages/rspack": {
"entry": [
"../webpack/src/index.ts",
"../webpack/src/runtime/**/*.{js,ts,mjs}",
"builder.mjs"
]
},
"packages/ui-templates": {
"entry": [
"lib/*.ts",
"styles.ts"
]
},
"packages/webpack": {
"entry": [
"src/index.ts",
"src/runtime/**/*.{js,ts,mjs}",
"builder.mjs"
]
}
}
}

View File

@ -17,5 +17,8 @@ export default defineNuxtConfig({
},
],
pages: process.env.DOCS_TYPECHECK === 'true',
typescript: { shim: process.env.DOCS_TYPECHECK === 'true' },
typescript: {
shim: process.env.DOCS_TYPECHECK === 'true',
hoist: ['@vitejs/plugin-vue', 'vue-router'],
},
})

View File

@ -17,7 +17,7 @@
"lint:fix": "eslint . --cache --fix",
"lint:docs": "markdownlint ./docs && case-police 'docs/**/*.md' *.md",
"lint:docs:fix": "markdownlint ./docs --fix && case-police 'docs/**/*.md' *.md --fix",
"lint:knip": "pnpx knip",
"lint:knip": "knip",
"play": "nuxi dev playground",
"play:build": "nuxi build playground",
"play:generate": "nuxi generate playground",
@ -37,88 +37,84 @@
"@nuxt/kit": "workspace:*",
"@nuxt/rspack-builder": "workspace:*",
"@nuxt/schema": "workspace:*",
"@nuxt/ui-templates": "workspace:*",
"@nuxt/vite-builder": "workspace:*",
"@nuxt/webpack-builder": "workspace:*",
"@types/node": "22.9.0",
"@unhead/dom": "1.11.11",
"@unhead/shared": "1.11.11",
"@unhead/vue": "1.11.11",
"@unhead/schema": "1.11.11",
"@unhead/ssr": "1.11.11",
"@vue/compiler-core": "3.5.12",
"@vue/compiler-dom": "3.5.12",
"@vue/shared": "3.5.12",
"@types/node": "22.10.0",
"@unhead/dom": "1.11.13",
"@unhead/schema": "1.11.13",
"@unhead/shared": "1.11.13",
"@unhead/ssr": "1.11.13",
"@unhead/vue": "1.11.13",
"@vue/compiler-core": "3.5.13",
"@vue/compiler-dom": "3.5.13",
"@vue/shared": "3.5.13",
"c12": "2.0.1",
"h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
"jiti": "2.4.0",
"magic-string": "^0.30.12",
"magic-string": "^0.30.14",
"nitro": "npm:nitro-nightly@3.0.0-beta-28796231.359af68d",
"nuxt": "workspace:*",
"ohash": "1.1.4",
"postcss": "8.4.47",
"rollup": "4.24.4",
"postcss": "8.4.49",
"rollup": "4.27.4",
"send": ">=1.1.0",
"typescript": "5.6.3",
"ufo": "1.5.4",
"unbuild": "3.0.0-rc.11",
"unhead": "1.11.11",
"vite": "5.4.10",
"vue": "3.5.12"
"unhead": "1.11.13",
"vite": "6.0.0",
"vue": "3.5.13"
},
"devDependencies": {
"@eslint/js": "9.14.0",
"@nuxt/eslint-config": "0.6.1",
"@nuxt/eslint-config": "0.7.2",
"@nuxt/kit": "workspace:*",
"@nuxt/rspack-builder": "workspace:*",
"@nuxt/test-utils": "3.14.4",
"@nuxt/webpack-builder": "workspace:*",
"@testing-library/vue": "8.1.0",
"@types/eslint__js": "8.42.3",
"@types/node": "22.9.0",
"@types/node": "22.10.0",
"@types/semver": "7.5.8",
"@unhead/schema": "1.11.11",
"@unhead/vue": "1.11.11",
"@vitejs/plugin-vue": "5.1.4",
"@vitest/coverage-v8": "2.1.4",
"@unhead/schema": "1.11.13",
"@unhead/vue": "1.11.13",
"@vitest/coverage-v8": "2.1.6",
"@vue/test-utils": "2.4.6",
"autoprefixer": "10.4.20",
"case-police": "0.7.0",
"case-police": "0.7.2",
"changelogen": "0.5.7",
"consola": "3.2.3",
"cssnano": "7.0.6",
"destr": "2.0.3",
"devalue": "5.1.1",
"eslint": "9.14.0",
"eslint": "9.15.0",
"eslint-plugin-no-only-tests": "3.3.0",
"eslint-plugin-perfectionist": "3.9.1",
"eslint-plugin-perfectionist": "4.1.2",
"eslint-typegen": "0.3.2",
"h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
"happy-dom": "15.11.0",
"happy-dom": "15.11.6",
"jiti": "2.4.0",
"markdownlint-cli": "0.42.0",
"knip": "5.38.0",
"markdownlint-cli": "0.43.0",
"nitro": "npm:nitro-nightly@3.0.0-beta-28796231.359af68d",
"nuxi": "3.15.0",
"nuxt": "workspace:*",
"nuxt-content-twoslash": "0.1.1",
"ofetch": "1.4.1",
"pathe": "1.1.2",
"playwright-core": "1.48.2",
"playwright-core": "1.49.0",
"rimraf": "6.0.1",
"semver": "7.6.3",
"sherif": "1.0.1",
"sherif": "1.0.2",
"std-env": "3.8.0",
"tinyexec": "0.3.1",
"tinyglobby": "0.2.10",
"typescript": "5.6.3",
"ufo": "1.5.4",
"vitest": "2.1.4",
"vitest": "2.1.6",
"vitest-environment-nuxt": "1.0.1",
"vue": "3.5.12",
"vue-router": "4.4.5",
"vue": "3.5.13",
"vue-tsc": "2.1.10"
},
"packageManager": "pnpm@9.12.3",
"packageManager": "pnpm@9.14.2",
"engines": {
"node": "^16.10.0 || >=18.0.0"
},

View File

@ -1,6 +1,6 @@
{
"name": "@nuxt/kit",
"version": "3.12.2",
"version": "4.0.0-0",
"repository": {
"type": "git",
"url": "git+https://github.com/nuxt/nuxt.git",
@ -33,28 +33,27 @@
"destr": "^2.0.3",
"errx": "^0.1.0",
"globby": "^14.0.2",
"hash-sum": "^2.0.0",
"ignore": "^6.0.2",
"jiti": "^2.4.0",
"klona": "^2.0.6",
"mlly": "^1.7.2",
"mlly": "^1.7.3",
"ohash": "^1.1.4",
"pathe": "^1.1.2",
"pkg-types": "^1.2.1",
"scule": "^1.3.0",
"semver": "^7.6.3",
"ufo": "^1.5.4",
"unctx": "^2.3.1",
"unimport": "^3.13.1",
"unimport": "^3.13.3",
"untyped": "^1.5.1"
},
"devDependencies": {
"@rspack/core": "1.1.0",
"@types/hash-sum": "1.0.2",
"@rspack/core": "1.1.4",
"@types/semver": "7.5.8",
"nitro": "npm:nitro-nightly@3.0.0-beta-28796231.359af68d",
"unbuild": "3.0.0-rc.11",
"vite": "5.4.10",
"vitest": "2.1.4",
"vite": "6.0.0",
"vitest": "2.1.6",
"webpack": "5.96.1"
},
"engines": {

View File

@ -28,7 +28,7 @@ export type { AddPluginOptions } from './plugin'
export { createResolver, findPath, resolveAlias, resolveFiles, resolveNuxtModule, resolvePath } from './resolve'
export type { ResolvePathOptions, Resolver } from './resolve'
export { addServerHandler, addDevServerHandler, addServerPlugin, addPrerenderRoutes, useNitro, addServerImports, addServerImportsDir, addServerScanDir } from './nitro'
export { addTemplate, addTypeTemplate, normalizeTemplate, updateTemplates, writeTypes } from './template'
export { addTemplate, addServerTemplate, addTypeTemplate, normalizeTemplate, updateTemplates, writeTypes } from './template'
export { logger, useLogger } from './logger'
// Internal Utils

View File

@ -65,7 +65,7 @@ function _defineNuxtModule<
const optionsDefaults: TOptionsDefaults =
module.defaults instanceof Function
? module.defaults(nuxt)
? await module.defaults(nuxt)
: module.defaults ?? <TOptionsDefaults> {}
let options = defu(inlineOptions, nuxtConfigOptions, optionsDefaults)

View File

@ -5,6 +5,7 @@ import { dirname, isAbsolute, join, resolve } from 'pathe'
import { defu } from 'defu'
import { createJiti } from 'jiti'
import { resolve as resolveModule } from 'mlly'
import { isRelative } from 'ufo'
import { useNuxt } from '../context'
import { resolveAlias, resolvePath } from '../resolve'
import { logger } from '../logger'
@ -78,14 +79,23 @@ export async function loadNuxtModuleInstance (nuxtModule: string | NuxtModule, n
// Import if input is string
if (typeof nuxtModule === 'string') {
const paths = [join(nuxtModule, 'nuxt'), join(nuxtModule, 'module'), nuxtModule, join(nuxt.options.rootDir, nuxtModule)]
const paths = new Set<string>()
nuxtModule = resolveAlias(nuxtModule, nuxt.options.alias)
if (isRelative(nuxtModule)) {
nuxtModule = resolve(nuxt.options.rootDir, nuxtModule)
}
paths.add(join(nuxtModule, 'nuxt'))
paths.add(join(nuxtModule, 'module'))
paths.add(nuxtModule)
for (const path of paths) {
for (const parentURL of nuxt.options.modulesDir) {
try {
const resolved = resolveAlias(path, nuxt.options.alias)
const src = isAbsolute(resolved)
? pathToFileURL(await resolvePath(resolved, { cwd: parentURL, fallbackToOriginal: false, extensions: nuxt.options.extensions })).href
: await resolveModule(resolved, { url: pathToFileURL(parentURL.replace(/\/node_modules\/?$/, '')), extensions: nuxt.options.extensions })
const src = isAbsolute(path)
? pathToFileURL(await resolvePath(path, { cwd: parentURL, fallbackToOriginal: false, extensions: nuxt.options.extensions })).href
: await resolveModule(path, { url: pathToFileURL(parentURL.replace(/\/node_modules\/?$/, '')), extensions: nuxt.options.extensions })
nuxtModule = await jiti.import(src, { default: true }) as NuxtModule

View File

@ -1,6 +1,6 @@
import { existsSync, promises as fsp } from 'node:fs'
import { basename, isAbsolute, join, parse, relative, resolve } from 'pathe'
import hash from 'hash-sum'
import { hash } from 'ohash'
import type { Nuxt, NuxtServerTemplate, NuxtTemplate, NuxtTypeTemplate, ResolvedNuxtTemplate, TSReference } from '@nuxt/schema'
import { withTrailingSlash } from 'ufo'
import { defu } from 'defu'
@ -22,9 +22,9 @@ export function addTemplate<T> (_template: NuxtTemplate<T> | string) {
// Normalize template
const template = normalizeTemplate(_template)
// Remove any existing template with the same filename
// Remove any existing template with the same destination path
nuxt.options.build.templates = nuxt.options.build.templates
.filter(p => normalizeTemplate(p).filename !== template.filename)
.filter(p => normalizeTemplate(p).dst !== template.dst)
// Add to templates array
nuxt.options.build.templates.push(template)

View File

@ -60,16 +60,16 @@
},
"dependencies": {
"@nuxt/devalue": "^2.0.2",
"@nuxt/devtools": "^1.6.0",
"@nuxt/devtools": "^1.6.1",
"@nuxt/kit": "workspace:*",
"@nuxt/schema": "workspace:*",
"@nuxt/telemetry": "^2.6.0",
"@nuxt/vite-builder": "workspace:*",
"@unhead/dom": "^1.11.11",
"@unhead/shared": "^1.11.11",
"@unhead/ssr": "^1.11.11",
"@unhead/vue": "^1.11.11",
"@vue/shared": "^3.5.12",
"@unhead/dom": "^1.11.13",
"@unhead/shared": "^1.11.13",
"@unhead/ssr": "^1.11.13",
"@unhead/vue": "^1.11.13",
"@vue/shared": "^3.5.13",
"acorn": "8.14.0",
"c12": "^2.0.1",
"chokidar": "^4.0.1",
@ -91,8 +91,8 @@
"jiti": "^2.4.0",
"klona": "^2.0.6",
"knitwork": "^1.1.0",
"magic-string": "^0.30.12",
"mlly": "^1.7.2",
"magic-string": "^0.30.14",
"mlly": "^1.7.3",
"nanotar": "^0.1.1",
"nitro": "npm:nitro-nightly@3.0.0-beta-28796231.359af68d",
"nuxi": "^3.15.0",
@ -106,34 +106,33 @@
"scule": "^1.3.0",
"semver": "^7.6.3",
"std-env": "^3.8.0",
"strip-literal": "^2.1.0",
"strip-literal": "^2.1.1",
"tinyglobby": "0.2.10",
"ufo": "^1.5.4",
"ultrahtml": "^1.5.3",
"uncrypto": "^0.1.3",
"unctx": "^2.3.1",
"unenv": "^1.10.0",
"unhead": "^1.11.11",
"unimport": "^3.13.1",
"unplugin": "^1.15.0",
"unhead": "^1.11.13",
"unimport": "^3.13.3",
"unplugin": "^1.16.0",
"unplugin-vue-router": "^0.10.8",
"unstorage": "^1.13.1",
"untyped": "^1.5.1",
"vue": "^3.5.12",
"vue": "^3.5.13",
"vue-bundle-renderer": "^2.1.1",
"vue-devtools-stub": "^0.1.0",
"vue-router": "^4.4.5"
"vue-router": "^4.5.0"
},
"devDependencies": {
"@nuxt/scripts": "0.9.5",
"@nuxt/ui-templates": "1.3.4",
"@parcel/watcher": "2.5.0",
"@types/estree": "1.0.6",
"@vitejs/plugin-vue": "5.1.4",
"@vue/compiler-sfc": "3.5.12",
"@vitejs/plugin-vue": "5.2.1",
"@vue/compiler-sfc": "3.5.13",
"unbuild": "3.0.0-rc.11",
"vite": "5.4.10",
"vitest": "2.1.4"
"vite": "6.0.0",
"vitest": "2.1.6"
},
"peerDependencies": {
"@parcel/watcher": "^2.1.0",

View File

@ -16,7 +16,6 @@ import layouts from '#build/layouts'
// @ts-expect-error virtual file
import { appLayoutTransition as defaultLayoutTransition } from '#build/nuxt.config.mjs'
// TODO: revert back to defineAsyncComponent when https://github.com/vuejs/core/issues/6638 is resolved
const LayoutLoader = defineComponent({
name: 'LayoutLoader',
inheritAttrs: false,
@ -24,13 +23,10 @@ const LayoutLoader = defineComponent({
name: String,
layoutProps: Object,
},
async setup (props, context) {
setup (props, context) {
// This is a deliberate hack - this component must always be called with an explicit key to ensure
// that setup reruns when the name changes.
const LayoutComponent = await layouts[props.name]().then((r: any) => r.default || r)
return () => h(LayoutComponent, props.layoutProps, context.slots)
return () => h(layouts[props.name], props.layoutProps, context.slots)
},
})

View File

@ -506,9 +506,9 @@ function useObserver (): { observe: ObserveFn } | undefined {
observer.observe(element)
return () => {
callbacks.delete(element)
observer!.unobserve(element)
observer?.unobserve(element)
if (callbacks.size === 0) {
observer!.disconnect()
observer?.disconnect()
observer = null
}
}

View File

@ -525,7 +525,7 @@ function clearNuxtDataByKey (nuxtApp: NuxtApp, key: string): void {
}
if (nuxtApp._asyncData[key]) {
nuxtApp._asyncData[key]!.data.value = nuxtApp._asyncData[key]!._default()
nuxtApp._asyncData[key]!.data.value = unref(nuxtApp._asyncData[key]!._default())
nuxtApp._asyncData[key]!.error.value = undefined
nuxtApp._asyncData[key]!.pending.value = false
nuxtApp._asyncData[key]!.status.value = 'idle'

View File

@ -1,6 +1,7 @@
import { createUnplugin } from 'unplugin'
import MagicString from 'magic-string'
import type { Component } from 'nuxt/schema'
import type { Program } from 'acorn'
import { SX_RE, isVue } from '../../core/utils'
interface NameDevPluginOptions {
@ -34,6 +35,16 @@ export const ComponentNamePlugin = (options: NameDevPluginOptions) => createUnpl
const s = new MagicString(code)
s.replace(NAME_RE, `__name: ${JSON.stringify(component.pascalName)}`)
// Without setup function, vue compiler does not generate __name
if (!s.hasChanged()) {
const ast = this.parse(code) as Program
const exportDefault = ast.body.find(node => node.type === 'ExportDefaultDeclaration')
if (exportDefault) {
const { start, end } = exportDefault.declaration
s.overwrite(start, end, `Object.assign(${code.slice(start, end)}, { __name: ${JSON.stringify(component.pascalName)} })`)
}
}
if (s.hasChanged()) {
return {
code: s.toString(),

View File

@ -10,7 +10,6 @@ import { generateApp as _generateApp, createApp } from './app'
import { checkForExternalConfigurationFiles } from './external-config-files'
import { cleanupCaches, getVueHash } from './cache'
const IS_RESTART_PATH_RE = /^(?:app\.|error\.|plugins\/|middleware\/|layouts\/)/i
export async function build (nuxt: Nuxt) {
const app = createApp(nuxt)
nuxt.apps.default = app
@ -21,19 +20,24 @@ export async function build (nuxt: Nuxt) {
if (nuxt.options.dev) {
watch(nuxt)
nuxt.hook('builder:watch', async (event, relativePath) => {
if (event === 'change') { return }
// Unset mainComponent and errorComponent if app or error component is changed
if (event === 'add' || event === 'unlink') {
const path = resolve(nuxt.options.srcDir, relativePath)
const relativePaths = nuxt.options._layers.map(l => relative(l.config.srcDir || l.cwd, path))
const restartPath = relativePaths.find(relativePath => IS_RESTART_PATH_RE.test(relativePath))
if (restartPath) {
if (restartPath.startsWith('app')) {
for (const layer of nuxt.options._layers) {
const relativePath = relative(layer.config.srcDir || layer.cwd, path)
if (relativePath.match(/^app\./i)) {
app.mainComponent = undefined
break
}
if (restartPath.startsWith('error')) {
if (relativePath.match(/^error\./i)) {
app.errorComponent = undefined
break
}
}
}
// Recompile app templates
await generateApp()
}
})
nuxt.hook('builder:generateApp', (options) => {
// Bypass debounce if we are selectively invalidating templates

View File

@ -6,7 +6,7 @@ import { isIgnored } from '@nuxt/kit'
import type { Nuxt, NuxtConfig, NuxtConfigLayer } from '@nuxt/schema'
import { hash, murmurHash, objectHash } from 'ohash'
import { glob } from 'tinyglobby'
import _consola, { consola } from 'consola'
import { consola } from 'consola'
import { dirname, join, relative } from 'pathe'
import { createTar, parseTar } from 'nanotar'
import type { TarFileInput } from 'nanotar'

View File

@ -1,6 +1,5 @@
import { findPath, logger } from '@nuxt/kit'
import { basename } from 'pathe'
import { generateApp as _generateApp } from './app'
/**
* Check for those external configuration files that are not compatible with Nuxt,

View File

@ -5,7 +5,6 @@ import { createDebugger, createHooks } from 'hookable'
import ignore from 'ignore'
import type { LoadNuxtOptions } from '@nuxt/kit'
import { addBuildPlugin, addComponent, addPlugin, addPluginTemplate, addRouteMiddleware, addServerPlugin, addVitePlugin, addWebpackPlugin, installModule, loadNuxtConfig, logger, nuxtCtx, resolveAlias, resolveFiles, resolveIgnorePatterns, resolvePath, tryResolveModule, useNitro } from '@nuxt/kit'
import { resolvePath as _resolvePath } from 'mlly'
import type { Nuxt, NuxtHooks, NuxtModule, NuxtOptions } from 'nuxt/schema'
import type { PackageJson } from 'pkg-types'
import { readPackageJSON } from 'pkg-types'
@ -41,6 +40,7 @@ import { initNitro } from './nitro'
import schemaModule from './schema'
import { RemovePluginMetadataPlugin } from './plugins/plugin-metadata'
import { AsyncContextInjectionPlugin } from './plugins/async-context'
import { ComposableKeysPlugin } from './plugins/composable-keys'
import { resolveDeepImportsPlugin } from './plugins/resolve-deep-imports'
import { prehydrateTransformPlugin } from './plugins/prehydrate'
import { VirtualFSPlugin } from './plugins/virtual'
@ -248,6 +248,13 @@ async function initNuxt (nuxt: Nuxt) {
// Add plugin normalization plugin
addBuildPlugin(RemovePluginMetadataPlugin(nuxt))
// Add keys for useFetch, useAsyncData, etc.
addBuildPlugin(ComposableKeysPlugin({
sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client,
rootDir: nuxt.options.rootDir,
composables: nuxt.options.optimization.keyedComposables,
}))
// shared folder import protection
const sharedDir = withTrailingSlash(resolve(nuxt.options.rootDir, nuxt.options.dir.shared))
const relativeSharedDir = withTrailingSlash(relative(nuxt.options.rootDir, resolve(nuxt.options.rootDir, nuxt.options.dir.shared)))
@ -409,11 +416,15 @@ async function initNuxt (nuxt: Nuxt) {
}
// Add <NuxtWelcome>
// TODO: revert when deep server component config is properly bundle-split: https://github.com/nuxt/nuxt/pull/29956
const islandsConfig = nuxt.options.experimental.componentIslands
if (nuxt.options.dev || !(typeof islandsConfig === 'object' && islandsConfig.selectiveClient === 'deep')) {
addComponent({
name: 'NuxtWelcome',
priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/welcome'),
})
}
addComponent({
name: 'NuxtLayout',

View File

@ -9,7 +9,7 @@ import type { CallExpression, Pattern } from 'estree'
import { parseQuery, parseURL } from 'ufo'
import escapeRE from 'escape-string-regexp'
import { findStaticImports, parseStaticImport } from 'mlly'
import { matchWithStringOrRegex } from '../utils'
import { matchWithStringOrRegex } from '../utils/plugins'
interface ComposableKeysOptions {
sourcemap: boolean
@ -22,7 +22,7 @@ const NUXT_LIB_RE = /node_modules\/(?:nuxt|nuxt3|nuxt-nightly)\//
const SUPPORTED_EXT_RE = /\.(?:m?[jt]sx?|vue)/
const SCRIPT_RE = /(?<=<script[^>]*>)[\s\S]*?(?=<\/script>)/i
export const composableKeysPlugin = createUnplugin((options: ComposableKeysOptions) => {
export const ComposableKeysPlugin = (options: ComposableKeysOptions) => createUnplugin(() => {
const composableMeta: Record<string, any> = {}
const composableLengths = new Set<number>()
const keyedFunctions = new Set<string>()

View File

@ -36,7 +36,7 @@ export const createImportProtectionPatterns = (nuxt: { options: NuxtOptions }, o
])
}
for (const i of [/(^|node_modules\/)@nuxt\/(kit|test-utils)/, /(^|node_modules\/)nuxi/, /(^|node_modules\/)nitro(?:pack)?(?:-nightly)?(?:$|\/)(?!(?:dist\/)?(?:presets|runtime|types))/, /(^|node_modules\/)nuxt\/(config|kit|schema)/]) {
for (const i of [/(^|node_modules\/)@nuxt\/(kit|test-utils)/, /(^|node_modules\/)nuxi/, /(^|node_modules\/)nitro(?:pack)?(?:-nightly)?(?:$|\/)(?!(?:dist\/)?(?:node_modules|presets|runtime|types))/, /(^|node_modules\/)nuxt\/(config|kit|schema)/]) {
patterns.push([i, `This module cannot be imported in ${context}.`])
}

View File

@ -125,18 +125,26 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
const plugin = nuxt.apps.default?.plugins.find(p => p.src === id)
if (!plugin) { return }
const s = new MagicString(code)
if (!code.trim()) {
logger.warn(`Plugin \`${plugin.src}\` has no content.`)
return {
code: 'export default () => {}',
map: null,
}
}
const exports = findExports(code)
const defaultExport = exports.find(e => e.type === 'default' || e.name === 'default')
if (!defaultExport) {
logger.warn(`Plugin \`${plugin.src}\` has no default export and will be ignored at build time. Add \`export default defineNuxtPlugin(() => {})\` to your plugin.`)
s.overwrite(0, code.length, 'export default () => {}')
return {
code: s.toString(),
map: nuxt.options.sourcemap.client || nuxt.options.sourcemap.server ? s.generateMap({ hires: true }) : null,
code: 'export default () => {}',
map: null,
}
}
const s = new MagicString(code)
let wrapped = false
const wrapperNames = new Set(['defineNuxtPlugin', 'definePayloadPlugin'])

View File

@ -285,9 +285,10 @@ export const layoutTemplate: NuxtTemplate = {
filename: 'layouts.mjs',
getContents ({ app }) {
const layoutsObject = genObjectFromRawEntries(Object.values(app.layouts).map(({ name, file }) => {
return [name, genDynamicImport(file)]
return [name, `defineAsyncComponent(${genDynamicImport(file)})`]
}))
return [
`import { defineAsyncComponent } from 'vue'`,
`export default ${layoutsObject}`,
].join('\n')
},

View File

@ -54,3 +54,13 @@ export function getLoader (id: string): 'vue' | 'ts' | 'tsx' | null {
}
return ext.endsWith('x') ? 'tsx' : 'ts'
}
export function matchWithStringOrRegex (value: string, matcher: string | RegExp) {
if (typeof matcher === 'string') {
return value === matcher
} else if (matcher instanceof RegExp) {
return matcher.test(value)
}
return false
}

View File

@ -107,12 +107,9 @@ export default defineNuxtModule<Partial<ImportsOptions>>({
const priorities = nuxt.options._layers.map((layer, i) => [layer.config.srcDir, -i] as const).sort(([a], [b]) => b.length - a.length)
const IMPORTS_TEMPLATE_RE = /\/imports\.(?:d\.ts|mjs)$/
function isImportsTemplate (template: ResolvedNuxtTemplate) {
return [
'/types/imports.d.ts',
'/imports.d.ts',
'/imports.mjs',
].some(i => template.filename.endsWith(i))
return IMPORTS_TEMPLATE_RE.test(template.filename)
}
const regenerateImports = async () => {

View File

@ -242,6 +242,8 @@ const vueTypesPreset = defineUnimportPreset({
'Component',
'ComponentPublicInstance',
'ComputedRef',
'DirectiveBinding',
'ExtractDefaultPropTypes',
'ExtractPropTypes',
'ExtractPublicPropTypes',
'InjectionKey',
@ -250,6 +252,7 @@ const vueTypesPreset = defineUnimportPreset({
'MaybeRef',
'MaybeRefOrGetter',
'VNode',
'WritableComputedRef',
],
})

View File

@ -77,8 +77,8 @@ export async function resolvePagesRoutes (): Promise<NuxtPage[]> {
} else {
const augmentedPages = await augmentPages(pages, nuxt.vfs)
await nuxt.callHook('pages:extend', pages)
await augmentPages(pages, nuxt.vfs, augmentedPages)
augmentedPages.clear()
await augmentPages(pages, nuxt.vfs, { pagesToSkip: augmentedPages })
augmentedPages?.clear()
}
await nuxt.callHook('pages:resolved', pages)
@ -155,9 +155,14 @@ export function generateRoutesFromFiles (files: ScannedFile[], options: Generate
return prepareRoutes(routes)
}
export async function augmentPages (routes: NuxtPage[], vfs: Record<string, string>, augmentedPages = new Set<string>()) {
interface AugmentPagesContext {
pagesToSkip?: Set<string>
augmentedPages?: Set<string>
}
export async function augmentPages (routes: NuxtPage[], vfs: Record<string, string>, ctx: AugmentPagesContext = {}) {
ctx.augmentedPages ??= new Set()
for (const route of routes) {
if (route.file && !augmentedPages.has(route.file)) {
if (route.file && !ctx.pagesToSkip?.has(route.file)) {
const fileContent = route.file in vfs ? vfs[route.file]! : fs.readFileSync(await resolvePath(route.file), 'utf-8')
const routeMeta = await getRouteMeta(fileContent, route.file)
if (route.meta) {
@ -165,14 +170,14 @@ export async function augmentPages (routes: NuxtPage[], vfs: Record<string, stri
}
Object.assign(route, routeMeta)
augmentedPages.add(route.file)
ctx.augmentedPages.add(route.file)
}
if (route.children && route.children.length > 0) {
await augmentPages(route.children, vfs, augmentedPages)
await augmentPages(route.children, vfs, ctx)
}
}
return augmentedPages
return ctx.augmentedPages
}
const SFC_SCRIPT_RE = /<script(?<attrs>[^>]*)>(?<content>[\s\S]*?)<\/script[^>]*>/gi

View File

@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest'
import { detectImportNames } from '../src/plugins/composable-keys'
import { detectImportNames } from '../src/core/plugins/composable-keys'
describe('detectImportNames', () => {
const keyedComposables = {

View File

@ -24,6 +24,7 @@ const testsToTriggerOn = [
['some-nuxt-module', 'components/Component.vue', true],
['/root/src/server/api/test.ts', 'components/Component.vue', true],
['src/server/api/test.ts', 'components/Component.vue', true],
['node_modules/nitropack/node_modules/crossws/dist/adapters/bun.mjs', 'node_modules/nitropack/dist/presets/bun/runtime/bun.mjs', false],
] as const
describe('import protection', () => {

View File

@ -31,7 +31,7 @@
"dependencies": {
"@nuxt/friendly-errors-webpack-plugin": "^2.6.0",
"@nuxt/kit": "workspace:*",
"@rspack/core": "^1.1.0",
"@rspack/core": "^1.1.4",
"autoprefixer": "^10.4.20",
"css-loader": "^7.1.2",
"css-minimizer-webpack-plugin": "^7.0.0",
@ -39,22 +39,19 @@
"defu": "^6.1.4",
"esbuild-loader": "^4.2.2",
"escape-string-regexp": "^5.0.0",
"estree-walker": "^3.0.3",
"file-loader": "^6.2.0",
"fork-ts-checker-webpack-plugin": "^9.0.2",
"globby": "^14.0.2",
"h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
"hash-sum": "^2.0.0",
"jiti": "^2.4.0",
"knitwork": "^1.1.0",
"lodash-es": "4.17.21",
"magic-string": "^0.30.12",
"magic-string": "^0.30.14",
"memfs": "^4.14.0",
"mlly": "^1.7.2",
"ohash": "^1.1.4",
"pathe": "^1.1.2",
"pify": "^6.1.0",
"postcss": "^8.4.47",
"postcss": "^8.4.49",
"postcss-import": "^16.1.0",
"postcss-import-resolver": "^2.0.0",
"postcss-loader": "^8.1.1",
@ -64,26 +61,24 @@
"time-fix-plugin": "^2.0.7",
"ufo": "^1.5.4",
"unenv": "^1.10.0",
"unplugin": "^1.15.0",
"unplugin": "^1.16.0",
"url-loader": "^4.1.1",
"vue-bundle-renderer": "^2.1.1",
"vue-loader": "^17.4.2",
"webpack-bundle-analyzer": "^4.10.2",
"webpack-dev-middleware": "^7.4.2",
"webpack-hot-middleware": "^2.26.1",
"webpack-virtual-modules": "^0.6.2",
"webpackbar": "^7.0.0"
},
"devDependencies": {
"@nuxt/schema": "workspace:*",
"@types/hash-sum": "1.0.2",
"@types/lodash-es": "4.17.12",
"@types/pify": "5.0.4",
"@types/webpack-bundle-analyzer": "4.7.0",
"@types/webpack-hot-middleware": "2.25.9",
"rollup": "4.24.4",
"rollup": "4.27.4",
"unbuild": "3.0.0-rc.11",
"vue": "3.5.12"
"vue": "3.5.13"
},
"peerDependencies": {
"vue": "^3.3.4"

View File

@ -27,7 +27,6 @@ export default defineBuildConfig({
'autoprefixer',
'ofetch',
'vue-router',
'@nuxt/telemetry',
'vue-bundle-renderer',
'@unhead/schema',
'vue',
@ -55,7 +54,6 @@ export default defineBuildConfig({
'pug',
'sass-loader',
'c12',
'unenv',
'@vue/language-core',
// Implicit
'@vue/compiler-core',

View File

@ -34,16 +34,14 @@
"prepack": "unbuild"
},
"devDependencies": {
"@nuxt/telemetry": "2.6.0",
"@nuxt/ui-templates": "1.3.4",
"@types/file-loader": "5.0.4",
"@types/pug": "2.0.10",
"@types/sass-loader": "8.0.9",
"@unhead/schema": "1.11.11",
"@vitejs/plugin-vue": "5.1.4",
"@vitejs/plugin-vue-jsx": "4.0.1",
"@vue/compiler-core": "3.5.12",
"@vue/compiler-sfc": "3.5.12",
"@unhead/schema": "1.11.13",
"@vitejs/plugin-vue": "5.2.1",
"@vitejs/plugin-vue-jsx": "4.1.1",
"@vue/compiler-core": "3.5.13",
"@vue/compiler-sfc": "3.5.13",
"@vue/language-core": "2.1.10",
"esbuild-loader": "4.2.2",
"h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
@ -52,12 +50,11 @@
"ofetch": "1.4.1",
"unbuild": "3.0.0-rc.11",
"unctx": "2.3.1",
"unenv": "1.10.0",
"vite": "5.4.10",
"vue": "3.5.12",
"vite": "6.0.0",
"vue": "3.5.13",
"vue-bundle-renderer": "2.1.1",
"vue-loader": "17.4.2",
"vue-router": "4.4.5",
"vue-router": "4.5.0",
"webpack": "5.96.1",
"webpack-dev-middleware": "7.4.2"
},
@ -73,7 +70,7 @@
"std-env": "^3.8.0",
"ufo": "^1.5.4",
"uncrypto": "^0.1.3",
"unimport": "^3.13.1",
"unimport": "^3.13.3",
"untyped": "^1.5.1"
},
"engines": {

View File

@ -64,7 +64,7 @@ export interface ModuleDefinition<
TWith extends boolean,
> {
meta?: ModuleMeta
defaults?: TOptionsDefaults | ((nuxt: Nuxt) => TOptionsDefaults)
defaults?: TOptionsDefaults | ((nuxt: Nuxt) => Awaitable<TOptionsDefaults>)
schema?: TOptions
hooks?: Partial<NuxtHooks>
setup?: (

View File

@ -14,22 +14,22 @@
"dev": "vite",
"optimize-assets": "npx svgo public/assets/**/*.svg",
"postinstall": "pnpm build",
"prerender": "pnpm build && jiti ./lib/prerender",
"test": "pnpm lint && pnpm build"
"prerender": "pnpm build && jiti ./lib/prerender"
},
"devDependencies": {
"@unocss/reset": "0.64.0",
"@unocss/reset": "0.64.1",
"beasties": "0.1.0",
"html-validate": "8.24.2",
"html-validate": "8.25.1",
"htmlnano": "2.1.1",
"jiti": "2.4.0",
"knitwork": "1.1.0",
"pathe": "1.1.2",
"prettier": "3.3.3",
"prettier": "3.4.1",
"scule": "1.3.0",
"svgo": "3.3.2",
"tinyexec": "0.3.1",
"tinyglobby": "0.2.10",
"unocss": "0.64.0",
"vite": "5.4.10"
"unocss": "0.64.1",
"vite": "6.0.0"
}
}

View File

@ -26,16 +26,15 @@
"devDependencies": {
"@nuxt/schema": "workspace:*",
"@types/clear": "0.1.4",
"@types/estree": "1.0.6",
"rollup": "4.24.4",
"rollup": "4.27.4",
"unbuild": "3.0.0-rc.11",
"vue": "3.5.12"
"vue": "3.5.13"
},
"dependencies": {
"@nuxt/kit": "workspace:*",
"@rollup/plugin-replace": "^6.0.1",
"@vitejs/plugin-vue": "^5.1.4",
"@vitejs/plugin-vue-jsx": "^4.0.1",
"@vitejs/plugin-vue": "^5.2.1",
"@vitejs/plugin-vue-jsx": "^4.1.1",
"autoprefixer": "^10.4.20",
"clear": "^0.1.0",
"consola": "^3.2.3",
@ -43,27 +42,23 @@
"defu": "^6.1.4",
"esbuild": "^0.24.0",
"escape-string-regexp": "^5.0.0",
"estree-walker": "^3.0.3",
"externality": "^1.0.2",
"get-port-please": "^3.1.2",
"h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
"jiti": "^2.4.0",
"knitwork": "^1.1.0",
"magic-string": "^0.30.12",
"mlly": "^1.7.2",
"ohash": "^1.1.4",
"magic-string": "^0.30.14",
"mlly": "^1.7.3",
"pathe": "^1.1.2",
"perfect-debounce": "^1.0.0",
"pkg-types": "^1.2.1",
"postcss": "^8.4.47",
"postcss": "^8.4.49",
"rollup-plugin-visualizer": "^5.12.0",
"std-env": "^3.8.0",
"strip-literal": "^2.1.0",
"ufo": "^1.5.4",
"unenv": "^1.10.0",
"unplugin": "^1.15.0",
"vite": "^5.4.10",
"vite-node": "^2.1.4",
"unplugin": "^1.16.0",
"vite": "^6.0.0",
"vite-node": "^2.1.6",
"vite-plugin-checker": "^0.8.0",
"vue-bundle-renderer": "^2.1.1"
},

View File

@ -7,16 +7,6 @@ export function isCSS (file: string) {
return IS_CSS_RE.test(file)
}
export function matchWithStringOrRegex (value: string, matcher: string | RegExp) {
if (typeof matcher === 'string') {
return value === matcher
} else if (matcher instanceof RegExp) {
return matcher.test(value)
}
return false
}
/** @since 3.9.0 */
export function toArray<T> (value: T | T[]): T[] {
return Array.isArray(value) ? value : [value]

View File

@ -3,7 +3,7 @@ import { pathToFileURL } from 'node:url'
import { createApp, createError, defineEventHandler, defineLazyEventHandler, eventHandler, toNodeListener } from 'h3'
import { ViteNodeServer } from 'vite-node/server'
import { isAbsolute, join, normalize, resolve } from 'pathe'
import { addDevServerHandler } from '@nuxt/kit'
// import { addDevServerHandler } from '@nuxt/kit'
import { isFileServingAllowed } from 'vite'
import type { ModuleNode, Plugin as VitePlugin } from 'vite'
import { getQuery } from 'ufo'
@ -16,7 +16,7 @@ import { createIsExternal } from './utils/external'
import { transpile } from './utils/transpile'
// TODO: Remove this in favor of registerViteNodeMiddleware
// after Nitropack or h3 fixed for adding middlewares after setup
// after Nitropack or h3 allows adding middleware after setup
export function viteNodePlugin (ctx: ViteBuildContext): VitePlugin {
// Store the invalidates for the next rendering
const invalidates = new Set<string>()
@ -45,13 +45,13 @@ export function viteNodePlugin (ctx: ViteBuildContext): VitePlugin {
markInvalidate(mod)
}
}
for (const plugin of ctx.nuxt.options.plugins) {
markInvalidates(server.moduleGraph.getModulesByFile(typeof plugin === 'string' ? plugin : plugin.src))
}
for (const template of ctx.nuxt.options.build.templates) {
if (ctx.nuxt.apps.default) {
for (const template of ctx.nuxt.apps.default.templates) {
markInvalidates(server.moduleGraph.getModulesByFile(template.dst!))
}
}
}
server.middlewares.use('/__nuxt_vite_node__', toNodeListener(createViteNodeApp(ctx, invalidates)))
@ -71,12 +71,13 @@ export function viteNodePlugin (ctx: ViteBuildContext): VitePlugin {
}
}
export function registerViteNodeMiddleware (ctx: ViteBuildContext) {
addDevServerHandler({
route: '/__nuxt_vite_node__/',
handler: createViteNodeApp(ctx).handler,
})
}
// TODO: Use this when Nitropack or h3 allows adding middleware after setup
// export function registerViteNodeMiddleware (ctx: ViteBuildContext) {
// addDevServerHandler({
// route: '/__nuxt_vite_node__/',
// handler: createViteNodeApp(ctx).handler,
// })
// }
function getManifest (ctx: ViteBuildContext) {
const css = new Set<string>()

View File

@ -14,7 +14,6 @@ import { buildClient } from './client'
import { buildServer } from './server'
import { warmupViteServer } from './utils/warmup'
import { resolveCSSOptions } from './css'
import { composableKeysPlugin } from './plugins/composable-keys'
import { logLevelMap } from './utils/logger'
import { ssrStylesPlugin } from './plugins/ssr-styles'
import { VitePublicDirsPlugin } from './plugins/public-dirs'
@ -99,11 +98,6 @@ export const bundle: NuxtBuilder['bundle'] = async (nuxt) => {
sourcemap: !!nuxt.options.sourcemap.server,
baseURL: nuxt.options.app.baseURL,
}),
composableKeysPlugin.vite({
sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client,
rootDir: nuxt.options.rootDir,
composables: nuxt.options.optimization.keyedComposables,
}),
replace({ preventAssignment: true, ...globalThisReplacements }),
],
server: {

View File

@ -38,23 +38,20 @@
"defu": "^6.1.4",
"esbuild-loader": "^4.2.2",
"escape-string-regexp": "^5.0.0",
"estree-walker": "^3.0.3",
"file-loader": "^6.2.0",
"fork-ts-checker-webpack-plugin": "^9.0.2",
"globby": "^14.0.2",
"h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
"hash-sum": "^2.0.0",
"jiti": "^2.4.0",
"knitwork": "^1.1.0",
"lodash-es": "4.17.21",
"magic-string": "^0.30.12",
"magic-string": "^0.30.14",
"memfs": "^4.14.0",
"mini-css-extract-plugin": "^2.9.2",
"mlly": "^1.7.2",
"ohash": "^1.1.4",
"pathe": "^1.1.2",
"pify": "^6.1.0",
"postcss": "^8.4.47",
"postcss": "^8.4.49",
"postcss-import": "^16.1.0",
"postcss-import-resolver": "^2.0.0",
"postcss-loader": "^8.1.1",
@ -64,7 +61,7 @@
"time-fix-plugin": "^2.0.7",
"ufo": "^1.5.4",
"unenv": "^1.10.0",
"unplugin": "^1.15.0",
"unplugin": "^1.16.0",
"url-loader": "^4.1.1",
"vue-bundle-renderer": "^2.1.1",
"vue-loader": "^17.4.2",
@ -76,15 +73,14 @@
},
"devDependencies": {
"@nuxt/schema": "workspace:*",
"@rspack/core": "1.1.0",
"@types/hash-sum": "1.0.2",
"@rspack/core": "1.1.4",
"@types/lodash-es": "4.17.12",
"@types/pify": "5.0.4",
"@types/webpack-bundle-analyzer": "4.7.0",
"@types/webpack-hot-middleware": "2.25.9",
"rollup": "4.24.4",
"rollup": "4.27.4",
"unbuild": "3.0.0-rc.11",
"vue": "3.5.12"
"vue": "3.5.13"
},
"peerDependencies": {
"vue": "^3.3.4"

View File

@ -11,7 +11,6 @@ import { joinURL } from 'ufo'
import { logger, useNitro, useNuxt } from '@nuxt/kit'
import type { InputPluginOption } from 'rollup'
import { composableKeysPlugin } from '../../vite/src/plugins/composable-keys'
import { DynamicBasePlugin } from './plugins/dynamic-base'
import { ChunkErrorPlugin } from './plugins/chunk'
import { createMFS } from './utils/mfs'
@ -67,11 +66,6 @@ export const bundle: NuxtBuilder['bundle'] = async (nuxt) => {
if (config.name === 'client' && nuxt.options.experimental.emitRouteChunkError && nuxt.options.builder !== '@nuxt/rspack-builder') {
config.plugins!.push(new ChunkErrorPlugin())
}
config.plugins!.push(composableKeysPlugin.webpack({
sourcemap: !!nuxt.options.sourcemap[config.name as 'client' | 'server'],
rootDir: nuxt.options.rootDir,
composables: nuxt.options.optimization.keyedComposables,
}))
}
await nuxt.callHook(`${builder}:configResolved`, webpackConfigs)

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,7 @@
"ignoreDeps": [
"nitro",
"h3",
"typescript",
"nuxt",
"nuxt3",
"@nuxt/kit"

View File

@ -40,7 +40,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"209k"`)
const modules = await analyzeSizes(['node_modules/**/*'], serverDir)
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"1394k"`)
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"1396k"`)
const packages = modules.files
.filter(m => m.endsWith('package.json'))
@ -78,7 +78,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
const serverDir = join(rootDir, '.output-inline/server')
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"557k"`)
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"559k"`)
const modules = await analyzeSizes(['node_modules/**/*'], serverDir)
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"94.4k"`)

View File

@ -11,6 +11,7 @@
},
"devDependencies": {
"@vue/devtools-api": "latest",
"defu": "latest",
"ufo": "latest",
"unplugin": "latest",
"vue": "latest"