diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index 36ced1c6075d..a9a4539616a9 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -109,6 +109,7 @@ "unimport": "^3.7.1", "unplugin": "^1.8.2", "unplugin-vue-router": "^0.7.0", + "unstorage": "^1.10.1", "untyped": "^1.4.2", "vue": "^3.4.21", "vue-bundle-renderer": "^2.0.0", diff --git a/packages/nuxt/src/core/nitro.ts b/packages/nuxt/src/core/nitro.ts index 8a78dbfa75cf..9bb9fddfa9e2 100644 --- a/packages/nuxt/src/core/nitro.ts +++ b/packages/nuxt/src/core/nitro.ts @@ -1,3 +1,4 @@ +import { pathToFileURL } from 'node:url' import { existsSync, promises as fsp, readFileSync } from 'node:fs' import { cpus } from 'node:os' import { join, normalize, relative, resolve } from 'pathe' @@ -6,7 +7,7 @@ import { randomUUID } from 'uncrypto' import { joinURL, withTrailingSlash } from 'ufo' import { build, copyPublicAssets, createDevServer, createNitro, prepare, prerender, scanHandlers, writeTypes } from 'nitropack' import type { Nitro, NitroConfig } from 'nitropack' -import { findPath, logger, resolveIgnorePatterns, resolveNuxtModule } from '@nuxt/kit' +import { findPath, logger, resolveIgnorePatterns, resolveNuxtModule, resolvePath } from '@nuxt/kit' import escapeRE from 'escape-string-regexp' import { defu } from 'defu' import fsExtra from 'fs-extra' @@ -392,11 +393,12 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) { } }) - // Set prerender-only options - nitro.options._config.storage ||= {} - nitro.options._config.storage['internal:nuxt:prerender'] = { driver: 'memory' } - nitro.options._config.storage['internal:nuxt:prerender:island'] = { driver: 'lruCache', max: 1000 } - nitro.options._config.storage['internal:nuxt:prerender:payload'] = { driver: 'lruCache', max: 1000 } + nitro.options._config.storage = defu(nitro.options._config.storage, { + 'internal:nuxt:prerender': { + driver: pathToFileURL(await resolvePath(join(distDir, 'core/runtime/nitro/cache-driver'))).href, + base: resolve(nuxt.options.buildDir, 'cache/nitro/prerender') + } + }) // Expose nitro to modules and kit nuxt._nitro = nitro diff --git a/packages/nuxt/src/core/runtime/nitro/cache-driver.ts b/packages/nuxt/src/core/runtime/nitro/cache-driver.ts new file mode 100644 index 000000000000..92920a4b4be5 --- /dev/null +++ b/packages/nuxt/src/core/runtime/nitro/cache-driver.ts @@ -0,0 +1,27 @@ +import { defineDriver } from 'unstorage' +import fsDriver from 'unstorage/drivers/fs-lite' +import lruCache from 'unstorage/drivers/lru-cache' + +// Ensure we don't try to write/read from directory index for `/` paths +const normalizeFsKey = (item: string) => item.indexOf(':') === -1 ? `${item}:index` : item + +export default defineDriver((opts: { base: string }) => { + const fs = fsDriver({ base: opts.base }) + const lru = lruCache({ max: 1000 }) + + return { + ...fs, // fall back to file system - only the bottom three methods are used in renderer + async setItem (key, value, opts) { + await Promise.all([ + fs.setItem(normalizeFsKey(key), value, opts), + lru.setItem(key, value, opts) + ]) + }, + async hasItem (key, opts) { + return await lru.hasItem(key, opts) || await fs.hasItem(normalizeFsKey(key), opts) + }, + async getItem (key, opts) { + return await lru.getItem(key, opts) || await fs.getItem(normalizeFsKey(key), opts) + }, + } +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 06711133753c..af61055ed29f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -395,6 +395,9 @@ importers: unplugin-vue-router: specifier: ^0.7.0 version: 0.7.0(rollup@4.12.1)(vue-router@4.3.0)(vue@3.4.21) + unstorage: + specifier: ^1.10.1 + version: 1.10.1 untyped: specifier: ^1.4.2 version: 1.4.2