From c3a76a5c395f4b629b9ac9c873af46437b701473 Mon Sep 17 00:00:00 2001 From: daiwei Date: Thu, 25 Sep 2025 11:27:38 +0800 Subject: [PATCH 1/2] feat(compiler-sfc): enhance cache management with configurable options --- packages/compiler-sfc/src/cache.ts | 25 +++++++++++++++++-- packages/compiler-sfc/src/index.ts | 3 +++ packages/compiler-sfc/src/parse.ts | 6 +++-- .../src/script/importUsageCheck.ts | 6 +++-- .../compiler-sfc/src/script/resolveType.ts | 6 ++--- 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/packages/compiler-sfc/src/cache.ts b/packages/compiler-sfc/src/cache.ts index 0bedc7b4d35..abc81274d19 100644 --- a/packages/compiler-sfc/src/cache.ts +++ b/packages/compiler-sfc/src/cache.ts @@ -1,11 +1,32 @@ import { LRUCache } from 'lru-cache' +export const COMPILER_CACHE_KEYS = { + parse: 'parse', + templateUsageCheck: 'templateUsageCheck', + tsConfig: 'tsConfig', + fileToScope: 'fileToScope', +} as const + +type CacheKey = keyof typeof COMPILER_CACHE_KEYS +type CacheOptions = Partial< + Record> +> + +let cacheOptions: CacheOptions = Object.create(null) + export function createCache( - max = 500, + key: CacheKey, ): Map | LRUCache { /* v8 ignore next 3 */ if (__GLOBAL__ || __ESM_BROWSER__) { return new Map() } - return new LRUCache({ max }) + return new LRUCache(cacheOptions[key] || { max: 500 }) +} + +/** + * @private + */ +export function configureCacheOptions(options: CacheOptions = {}): void { + cacheOptions = options } diff --git a/packages/compiler-sfc/src/index.ts b/packages/compiler-sfc/src/index.ts index 5123a908976..f890122b7b1 100644 --- a/packages/compiler-sfc/src/index.ts +++ b/packages/compiler-sfc/src/index.ts @@ -44,6 +44,9 @@ export { invalidateTypeCache, registerTS } from './script/resolveType' export { extractRuntimeProps } from './script/defineProps' export { extractRuntimeEmits } from './script/defineEmits' +// Internals for cache control +export { configureCacheOptions } from './cache' + // Types export type { SFCParseOptions, diff --git a/packages/compiler-sfc/src/parse.ts b/packages/compiler-sfc/src/parse.ts index 9172cfc67ff..ab173d25464 100644 --- a/packages/compiler-sfc/src/parse.ts +++ b/packages/compiler-sfc/src/parse.ts @@ -14,7 +14,7 @@ import * as CompilerDOM from '@vue/compiler-dom' import { SourceMapGenerator } from 'source-map-js' import type { TemplateCompiler } from './compileTemplate' import { parseCssVars } from './style/cssVars' -import { createCache } from './cache' +import { COMPILER_CACHE_KEYS, createCache } from './cache' import type { ImportBinding } from './compileScript' import { isUsedInTemplate } from './script/importUsageCheck' import type { LRUCache } from 'lru-cache' @@ -104,7 +104,9 @@ export interface SFCParseResult { export const parseCache: | Map - | LRUCache = createCache() + | LRUCache = createCache( + COMPILER_CACHE_KEYS.parse, +) export function parse( source: string, diff --git a/packages/compiler-sfc/src/script/importUsageCheck.ts b/packages/compiler-sfc/src/script/importUsageCheck.ts index 6fc16db446b..e5ead66772d 100644 --- a/packages/compiler-sfc/src/script/importUsageCheck.ts +++ b/packages/compiler-sfc/src/script/importUsageCheck.ts @@ -7,7 +7,7 @@ import { parserOptions, walkIdentifiers, } from '@vue/compiler-dom' -import { createCache } from '../cache' +import { COMPILER_CACHE_KEYS, createCache } from '../cache' import { camelize, capitalize, isBuiltInDirective } from '@vue/shared' /** @@ -23,7 +23,9 @@ export function isUsedInTemplate( return resolveTemplateUsedIdentifiers(sfc).has(identifier) } -const templateUsageCheckCache = createCache>() +const templateUsageCheckCache = createCache>( + COMPILER_CACHE_KEYS.templateUsageCheck, +) function resolveTemplateUsedIdentifiers(sfc: SFCDescriptor): Set { const { content, ast } = sfc.template! diff --git a/packages/compiler-sfc/src/script/resolveType.ts b/packages/compiler-sfc/src/script/resolveType.ts index d8f43070050..6d17d32a54f 100644 --- a/packages/compiler-sfc/src/script/resolveType.ts +++ b/packages/compiler-sfc/src/script/resolveType.ts @@ -37,7 +37,7 @@ import type { ImportBinding, SFCScriptCompileOptions } from '../compileScript' import { capitalize, hasOwn } from '@vue/shared' import { parse as babelParse } from '@babel/parser' import { parse } from '../parse' -import { createCache } from '../cache' +import { COMPILER_CACHE_KEYS, createCache } from '../cache' import type TS from 'typescript' import { dirname, extname, join } from 'path' import { minimatch as isMatch } from 'minimatch' @@ -999,7 +999,7 @@ interface CachedConfig { cache?: TS.ModuleResolutionCache } -const tsConfigCache = createCache() +const tsConfigCache = createCache(COMPILER_CACHE_KEYS.tsConfig) const tsConfigRefMap = new Map() function resolveWithTS( @@ -1123,7 +1123,7 @@ function loadTSConfig( return res } -const fileToScopeCache = createCache() +const fileToScopeCache = createCache(COMPILER_CACHE_KEYS.fileToScope) /** * @private From a5786924c52aa20f789314e74ce48c203e173b3b Mon Sep 17 00:00:00 2001 From: daiwei Date: Thu, 25 Sep 2025 16:26:23 +0800 Subject: [PATCH 2/2] chore: lazy call createCache --- packages/compiler-sfc/src/parse.ts | 11 ++++--- .../src/script/importUsageCheck.ts | 12 ++++--- .../compiler-sfc/src/script/resolveType.ts | 33 ++++++++++++++----- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/packages/compiler-sfc/src/parse.ts b/packages/compiler-sfc/src/parse.ts index ab173d25464..0e1d9547156 100644 --- a/packages/compiler-sfc/src/parse.ts +++ b/packages/compiler-sfc/src/parse.ts @@ -102,11 +102,9 @@ export interface SFCParseResult { errors: (CompilerError | SyntaxError)[] } -export const parseCache: +export let parseCache: | Map - | LRUCache = createCache( - COMPILER_CACHE_KEYS.parse, -) + | LRUCache export function parse( source: string, @@ -116,7 +114,10 @@ export function parse( ...options, compiler: { parse: options.compiler?.parse }, }) - const cache = parseCache.get(sourceKey) + const cache = ( + parseCache || + (parseCache = createCache(COMPILER_CACHE_KEYS.parse)) + ).get(sourceKey) if (cache) { return cache } diff --git a/packages/compiler-sfc/src/script/importUsageCheck.ts b/packages/compiler-sfc/src/script/importUsageCheck.ts index e5ead66772d..19c8c62e1d8 100644 --- a/packages/compiler-sfc/src/script/importUsageCheck.ts +++ b/packages/compiler-sfc/src/script/importUsageCheck.ts @@ -9,6 +9,7 @@ import { } from '@vue/compiler-dom' import { COMPILER_CACHE_KEYS, createCache } from '../cache' import { camelize, capitalize, isBuiltInDirective } from '@vue/shared' +import type { LRUCache } from 'lru-cache' /** * Check if an identifier is used in the SFC's template. @@ -23,13 +24,16 @@ export function isUsedInTemplate( return resolveTemplateUsedIdentifiers(sfc).has(identifier) } -const templateUsageCheckCache = createCache>( - COMPILER_CACHE_KEYS.templateUsageCheck, -) +let templateUsageCheckCache: LRUCache> function resolveTemplateUsedIdentifiers(sfc: SFCDescriptor): Set { const { content, ast } = sfc.template! - const cached = templateUsageCheckCache.get(content) + const cached = ( + templateUsageCheckCache || + (templateUsageCheckCache = createCache>( + COMPILER_CACHE_KEYS.templateUsageCheck, + ) as LRUCache>) + ).get(content) if (cached) { return cached } diff --git a/packages/compiler-sfc/src/script/resolveType.ts b/packages/compiler-sfc/src/script/resolveType.ts index 6d17d32a54f..020eaf8da56 100644 --- a/packages/compiler-sfc/src/script/resolveType.ts +++ b/packages/compiler-sfc/src/script/resolveType.ts @@ -42,6 +42,7 @@ import type TS from 'typescript' import { dirname, extname, join } from 'path' import { minimatch as isMatch } from 'minimatch' import * as process from 'process' +import type { LRUCache } from 'lru-cache' export type SimpleTypeResolveOptions = Partial< Pick< @@ -999,7 +1000,7 @@ interface CachedConfig { cache?: TS.ModuleResolutionCache } -const tsConfigCache = createCache(COMPILER_CACHE_KEYS.tsConfig) +let tsConfigCache: LRUCache const tsConfigRefMap = new Map() function resolveWithTS( @@ -1018,7 +1019,12 @@ function resolveWithTS( if (configPath) { let configs: CachedConfig[] const normalizedConfigPath = normalizePath(configPath) - const cached = tsConfigCache.get(normalizedConfigPath) + const cached = ( + tsConfigCache || + (tsConfigCache = createCache( + COMPILER_CACHE_KEYS.tsConfig, + ) as LRUCache) + ).get(normalizedConfigPath) if (!cached) { configs = loadTSConfig(configPath, ts, fs).map(config => ({ config })) tsConfigCache.set(normalizedConfigPath, configs) @@ -1123,17 +1129,21 @@ function loadTSConfig( return res } -const fileToScopeCache = createCache(COMPILER_CACHE_KEYS.fileToScope) +let fileToScopeCache: LRUCache /** * @private */ export function invalidateTypeCache(filename: string): void { filename = normalizePath(filename) - fileToScopeCache.delete(filename) - tsConfigCache.delete(filename) - const affectedConfig = tsConfigRefMap.get(filename) - if (affectedConfig) tsConfigCache.delete(affectedConfig) + if (fileToScopeCache) { + fileToScopeCache.delete(filename) + } + if (tsConfigCache) { + tsConfigCache.delete(filename) + const affectedConfig = tsConfigRefMap.get(filename) + if (affectedConfig) tsConfigCache.delete(affectedConfig) + } } export function fileToScope( @@ -1141,7 +1151,12 @@ export function fileToScope( filename: string, asGlobal = false, ): TypeScope { - const cached = fileToScopeCache.get(filename) + const cached = ( + fileToScopeCache || + (fileToScopeCache = createCache( + COMPILER_CACHE_KEYS.fileToScope, + ) as LRUCache) + ).get(filename) if (cached) { return cached } @@ -1151,7 +1166,7 @@ export function fileToScope( const body = parseFile(filename, source, fs, ctx.options.babelParserPlugins) const scope = new TypeScope(filename, source, 0, recordImports(body)) recordTypes(ctx, body, scope, asGlobal) - fileToScopeCache.set(filename, scope) + fileToScopeCache!.set(filename, scope) return scope }