Merge branch 'main' into feat/unhead-v2

This commit is contained in:
Harlan Wilton 2025-01-22 15:48:45 +11:00 committed by GitHub
commit 0ce81cba96
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 583 additions and 363 deletions

View File

@ -188,6 +188,31 @@ jobs:
- name: Test (runtime unit)
run: pnpm test:runtime
test-size:
runs-on: ubuntu-latest
needs:
- build
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- run: corepack enable
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: lts/*
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Restore dist cache
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: dist
path: packages
- name: Check bundle size
run: pnpm vitest run bundle
test-fixtures:
runs-on: ${{ matrix.os }}
needs:
@ -253,7 +278,7 @@ jobs:
TEST_MANIFEST: ${{ matrix.manifest }}
TEST_CONTEXT: ${{ matrix.context }}
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' }}
SKIP_BUNDLE_SIZE: true
- uses: codecov/codecov-action@1e68e06f1dbfde0e4cefc87efeba9e4643565303 # v5.1.2
if: github.event_name != 'push' && matrix.env == 'built' && matrix.builder == 'vite' && matrix.context == 'default' && matrix.os == 'ubuntu-latest' && matrix.manifest == 'manifest-on'

View File

@ -1,8 +1,12 @@
// @ts-check
import { fileURLToPath } from 'node:url'
import { declare } from '@babel/helper-plugin-utils'
import { types as t } from '@babel/core'
const metricsPath = fileURLToPath(new URL('../../debug-timings.json', import.meta.url))
// inlined from https://github.com/danielroe/errx
function captureStackTrace () {
const IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[a-z]:[/\\]/i
@ -46,6 +50,7 @@ function captureStackTrace () {
}
export const leading = `
import { writeFileSync as ____writeFileSync } from 'node:fs'
const ___captureStackTrace = ${captureStackTrace.toString()};
globalThis.___calls ||= {};
globalThis.___timings ||= {};
@ -55,6 +60,16 @@ function onExit () {
if (globalThis.___logged) { return }
globalThis.___logged = true
// eslint-disable-next-line no-undef
____writeFileSync(metricsPath, JSON.stringify(Object.fromEntries(Object.entries(globalThis.___timings).map(([name, time]) => [
name,
{
time: Number(Number(time).toFixed(2)),
calls: globalThis.___calls[name],
callers: globalThis.___callers[name] ? Object.fromEntries(Object.entries(globalThis.___callers[name]).map(([name, count]) => [name.trim(), count]).sort((a, b) => typeof b[0] === 'string' && typeof a[0] === 'string' ? a[0].localeCompare(b[0]) : 0)) : undefined,
},
]).sort((a, b) => typeof b[0] === 'string' && typeof a[0] === 'string' ? a[0].localeCompare(b[0]) : 0)), null, 2))
// worst by total time
const timings = Object.entries(globalThis.___timings)
@ -93,7 +108,7 @@ function onExit () {
console.table(topFunctionsAverageTime)
}
export const trailing = `process.on("exit", ${onExit.toString()})`
export const trailing = `process.on("exit", ${onExit.toString().replace('metricsPath', JSON.stringify(metricsPath))})`
/** @param {string} functionName */
export function generateInitCode (functionName) {

View File

@ -15,6 +15,8 @@ declare global {
var ___calls: Record<string, number>
// eslint-disable-next-line no-var
var ___callers: Record<string, number>
// eslint-disable-next-line no-var
var ____writeFileSync: typeof import('fs').writeFileSync
}
export function AnnotateFunctionTimingsPlugin () {
@ -29,7 +31,7 @@ export function AnnotateFunctionTimingsPlugin () {
walk(ast as Node, {
enter (node) {
if (node.type === 'FunctionDeclaration' && node.id && node.id.name) {
const functionName = node.id.name ? `${node.id.name} (${id.match(/\/packages\/([^/]+)\//)?.[1]})` : ''
const functionName = node.id.name ? `${node.id.name} (${id.match(/[\\/]packages[\\/]([^/]+)[\\/]/)?.[1]})` : ''
const start = (node.body as Node & { start: number, end: number }).start
const end = (node.body as Node & { start: number, end: number }).end

View File

@ -51,3 +51,26 @@ The content of the default slot will be tree-shaken out of the server build. (Th
</div>
</template>
```
## Examples
### Accessing HTML Elements
Components inside `<ClientOnly>` are rendered only after being mounted. To access the rendered elements in the DOM, you can watch a template ref:
```vue [pages/example.vue]
<script setup lang="ts">
const nuxtWelcomeRef = ref()
// The watch will be triggered when the component is available
watch(nuxtWelcomeRef, () => {
console.log('<NuxtWelcome /> mounted')
}, { once: true })
</script>
<template>
<ClientOnly>
<NuxtWelcome ref="nuxtWelcomeRef" />
</ClientOnly>
</template>
```

View File

@ -24,6 +24,8 @@ This is useful for code that should be executed only once, such as logging an ev
## Usage
The default mode of `callOnce` is to run code only once. For example, if the code runs on the server it won't run again on the client. It also won't run again if you `callOnce` more than once on the client, for example by navigating back to this page.
```vue [app.vue]
<script setup lang="ts">
const websiteConfig = useState('config')
@ -35,6 +37,23 @@ await callOnce(async () => {
</script>
```
It is also possible to run on every navigation while still avoiding the initial server/client double load. For this, it is possible to use the `navigation` mode:
```vue [app.vue]
<script setup lang="ts">
const websiteConfig = useState('config')
await callOnce(async () => {
console.log('This will only be logged once and then on every client side navigation')
websiteConfig.value = await $fetch('https://my-cms.com/api/website-config')
}, { mode: 'navigation' })
</script>
```
::important
`navigation` mode is available since [Nuxt v3.15](/blog/v3-15).
::
::tip{to="/docs/getting-started/state-management#usage-with-pinia"}
`callOnce` is useful in combination with the [Pinia module](/modules/pinia) to call store actions.
::
@ -52,9 +71,22 @@ Note that `callOnce` doesn't return anything. You should use [`useAsyncData`](/d
## Type
```ts
callOnce(fn?: () => any | Promise<any>): Promise<void>
callOnce(key: string, fn?: () => any | Promise<any>): Promise<void>
callOnce (key?: string, fn?: (() => any | Promise<any>), options?: CallOnceOptions): Promise<void>
callOnce(fn?: (() => any | Promise<any>), options?: CallOnceOptions): Promise<void>
type CallOnceOptions = {
/**
* Execution mode for the callOnce function
* @default 'render'
*/
mode?: 'navigation' | 'render'
}
```
## Parameters
- `key`: A unique key ensuring that the code is run once. If you do not provide a key, then a key that is unique to the file and line number of the instance of `callOnce` will be generated for you.
- `fn`: The function to run once. This function can also return a `Promise` and a value.
- `options`: Setup the mode, either to re-execute on navigation (`navigation`) or just once for the lifetime of the app (`render`). Defaults to `render`.
- `render`: Executes once during initial render (either SSR or CSR) - Default mode
- `navigation`: Executes once during initial render and once per subsequent client-side navigation

View File

@ -65,7 +65,7 @@
"unbuild": "3.3.1",
"unhead": "2.0.0-alpha.7",
"unimport": "3.14.6",
"vite": "6.0.10",
"vite": "6.0.11",
"vue": "3.5.13"
},
"devDependencies": {

View File

@ -50,11 +50,11 @@
"untyped": "^1.5.2"
},
"devDependencies": {
"@rspack/core": "1.1.8",
"@rspack/core": "1.2.0",
"@types/semver": "7.5.8",
"nitro": "npm:nitro-nightly@3.0.0-beta-28938837.19ec5395",
"unbuild": "3.3.1",
"vite": "6.0.10",
"vite": "6.0.11",
"vitest": "3.0.2",
"webpack": "5.97.1"
},

View File

@ -14,6 +14,11 @@ const builderMap = {
'@nuxt/webpack-builder': 'webpack',
}
export function checkNuxtVersion (version: string, nuxt: Nuxt = useNuxt()) {
const nuxtVersion = getNuxtVersion(nuxt)
return satisfies(normalizeSemanticVersion(nuxtVersion), version, { includePrerelease: true })
}
/**
* Check version constraints and return incompatibility issues as an array
*/
@ -23,7 +28,7 @@ export async function checkNuxtCompatibility (constraints: NuxtCompatibility, nu
// Nuxt version check
if (constraints.nuxt) {
const nuxtVersion = getNuxtVersion(nuxt)
if (!satisfies(normalizeSemanticVersion(nuxtVersion), constraints.nuxt, { includePrerelease: true })) {
if (!checkNuxtVersion(constraints.nuxt, nuxt)) {
issues.push({
name: 'nuxt',
message: `Nuxt version \`${constraints.nuxt}\` is required but currently using \`${nuxtVersion}\``,

View File

@ -1,16 +1,18 @@
import { kebabCase, pascalCase } from 'scule'
import type { Component, ComponentsDir } from '@nuxt/schema'
import { useNuxt } from './context'
import { assertNuxtCompatibility } from './compatibility'
import { checkNuxtVersion } from './compatibility'
import { logger } from './logger'
import { MODE_RE } from './utils'
/**
* Register a directory to be scanned for components and imported only when used.
*/
export async function addComponentsDir (dir: ComponentsDir, opts: { prepend?: boolean } = {}) {
export function addComponentsDir (dir: ComponentsDir, opts: { prepend?: boolean } = {}) {
const nuxt = useNuxt()
await assertNuxtCompatibility({ nuxt: '>=2.13' }, nuxt)
if (!checkNuxtVersion('>=2.13', nuxt)) {
throw new Error(`\`addComponentsDir\` requires Nuxt 2.13 or higher.`)
}
nuxt.options.components ||= []
dir.priority ||= 0
nuxt.hook('components:dirs', (dirs) => { dirs[opts.prepend ? 'unshift' : 'push'](dir) })
@ -23,9 +25,12 @@ export type AddComponentOptions = { name: string, filePath: string } & Partial<E
/**
* Register a component by its name and filePath.
*/
export async function addComponent (opts: AddComponentOptions) {
export function addComponent (opts: AddComponentOptions) {
const nuxt = useNuxt()
await assertNuxtCompatibility({ nuxt: '>=2.13' }, nuxt)
if (!checkNuxtVersion('>=2.13', nuxt)) {
throw new Error(`\`addComponent\` requires Nuxt 2.13 or higher.`)
}
nuxt.options.components ||= []
if (!opts.mode) {

View File

@ -1,4 +1,4 @@
import { existsSync, promises as fsp } from 'node:fs'
import { promises as fsp } from 'node:fs'
import { fileURLToPath } from 'node:url'
import { basename, dirname, isAbsolute, join, normalize, resolve } from 'pathe'
import { globby } from 'globby'
@ -38,97 +38,30 @@ export interface ResolvePathOptions {
* If path could not be resolved, normalized input path will be returned
*/
export async function resolvePath (path: string, opts: ResolvePathOptions = {}): Promise<string> {
// Always normalize input
const _path = path
path = normalize(path)
const res = await _resolvePathGranularly(path, opts)
// Fast return if the path exists
if (isAbsolute(path)) {
if (opts?.virtual && existsInVFS(path)) {
return path
}
if (existsSync(path) && !(await isDirectory(path))) {
return path
}
}
// Use current nuxt options
const nuxt = tryUseNuxt()
const cwd = opts.cwd || (nuxt ? nuxt.options.rootDir : process.cwd())
const extensions = opts.extensions || (nuxt ? nuxt.options.extensions : ['.ts', '.mjs', '.cjs', '.json'])
const modulesDir = nuxt ? nuxt.options.modulesDir : []
// Resolve aliases
path = resolveAlias(path)
// Resolve relative to cwd
if (!isAbsolute(path)) {
path = resolve(cwd, path)
}
// Check if resolvedPath is a file
if (opts?.virtual && existsInVFS(path, nuxt)) {
return path
}
let _isDir = false
if (existsSync(path)) {
_isDir = await isDirectory(path)
if (!_isDir) {
return path
}
}
// Check possible extensions
for (const ext of extensions) {
// path.[ext]
const pathWithExt = path + ext
if (opts?.virtual && existsInVFS(pathWithExt, nuxt)) {
return pathWithExt
}
if (existsSync(pathWithExt)) {
return pathWithExt
}
// path/index.[ext]
const pathWithIndex = join(path, 'index' + ext)
if (opts?.virtual && existsInVFS(pathWithIndex, nuxt)) {
return pathWithIndex
}
if (_isDir && existsSync(pathWithIndex)) {
return pathWithIndex
}
}
// Try to resolve as module id
const resolveModulePath = await _resolvePath(_path, { url: [cwd, ...modulesDir] }).catch(() => null)
if (resolveModulePath) {
return resolveModulePath
if (res.type === 'file') {
return res.path
}
// Return normalized input
return opts.fallbackToOriginal ? _path : path
return opts.fallbackToOriginal ? path : res.path
}
/**
* Try to resolve first existing file in paths
*/
export async function findPath (paths: string | string[], opts?: ResolvePathOptions, pathType: 'file' | 'dir' = 'file'): Promise<string | null> {
const nuxt = opts?.virtual ? tryUseNuxt() : undefined
for (const path of toArray(paths)) {
const rPath = await resolvePath(path, opts)
const res = await _resolvePathGranularly(path, opts)
// Check VFS
if (opts?.virtual && existsInVFS(rPath, nuxt)) {
return rPath
if (!res.type || (pathType && res.type !== pathType)) {
continue
}
// Check file system
if (await existsSensitive(rPath)) {
const _isDir = await isDirectory(rPath)
if (!pathType || (pathType === 'file' && !_isDir) || (pathType === 'dir' && _isDir)) {
return rPath
}
if (res.virtual || await existsSensitive(res.path)) {
return res.path
}
}
return null
@ -186,15 +119,106 @@ export async function resolveNuxtModule (base: string, paths: string[]): Promise
// --- Internal ---
async function existsSensitive (path: string) {
if (!existsSync(path)) { return false }
const dirFiles = await fsp.readdir(dirname(path))
return dirFiles.includes(basename(path))
interface PathResolution {
path: string
type?: 'file' | 'dir'
virtual?: boolean
}
// Usage note: We assume path existence is already ensured
async function isDirectory (path: string) {
return (await fsp.lstat(path)).isDirectory()
async function _resolvePathType (path: string, opts: ResolvePathOptions = {}, skipFs = false): Promise<PathResolution | undefined> {
if (opts?.virtual && existsInVFS(path)) {
return {
path,
type: 'file',
virtual: true,
}
}
if (skipFs) {
return
}
const fd = await fsp.open(path, 'r').catch(() => null)
try {
const stats = await fd?.stat()
if (stats) {
return {
path,
type: stats.isFile() ? 'file' : 'dir',
virtual: false,
}
}
} finally {
fd?.close()
}
}
async function _resolvePathGranularly (path: string, opts: ResolvePathOptions = {}): Promise<PathResolution> {
// Always normalize input
const _path = path
path = normalize(path)
// Fast return if the path exists
if (isAbsolute(path)) {
const res = await _resolvePathType(path, opts)
if (res && res.type === 'file') {
return res
}
}
// Use current nuxt options
const nuxt = tryUseNuxt()
const cwd = opts.cwd || (nuxt ? nuxt.options.rootDir : process.cwd())
const extensions = opts.extensions || (nuxt ? nuxt.options.extensions : ['.ts', '.mjs', '.cjs', '.json'])
const modulesDir = nuxt ? nuxt.options.modulesDir : []
// Resolve aliases
path = resolveAlias(path)
// Resolve relative to cwd
if (!isAbsolute(path)) {
path = resolve(cwd, path)
}
const res = await _resolvePathType(path, opts)
if (res && res.type === 'file') {
return res
}
// Check possible extensions
for (const ext of extensions) {
// path.[ext]
const extPath = await _resolvePathType(path + ext, opts)
if (extPath && extPath.type === 'file') {
return extPath
}
// path/index.[ext]
const indexPath = await _resolvePathType(join(path, 'index' + ext), opts, res?.type !== 'dir' /* skip checking if parent is not a directory */)
if (indexPath && indexPath.type === 'file') {
return indexPath
}
}
// Try to resolve as module id
const resolvedModulePath = await _resolvePath(_path, { url: [cwd, ...modulesDir] }).catch(() => null)
if (resolvedModulePath) {
return {
path: resolvedModulePath,
type: 'file',
virtual: false,
}
}
// Return normalized input
return {
path,
}
}
async function existsSensitive (path: string) {
const dirFiles = await fsp.readdir(dirname(path)).catch(() => null)
return dirFiles && dirFiles.includes(basename(path))
}
function existsInVFS (path: string, nuxt = tryUseNuxt()) {

View File

@ -117,7 +117,7 @@
"unenv": "^1.10.0",
"unimport": "^3.14.6",
"unplugin": "^2.1.2",
"unplugin-vue-router": "^0.10.9",
"unplugin-vue-router": "^0.11.0",
"unstorage": "^1.14.4",
"untyped": "^1.5.2",
"vue": "^3.5.13",
@ -132,7 +132,7 @@
"@vitejs/plugin-vue": "5.2.1",
"@vue/compiler-sfc": "3.5.13",
"unbuild": "3.3.1",
"vite": "6.0.10",
"vite": "6.0.11",
"vitest": "3.0.2"
},
"peerDependencies": {

View File

@ -1,6 +1,6 @@
import { existsSync, statSync, writeFileSync } from 'node:fs'
import { isAbsolute, join, normalize, relative, resolve } from 'pathe'
import { addBuildPlugin, addPluginTemplate, addTemplate, addTypeTemplate, addVitePlugin, defineNuxtModule, findPath, resolveAlias, resolvePath, updateTemplates } from '@nuxt/kit'
import { addBuildPlugin, addPluginTemplate, addTemplate, addTypeTemplate, addVitePlugin, defineNuxtModule, findPath, resolveAlias, resolvePath } from '@nuxt/kit'
import type { Component, ComponentsDir, ComponentsOptions } from 'nuxt/schema'
import { distDir } from '../dirs'
@ -198,24 +198,6 @@ export default defineNuxtModule<ComponentsOptions>({
tsConfig.compilerOptions!.paths['#components'] = [resolve(nuxt.options.buildDir, 'components')]
})
// Watch for changes
nuxt.hook('builder:watch', async (event, relativePath) => {
if (!['add', 'unlink'].includes(event)) {
return
}
const path = resolve(nuxt.options.srcDir, relativePath)
if (componentDirs.some(dir => path.startsWith(dir.path + '/'))) {
await updateTemplates({
filter: template => [
'components.plugin.mjs',
'components.d.ts',
'components.server.mjs',
'components.client.mjs',
].includes(template.filename),
})
}
})
addBuildPlugin(TreeShakeTemplatePlugin({ sourcemap: !!nuxt.options.sourcemap.server, getComponents }), { client: false })
const sharedLoaderOptions = {

View File

@ -1,6 +1,6 @@
import { existsSync, readdirSync } from 'node:fs'
import { mkdir, readFile } from 'node:fs/promises'
import { addBuildPlugin, addComponent, addPlugin, addTemplate, addTypeTemplate, defineNuxtModule, findPath, resolvePath, updateTemplates, useNitro } from '@nuxt/kit'
import { addBuildPlugin, addComponent, addPlugin, addTemplate, addTypeTemplate, defineNuxtModule, findPath, resolvePath, useNitro } from '@nuxt/kit'
import { dirname, join, relative, resolve } from 'pathe'
import { genImport, genObjectFromRawEntries, genString } from 'knitwork'
import { joinURL } from 'ufo'
@ -93,10 +93,8 @@ export default defineNuxtModule({
addPlugin(resolve(runtimeDir, 'plugins/check-if-page-unused'))
}
nuxt.hook('app:templates', async (app) => {
app.pages = await resolvePagesRoutes(nuxt)
if (!nuxt.options.ssr && app.pages.some(p => p.mode === 'server')) {
nuxt.hook('app:templates', (app) => {
if (!nuxt.options.ssr && app.pages?.some(p => p.mode === 'server')) {
logger.warn('Using server pages with `ssr: false` is not supported with auto-detected component islands. Set `experimental.componentIslands` to `true`.')
}
})
@ -269,6 +267,13 @@ export default defineNuxtModule({
if (!pages) { return false }
return pages.some(page => page.file === file) || pages.some(page => page.children && isPage(file, page.children))
}
nuxt.hooks.hookOnce('app:templates', async (app) => {
if (!app.pages) {
app.pages = await resolvePagesRoutes(nuxt)
}
})
nuxt.hook('builder:watch', async (event, relativePath) => {
const path = resolve(nuxt.options.srcDir, relativePath)
const shouldAlwaysRegenerate = nuxt.options.experimental.scanPageMeta && isPage(path)
@ -276,9 +281,7 @@ export default defineNuxtModule({
if (event === 'change' && !shouldAlwaysRegenerate) { return }
if (shouldAlwaysRegenerate || updateTemplatePaths.some(dir => path.startsWith(dir))) {
await updateTemplates({
filter: template => template.filename === 'routes.mjs',
})
nuxt.apps.default!.pages = await resolvePagesRoutes(nuxt)
}
})

View File

@ -32,7 +32,7 @@
"dependencies": {
"@nuxt/friendly-errors-webpack-plugin": "^2.6.0",
"@nuxt/kit": "workspace:*",
"@rspack/core": "^1.1.8",
"@rspack/core": "^1.2.0",
"autoprefixer": "^10.4.20",
"css-loader": "^7.1.2",
"css-minimizer-webpack-plugin": "^7.0.0",

View File

@ -60,7 +60,7 @@
"unctx": "2.4.1",
"unimport": "3.14.6",
"untyped": "1.5.2",
"vite": "6.0.10",
"vite": "6.0.11",
"vue": "3.5.13",
"vue-bundle-renderer": "2.1.1",
"vue-loader": "17.4.2",

View File

@ -30,6 +30,6 @@
"tinyexec": "0.3.2",
"tinyglobby": "0.2.10",
"unocss": "65.4.2",
"vite": "6.0.10"
"vite": "6.0.11"
}
}

View File

@ -55,7 +55,7 @@
"ufo": "^1.5.4",
"unenv": "^1.10.0",
"unplugin": "^2.1.2",
"vite": "^6.0.10",
"vite": "^6.0.11",
"vite-node": "^3.0.2",
"vite-plugin-checker": "^0.8.0",
"vue-bundle-renderer": "^2.1.1"

View File

@ -6,9 +6,8 @@ import { isAbsolute, join, normalize, resolve } from 'pathe'
// import { addDevServerHandler } from '@nuxt/kit'
import { isFileServingAllowed } from 'vite'
import type { ModuleNode, Plugin as VitePlugin } from 'vite'
import { getQuery, withTrailingSlash } from 'ufo'
import { getQuery } from 'ufo'
import { normalizeViteManifest } from 'vue-bundle-renderer'
import escapeStringRegexp from 'escape-string-regexp'
import { distDir } from './dirs'
import type { ViteBuildContext } from './vite'
import { isCSS } from './utils'
@ -120,10 +119,6 @@ function createViteNodeApp (ctx: ViteBuildContext, invalidates: Set<string> = ne
/^#/,
/\?/,
],
external: [
'#shared',
new RegExp('^' + escapeStringRegexp(withTrailingSlash(resolve(ctx.nuxt.options.rootDir, ctx.nuxt.options.dir.shared)))),
],
},
transformMode: {
ssr: [/.*/],

View File

@ -212,13 +212,13 @@ export const bundle: NuxtBuilder['bundle'] = async (nuxt) => {
nuxt.hook('vite:serverCreated', (server: vite.ViteDevServer, env) => {
// Invalidate virtual modules when templates are re-generated
ctx.nuxt.hook('app:templatesGenerated', (_app, changedTemplates) => {
for (const template of changedTemplates) {
ctx.nuxt.hook('app:templatesGenerated', async (_app, changedTemplates) => {
await Promise.all(changedTemplates.map(async (template) => {
for (const mod of server.moduleGraph.getModulesByFile(`virtual:nuxt:${encodeURIComponent(template.dst)}`) || []) {
server.moduleGraph.invalidateModule(mod)
server.reloadModule(mod)
await server.reloadModule(mod)
}
}
}))
})
if (nuxt.options.vite.warmupEntry !== false) {

View File

@ -73,7 +73,7 @@
},
"devDependencies": {
"@nuxt/schema": "workspace:*",
"@rspack/core": "1.1.8",
"@rspack/core": "1.2.0",
"@types/pify": "5.0.4",
"@types/webpack-bundle-analyzer": "4.7.0",
"@types/webpack-hot-middleware": "2.25.9",

File diff suppressed because it is too large Load Diff

View File

@ -123,7 +123,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
const serverDir = join(pagesRootDir, '.output/server')
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"302k"`)
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"303k"`)
const modules = await analyzeSizes(['node_modules/**/*'], serverDir)
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"1382k"`)