mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-26 07:32:01 +00:00
perf(nuxt): cache vue app build outputs (#28726)
This commit is contained in:
parent
901691aa65
commit
bafc482fa5
@ -411,3 +411,34 @@ export default defineNuxtConfig({
|
|||||||
::read-more{icon="i-simple-icons-mdnwebdocs" color="gray" to="https://developer.mozilla.org/en-US/docs/Web/API/CookieStore" target="_blank"}
|
::read-more{icon="i-simple-icons-mdnwebdocs" color="gray" to="https://developer.mozilla.org/en-US/docs/Web/API/CookieStore" target="_blank"}
|
||||||
Read more about the **CookieStore**.
|
Read more about the **CookieStore**.
|
||||||
::
|
::
|
||||||
|
|
||||||
|
## buildCache
|
||||||
|
|
||||||
|
Caches Nuxt build artifacts based on a hash of the configuration and source files.
|
||||||
|
|
||||||
|
```ts twoslash [nuxt.config.ts]
|
||||||
|
export default defineNuxtConfig({
|
||||||
|
experimental: {
|
||||||
|
buildCache: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
When enabled, changes to the following files will trigger a full rebuild:
|
||||||
|
|
||||||
|
```bash [Directory structure]
|
||||||
|
.nuxtrc
|
||||||
|
.npmrc
|
||||||
|
package.json
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
pnpm-lock.yaml
|
||||||
|
tsconfig.json
|
||||||
|
bun.lockb
|
||||||
|
```
|
||||||
|
|
||||||
|
In addition, any changes to files within `srcDir` will trigger a rebuild of the Vue client/server bundle. Nitro will always be rebuilt (though work is in progress to allow Nitro to announce its cacheable artifacts and their hashes).
|
||||||
|
|
||||||
|
::note
|
||||||
|
A maximum of 10 cache tarballs are kept.
|
||||||
|
::
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { existsSync } from 'node:fs'
|
||||||
import type { JSValue } from 'untyped'
|
import type { JSValue } from 'untyped'
|
||||||
import { applyDefaults } from 'untyped'
|
import { applyDefaults } from 'untyped'
|
||||||
import type { ConfigLayer, ConfigLayerMeta, LoadConfigOptions } from 'c12'
|
import type { ConfigLayer, ConfigLayerMeta, LoadConfigOptions } from 'c12'
|
||||||
@ -6,6 +7,7 @@ import type { NuxtConfig, NuxtOptions } from '@nuxt/schema'
|
|||||||
import { NuxtConfigSchema } from '@nuxt/schema'
|
import { NuxtConfigSchema } from '@nuxt/schema'
|
||||||
import { globby } from 'globby'
|
import { globby } from 'globby'
|
||||||
import defu from 'defu'
|
import defu from 'defu'
|
||||||
|
import { join } from 'pathe'
|
||||||
|
|
||||||
export interface LoadNuxtConfigOptions extends Omit<LoadConfigOptions<NuxtConfig>, 'overrides'> {
|
export interface LoadNuxtConfigOptions extends Omit<LoadConfigOptions<NuxtConfig>, 'overrides'> {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||||
@ -47,6 +49,11 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
|
|||||||
nuxtConfig._nuxtConfigFile = configFile
|
nuxtConfig._nuxtConfigFile = configFile
|
||||||
nuxtConfig._nuxtConfigFiles = [configFile]
|
nuxtConfig._nuxtConfigFiles = [configFile]
|
||||||
|
|
||||||
|
const defaultBuildDir = join(nuxtConfig.rootDir!, '.nuxt')
|
||||||
|
if (!opts.overrides?._prepare && !nuxtConfig.dev && !nuxtConfig.buildDir && nuxtConfig.future?.compatibilityVersion === 4 && existsSync(defaultBuildDir)) {
|
||||||
|
nuxtConfig.buildDir = join(nuxtConfig.rootDir!, 'node_modules/.cache/nuxt/.nuxt')
|
||||||
|
}
|
||||||
|
|
||||||
const _layers: ConfigLayer<NuxtConfig, ConfigLayerMeta>[] = []
|
const _layers: ConfigLayer<NuxtConfig, ConfigLayerMeta>[] = []
|
||||||
const processedLayers = new Set<string>()
|
const processedLayers = new Set<string>()
|
||||||
for (const layer of layers) {
|
for (const layer of layers) {
|
||||||
|
@ -91,6 +91,7 @@
|
|||||||
"knitwork": "^1.1.0",
|
"knitwork": "^1.1.0",
|
||||||
"magic-string": "^0.30.11",
|
"magic-string": "^0.30.11",
|
||||||
"mlly": "^1.7.1",
|
"mlly": "^1.7.1",
|
||||||
|
"nanotar": "^0.1.1",
|
||||||
"nitropack": "^2.9.7",
|
"nitropack": "^2.9.7",
|
||||||
"nuxi": "^3.13.1",
|
"nuxi": "^3.13.1",
|
||||||
"nypm": "^0.3.11",
|
"nypm": "^0.3.11",
|
||||||
@ -104,6 +105,7 @@
|
|||||||
"semver": "^7.6.3",
|
"semver": "^7.6.3",
|
||||||
"std-env": "^3.7.0",
|
"std-env": "^3.7.0",
|
||||||
"strip-literal": "^2.1.0",
|
"strip-literal": "^2.1.0",
|
||||||
|
"tinyglobby": "0.2.5",
|
||||||
"ufo": "^1.5.4",
|
"ufo": "^1.5.4",
|
||||||
"ultrahtml": "^1.5.3",
|
"ultrahtml": "^1.5.3",
|
||||||
"uncrypto": "^0.1.3",
|
"uncrypto": "^0.1.3",
|
||||||
|
@ -10,6 +10,7 @@ import type { Nuxt, NuxtBuilder } from 'nuxt/schema'
|
|||||||
|
|
||||||
import { generateApp as _generateApp, createApp } from './app'
|
import { generateApp as _generateApp, createApp } from './app'
|
||||||
import { checkForExternalConfigurationFiles } from './external-config-files'
|
import { checkForExternalConfigurationFiles } from './external-config-files'
|
||||||
|
import { cleanupCaches, getVueHash } from './cache'
|
||||||
|
|
||||||
export async function build (nuxt: Nuxt) {
|
export async function build (nuxt: Nuxt) {
|
||||||
const app = createApp(nuxt)
|
const app = createApp(nuxt)
|
||||||
@ -42,16 +43,32 @@ export async function build (nuxt: Nuxt) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
await nuxt.callHook('build:before')
|
if (!nuxt.options._prepare && !nuxt.options.dev && nuxt.options.experimental.buildCache) {
|
||||||
if (!nuxt.options._prepare) {
|
const { restoreCache, collectCache } = await getVueHash(nuxt)
|
||||||
await Promise.all([checkForExternalConfigurationFiles(), bundle(nuxt)])
|
if (await restoreCache()) {
|
||||||
await nuxt.callHook('build:done')
|
await nuxt.callHook('build:done')
|
||||||
|
return await nuxt.callHook('close', nuxt)
|
||||||
if (!nuxt.options.dev) {
|
|
||||||
await nuxt.callHook('close', nuxt)
|
|
||||||
}
|
}
|
||||||
} else {
|
nuxt.hooks.hookOnce('nitro:build:before', () => collectCache())
|
||||||
|
nuxt.hooks.hookOnce('close', () => cleanupCaches(nuxt))
|
||||||
|
}
|
||||||
|
|
||||||
|
await nuxt.callHook('build:before')
|
||||||
|
if (nuxt.options._prepare) {
|
||||||
nuxt.hook('prepare:types', () => nuxt.close())
|
nuxt.hook('prepare:types', () => nuxt.close())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nuxt.options.dev) {
|
||||||
|
checkForExternalConfigurationFiles()
|
||||||
|
}
|
||||||
|
|
||||||
|
await bundle(nuxt)
|
||||||
|
|
||||||
|
await nuxt.callHook('build:done')
|
||||||
|
|
||||||
|
if (!nuxt.options.dev) {
|
||||||
|
await nuxt.callHook('close', nuxt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
275
packages/nuxt/src/core/cache.ts
Normal file
275
packages/nuxt/src/core/cache.ts
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
import { mkdir, open, readFile, stat, unlink, writeFile } from 'node:fs/promises'
|
||||||
|
import type { FileHandle } from 'node:fs/promises'
|
||||||
|
import { resolve } from 'node:path'
|
||||||
|
import { existsSync } from 'node:fs'
|
||||||
|
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 { dirname, join, relative } from 'pathe'
|
||||||
|
import { createTar, parseTar } from 'nanotar'
|
||||||
|
import type { TarFileInput } from 'nanotar'
|
||||||
|
|
||||||
|
export async function getVueHash (nuxt: Nuxt) {
|
||||||
|
const id = 'vue'
|
||||||
|
|
||||||
|
const { hash } = await getHashes(nuxt, {
|
||||||
|
id,
|
||||||
|
cwd: layer => layer.config?.srcDir,
|
||||||
|
patterns: layer => [
|
||||||
|
join(relative(layer.cwd, layer.config.srcDir), '**'),
|
||||||
|
`!${relative(layer.cwd, layer.config.serverDir || join(layer.cwd, 'server'))}/**`,
|
||||||
|
`!${relative(layer.cwd, resolve(layer.config.srcDir || layer.cwd, layer.config.dir?.public || 'public'))}/**`,
|
||||||
|
`!${relative(layer.cwd, resolve(layer.config.srcDir || layer.cwd, layer.config.dir?.static || 'public'))}/**`,
|
||||||
|
'!node_modules/**',
|
||||||
|
'!nuxt.config.*',
|
||||||
|
],
|
||||||
|
configOverrides: {
|
||||||
|
buildId: undefined,
|
||||||
|
serverDir: undefined,
|
||||||
|
nitro: undefined,
|
||||||
|
devServer: undefined,
|
||||||
|
runtimeConfig: undefined,
|
||||||
|
logLevel: undefined,
|
||||||
|
devServerHandlers: undefined,
|
||||||
|
generate: undefined,
|
||||||
|
devtools: undefined,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const cacheFile = join(nuxt.options.workspaceDir, 'node_modules/.cache/nuxt/builds', id, hash + '.tar')
|
||||||
|
|
||||||
|
return {
|
||||||
|
hash,
|
||||||
|
async collectCache () {
|
||||||
|
const start = Date.now()
|
||||||
|
await writeCache(nuxt.options.buildDir, nuxt.options.buildDir, cacheFile)
|
||||||
|
const elapsed = Date.now() - start
|
||||||
|
consola.success(`Cached Vue client and server builds in \`${elapsed}ms\`.`)
|
||||||
|
},
|
||||||
|
async restoreCache () {
|
||||||
|
const start = Date.now()
|
||||||
|
const res = await restoreCache(nuxt.options.buildDir, cacheFile)
|
||||||
|
const elapsed = Date.now() - start
|
||||||
|
if (res) {
|
||||||
|
consola.success(`Restored Vue client and server builds from cache in \`${elapsed}ms\`.`)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function cleanupCaches (nuxt: Nuxt) {
|
||||||
|
const start = Date.now()
|
||||||
|
const caches = await glob(['*/*.tar'], {
|
||||||
|
cwd: join(nuxt.options.workspaceDir, 'node_modules/.cache/nuxt/builds'),
|
||||||
|
absolute: true,
|
||||||
|
})
|
||||||
|
if (caches.length >= 10) {
|
||||||
|
const cachesWithMeta = await Promise.all(caches.map(async (cache) => {
|
||||||
|
return [cache, await stat(cache).then(r => r.mtime.getTime()).catch(() => 0)] as const
|
||||||
|
}))
|
||||||
|
cachesWithMeta.sort((a, b) => a[1] - b[1])
|
||||||
|
for (const [cache] of cachesWithMeta.slice(0, cachesWithMeta.length - 10)) {
|
||||||
|
await unlink(cache)
|
||||||
|
}
|
||||||
|
const elapsed = Date.now() - start
|
||||||
|
consola.success(`Cleaned up old build caches in \`${elapsed}ms\`.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// internal
|
||||||
|
|
||||||
|
type HashSource = { name: string, data: any }
|
||||||
|
type Hashes = { hash: string, sources: HashSource[] }
|
||||||
|
|
||||||
|
interface GetHashOptions {
|
||||||
|
id: string
|
||||||
|
cwd: (layer: NuxtConfigLayer) => string
|
||||||
|
patterns: (layer: NuxtConfigLayer) => string[]
|
||||||
|
configOverrides: Partial<Record<keyof NuxtConfig, unknown>>
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getHashes (nuxt: Nuxt, options: GetHashOptions): Promise<Hashes> {
|
||||||
|
if ((nuxt as any)[`_${options.id}BuildHash`]) {
|
||||||
|
return (nuxt as any)[`_${options.id}BuildHash`]
|
||||||
|
}
|
||||||
|
|
||||||
|
const start = Date.now()
|
||||||
|
const hashSources: HashSource[] = []
|
||||||
|
|
||||||
|
// Layers
|
||||||
|
let layerCtr = 0
|
||||||
|
for (const layer of nuxt.options._layers) {
|
||||||
|
if (layer.cwd.includes('node_modules')) { continue }
|
||||||
|
|
||||||
|
const layerName = `layer#${layerCtr++}`
|
||||||
|
hashSources.push({
|
||||||
|
name: `${layerName}:config`,
|
||||||
|
data: objectHash({
|
||||||
|
...layer.config,
|
||||||
|
...options.configOverrides || {},
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const normalizeFiles = (files: Awaited<ReturnType<typeof readFilesRecursive>>) => files.map(f => ({
|
||||||
|
name: f.name,
|
||||||
|
size: (f.attrs as any)?.size,
|
||||||
|
data: murmurHash(f.data as any /* ArrayBuffer */),
|
||||||
|
}))
|
||||||
|
|
||||||
|
const sourceFiles = await readFilesRecursive(options.cwd(layer), {
|
||||||
|
shouldIgnore: isIgnored, // TODO: Validate if works with absolute paths
|
||||||
|
cwd: nuxt.options.rootDir,
|
||||||
|
patterns: options.patterns(layer),
|
||||||
|
})
|
||||||
|
|
||||||
|
hashSources.push({
|
||||||
|
name: `${layerName}:src`,
|
||||||
|
data: normalizeFiles(sourceFiles),
|
||||||
|
})
|
||||||
|
|
||||||
|
const rootFiles = await readFilesRecursive(layer.config?.rootDir || layer.cwd, {
|
||||||
|
shouldIgnore: isIgnored, // TODO: Validate if works with absolute paths
|
||||||
|
cwd: nuxt.options.rootDir,
|
||||||
|
patterns: [
|
||||||
|
'.nuxtrc',
|
||||||
|
'.npmrc',
|
||||||
|
'package.json',
|
||||||
|
'package-lock.json',
|
||||||
|
'yarn.lock',
|
||||||
|
'pnpm-lock.yaml',
|
||||||
|
'tsconfig.json',
|
||||||
|
'bun.lockb',
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
hashSources.push({
|
||||||
|
name: `${layerName}:root`,
|
||||||
|
data: normalizeFiles(rootFiles),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = ((nuxt as any)[`_${options.id}BuildHash`] = {
|
||||||
|
hash: hash(hashSources),
|
||||||
|
sources: hashSources,
|
||||||
|
})
|
||||||
|
|
||||||
|
const elapsed = Date.now() - start
|
||||||
|
consola.debug(`Computed \`${options.id}\` build hash in \`${elapsed}ms\`.`)
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileWithMeta = TarFileInput & {
|
||||||
|
attrs: {
|
||||||
|
mtime: number
|
||||||
|
size: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReadFilesRecursiveOptions {
|
||||||
|
shouldIgnore?: (name: string) => boolean
|
||||||
|
patterns: string[]
|
||||||
|
cwd: string
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readFilesRecursive (dir: string | string[], opts: ReadFilesRecursiveOptions): Promise<FileWithMeta[]> {
|
||||||
|
if (Array.isArray(dir)) {
|
||||||
|
return (await Promise.all(dir.map(d => readFilesRecursive(d, opts)))).flat()
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = await glob(opts.patterns, { cwd: dir })
|
||||||
|
|
||||||
|
const fileEntries = await Promise.all(files.map(async (fileName) => {
|
||||||
|
if (!opts.shouldIgnore?.(fileName)) {
|
||||||
|
const file = await readFileWithMeta(dir, fileName)
|
||||||
|
if (!file) { return }
|
||||||
|
return {
|
||||||
|
...file,
|
||||||
|
name: relative(opts.cwd, join(dir, file.name)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
return fileEntries.filter(Boolean) as FileWithMeta[]
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readFileWithMeta (dir: string, fileName: string, count = 0): Promise<FileWithMeta | undefined> {
|
||||||
|
let fd: FileHandle | undefined = undefined
|
||||||
|
|
||||||
|
try {
|
||||||
|
fd = await open(resolve(dir, fileName))
|
||||||
|
const stats = await fd.stat()
|
||||||
|
|
||||||
|
if (!stats?.isFile()) { return }
|
||||||
|
|
||||||
|
const mtime = stats.mtime.getTime()
|
||||||
|
const data = await fd.readFile()
|
||||||
|
|
||||||
|
// retry if file has changed during read
|
||||||
|
if ((await fd.stat()).mtime.getTime() !== mtime) {
|
||||||
|
if (count < 5) {
|
||||||
|
return readFileWithMeta(dir, fileName, count + 1)
|
||||||
|
}
|
||||||
|
console.warn(`Failed to read file \`${fileName}\` as it changed during read.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: fileName,
|
||||||
|
data,
|
||||||
|
attrs: {
|
||||||
|
mtime,
|
||||||
|
size: stats.size,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(`Failed to read file \`${fileName}\`:`, err)
|
||||||
|
} finally {
|
||||||
|
await fd?.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function restoreCache (cwd: string, cacheFile: string) {
|
||||||
|
if (!existsSync(cacheFile)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = parseTar(await readFile(cacheFile))
|
||||||
|
for (const file of files) {
|
||||||
|
let fd: FileHandle | undefined = undefined
|
||||||
|
try {
|
||||||
|
const filePath = resolve(cwd, file.name)
|
||||||
|
await mkdir(dirname(filePath), { recursive: true })
|
||||||
|
|
||||||
|
fd = await open(filePath, 'w')
|
||||||
|
|
||||||
|
const stats = await fd.stat().catch(() => null)
|
||||||
|
if (stats?.isFile() && stats.size) {
|
||||||
|
const lastModified = Number.parseInt(file.attrs?.mtime?.toString().padEnd(13, '0') || '0')
|
||||||
|
if (stats.mtime.getTime() >= lastModified) {
|
||||||
|
consola.debug(`Skipping \`${file.name}\` (up to date or newer than cache)`)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await fd.writeFile(file.data!)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
} finally {
|
||||||
|
await fd?.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
async function writeCache (cwd: string, sources: string | string[], cacheFile: string) {
|
||||||
|
const fileEntries = await readFilesRecursive(sources, {
|
||||||
|
patterns: ['**/*', '!analyze/**'],
|
||||||
|
cwd,
|
||||||
|
})
|
||||||
|
const tarData = createTar(fileEntries)
|
||||||
|
await mkdir(dirname(cacheFile), { recursive: true })
|
||||||
|
await writeFile(cacheFile, tarData)
|
||||||
|
}
|
@ -517,26 +517,30 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function symlinkDist () {
|
||||||
|
if (nitro.options.static) {
|
||||||
|
const distDir = resolve(nuxt.options.rootDir, 'dist')
|
||||||
|
if (!existsSync(distDir)) {
|
||||||
|
await fsp.symlink(nitro.options.output.publicDir, distDir, 'junction').catch(() => {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// nuxt build/dev
|
// nuxt build/dev
|
||||||
nuxt.hook('build:done', async () => {
|
nuxt.hook('build:done', async () => {
|
||||||
await nuxt.callHook('nitro:build:before', nitro)
|
await nuxt.callHook('nitro:build:before', nitro)
|
||||||
if (nuxt.options.dev) {
|
if (nuxt.options.dev) {
|
||||||
await build(nitro)
|
return build(nitro)
|
||||||
} else {
|
|
||||||
await prepare(nitro)
|
|
||||||
await prerender(nitro)
|
|
||||||
|
|
||||||
logger.restoreAll()
|
|
||||||
await build(nitro)
|
|
||||||
logger.wrapAll()
|
|
||||||
|
|
||||||
if (nitro.options.static) {
|
|
||||||
const distDir = resolve(nuxt.options.rootDir, 'dist')
|
|
||||||
if (!existsSync(distDir)) {
|
|
||||||
await fsp.symlink(nitro.options.output.publicDir, distDir, 'junction').catch(() => {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await prepare(nitro)
|
||||||
|
await prerender(nitro)
|
||||||
|
|
||||||
|
logger.restoreAll()
|
||||||
|
await build(nitro)
|
||||||
|
logger.wrapAll()
|
||||||
|
|
||||||
|
await symlinkDist()
|
||||||
})
|
})
|
||||||
|
|
||||||
// nuxt dev
|
// nuxt dev
|
||||||
|
@ -15,11 +15,13 @@ export function resolveDeepImportsPlugin (nuxt: Nuxt): Plugin {
|
|||||||
if (!importer || isAbsolute(id) || (!isAbsolute(importer) && !importer.startsWith('virtual:')) || exclude.some(e => id.startsWith(e))) {
|
if (!importer || isAbsolute(id) || (!isAbsolute(importer) && !importer.startsWith('virtual:')) || exclude.some(e => id.startsWith(e))) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id = normalize(id)
|
|
||||||
id = resolveAlias(id, nuxt.options.alias)
|
const normalisedId = resolveAlias(normalize(id), nuxt.options.alias)
|
||||||
const { dir } = parseNodeModulePath(importer)
|
const normalisedImporter = importer.replace(/^\0?virtual:(?:nuxt:)?/, '')
|
||||||
return await this.resolve?.(id, dir || pkgDir, { skipSelf: true }) ?? await resolvePath(id, {
|
const dir = parseNodeModulePath(normalisedImporter).dir || pkgDir
|
||||||
url: [dir || pkgDir, ...nuxt.options.modulesDir],
|
|
||||||
|
return await this.resolve?.(normalisedId, dir, { skipSelf: true }) ?? await resolvePath(id, {
|
||||||
|
url: [dir, ...nuxt.options.modulesDir],
|
||||||
// TODO: respect nitro runtime conditions
|
// TODO: respect nitro runtime conditions
|
||||||
conditions: options.ssr ? ['node', 'import', 'require'] : ['import', 'require'],
|
conditions: options.ssr ? ['node', 'import', 'require'] : ['import', 'require'],
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
|
@ -537,5 +537,12 @@ export default defineUntypedSchema({
|
|||||||
* It can reduce INP when navigating on prerendered routes.
|
* It can reduce INP when navigating on prerendered routes.
|
||||||
*/
|
*/
|
||||||
navigationRepaint: true,
|
navigationRepaint: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache Nuxt/Nitro build artifacts based on a hash of the configuration and source files.
|
||||||
|
*
|
||||||
|
* This only works for source files within `srcDir` and `serverDir` for the Vue/Nitro parts of your app.
|
||||||
|
*/
|
||||||
|
buildCache: false,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -358,6 +358,9 @@ importers:
|
|||||||
mlly:
|
mlly:
|
||||||
specifier: ^1.7.1
|
specifier: ^1.7.1
|
||||||
version: 1.7.1
|
version: 1.7.1
|
||||||
|
nanotar:
|
||||||
|
specifier: ^0.1.1
|
||||||
|
version: 0.1.1
|
||||||
nitropack:
|
nitropack:
|
||||||
specifier: ^2.9.7
|
specifier: ^2.9.7
|
||||||
version: 2.9.7(encoding@0.1.13)(magicast@0.3.4)
|
version: 2.9.7(encoding@0.1.13)(magicast@0.3.4)
|
||||||
@ -397,6 +400,9 @@ importers:
|
|||||||
strip-literal:
|
strip-literal:
|
||||||
specifier: ^2.1.0
|
specifier: ^2.1.0
|
||||||
version: 2.1.0
|
version: 2.1.0
|
||||||
|
tinyglobby:
|
||||||
|
specifier: 0.2.5
|
||||||
|
version: 0.2.5
|
||||||
ufo:
|
ufo:
|
||||||
specifier: ^1.5.4
|
specifier: ^1.5.4
|
||||||
version: 1.5.4
|
version: 1.5.4
|
||||||
@ -3612,7 +3618,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==}
|
resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: 5.5.4
|
typescript: '>=4.9.5'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
@ -3621,7 +3627,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==}
|
resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: 5.5.4
|
typescript: '>=4.9.5'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
@ -5490,6 +5496,9 @@ packages:
|
|||||||
engines: {node: ^18 || >=20}
|
engines: {node: ^18 || >=20}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
nanotar@0.1.1:
|
||||||
|
resolution: {integrity: sha512-AiJsGsSF3O0havL1BydvI4+wR76sKT+okKRwWIaK96cZUnXqH0uNBOsHlbwZq3+m2BR1VKqHDVudl3gO4mYjpQ==}
|
||||||
|
|
||||||
natural-compare-lite@1.4.0:
|
natural-compare-lite@1.4.0:
|
||||||
resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
|
resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
|
||||||
|
|
||||||
@ -7310,7 +7319,7 @@ packages:
|
|||||||
vue@3.4.38:
|
vue@3.4.38:
|
||||||
resolution: {integrity: sha512-f0ZgN+mZ5KFgVv9wz0f4OgVKukoXtS3nwET4c2vLBGQR50aI8G0cqbFtLlX9Yiyg3LFGBitruPHt2PxwTduJEw==}
|
resolution: {integrity: sha512-f0ZgN+mZ5KFgVv9wz0f4OgVKukoXtS3nwET4c2vLBGQR50aI8G0cqbFtLlX9Yiyg3LFGBitruPHt2PxwTduJEw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: 5.5.4
|
typescript: '*'
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
@ -12714,6 +12723,8 @@ snapshots:
|
|||||||
|
|
||||||
nanoid@5.0.7: {}
|
nanoid@5.0.7: {}
|
||||||
|
|
||||||
|
nanotar@0.1.1: {}
|
||||||
|
|
||||||
natural-compare-lite@1.4.0: {}
|
natural-compare-lite@1.4.0: {}
|
||||||
|
|
||||||
natural-compare@1.4.0: {}
|
natural-compare@1.4.0: {}
|
||||||
|
Loading…
Reference in New Issue
Block a user