From 8451b92a7a231a8c4b8e936f0918e321d38ce690 Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 13 Apr 2023 22:38:00 +0800 Subject: [PATCH] wip: cache fileToScope + improve vue file offset --- .../compileScript/resolveType.spec.ts | 5 ++ packages/compiler-sfc/src/cache.ts | 10 ++-- packages/compiler-sfc/src/index.ts | 1 + packages/compiler-sfc/src/script/context.ts | 2 +- .../compiler-sfc/src/script/resolveType.ts | 51 +++++++++++++++---- 5 files changed, 54 insertions(+), 15 deletions(-) diff --git a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts index c686a99ff..3e2a5ee17 100644 --- a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts @@ -3,6 +3,7 @@ import { parse } from '../../src' import { ScriptCompileContext } from '../../src/script/context' import { inferRuntimeType, + invalidateTypeCache, recordImports, resolveTypeElements } from '../../src/script/resolveType' @@ -369,6 +370,10 @@ function resolve(code: string, files: Record = {}) { } }) + for (const file in files) { + invalidateTypeCache(file) + } + // ctx.userImports is collected when calling compileScript(), but we are // skipping that here, so need to manually register imports ctx.userImports = recordImports(ctx.scriptSetupAst!.body) as any diff --git a/packages/compiler-sfc/src/cache.ts b/packages/compiler-sfc/src/cache.ts index 510dfee35..eb6bad0f8 100644 --- a/packages/compiler-sfc/src/cache.ts +++ b/packages/compiler-sfc/src/cache.ts @@ -1,7 +1,11 @@ import LRU from 'lru-cache' export function createCache(size = 500) { - return __GLOBAL__ || __ESM_BROWSER__ - ? new Map() - : (new LRU(size) as any as Map) + if (__GLOBAL__ || __ESM_BROWSER__) { + return new Map() + } + const cache = new LRU(size) + // @ts-expect-error + cache.delete = cache.del.bind(cache) + return cache as any as Map } diff --git a/packages/compiler-sfc/src/index.ts b/packages/compiler-sfc/src/index.ts index 6ba097b24..0b936553a 100644 --- a/packages/compiler-sfc/src/index.ts +++ b/packages/compiler-sfc/src/index.ts @@ -6,6 +6,7 @@ export { compileTemplate } from './compileTemplate' export { compileStyle, compileStyleAsync } from './compileStyle' export { compileScript } from './compileScript' export { rewriteDefault, rewriteDefaultAST } from './rewriteDefault' +export { invalidateTypeCache } from './script/resolveType' export { shouldTransform as shouldTransformRef, transform as transformRef, diff --git a/packages/compiler-sfc/src/script/context.ts b/packages/compiler-sfc/src/script/context.ts index efdf1368c..ec6bbe8d0 100644 --- a/packages/compiler-sfc/src/script/context.ts +++ b/packages/compiler-sfc/src/script/context.ts @@ -126,7 +126,7 @@ export class ScriptCompileContext { } error(msg: string, node: Node & WithScope, scope?: TypeScope): never { - const offset = scope ? scope.offset || 0 : this.startOffset! + const offset = scope ? scope.offset : this.startOffset! throw new Error( `[@vue/compiler-sfc] ${msg}\n\n${ (scope || this.descriptor).filename diff --git a/packages/compiler-sfc/src/script/resolveType.ts b/packages/compiler-sfc/src/script/resolveType.ts index f885b9702..c48e192f6 100644 --- a/packages/compiler-sfc/src/script/resolveType.ts +++ b/packages/compiler-sfc/src/script/resolveType.ts @@ -27,6 +27,7 @@ import { capitalize, hasOwn } from '@vue/shared' import path from 'path' import { parse as babelParse } from '@babel/parser' import { parse } from '../parse' +import { createCache } from '../cache' type Import = Pick @@ -539,23 +540,35 @@ function resolveExt( ) } +const fileToScopeCache = createCache() + +export function invalidateTypeCache(filename: string) { + fileToScopeCache.delete(filename) +} + function fileToScope( ctx: ScriptCompileContext, filename: string, fs: NonNullable ): TypeScope { - // TODO cache + const cached = fileToScopeCache.get(filename) + if (cached) { + return cached + } + const source = fs.readFile(filename) - const [body, offset] = parseFile(ctx, filename, source) + const body = parseFile(ctx, filename, source) const scope: TypeScope = { filename, source, - offset, + offset: 0, types: Object.create(null), exportedTypes: Object.create(null), imports: recordImports(body) } recordTypes(body, scope) + + fileToScopeCache.set(filename, scope) return scope } @@ -563,12 +576,10 @@ function parseFile( ctx: ScriptCompileContext, filename: string, content: string -): [Statement[], number] { - let body: Statement[] = [] - let offset = 0 +): Statement[] { const ext = path.extname(filename) if (ext === '.ts' || ext === '.tsx') { - body = babelParse(content, { + return babelParse(content, { plugins: resolveParserPlugins( ext.slice(1), ctx.options.babelParserPlugins @@ -579,15 +590,33 @@ function parseFile( const { descriptor: { script, scriptSetup } } = parse(content) - const scriptContent = (script?.content || '') + (scriptSetup?.content || '') + if (!script && !scriptSetup) { + return [] + } + + // ensure the correct offset with original source + const scriptOffset = script ? script.loc.start.offset : Infinity + const scriptSetupOffset = scriptSetup + ? scriptSetup.loc.start.offset + : Infinity + const firstBlock = scriptOffset < scriptSetupOffset ? script : scriptSetup + const secondBlock = scriptOffset < scriptSetupOffset ? scriptSetup : script + + let scriptContent = + ' '.repeat(Math.min(scriptOffset, scriptSetupOffset)) + + firstBlock!.content + if (secondBlock) { + scriptContent += + ' '.repeat(secondBlock.loc.start.offset - script!.loc.end.offset) + + secondBlock.content + } const lang = script?.lang || scriptSetup?.lang - body = babelParse(scriptContent, { + return babelParse(scriptContent, { plugins: resolveParserPlugins(lang!, ctx.options.babelParserPlugins), sourceType: 'module' }).program.body - offset = scriptSetup ? scriptSetup.loc.start.offset : 0 } - return [body, offset] + return [] } function ctxToScope(ctx: ScriptCompileContext): TypeScope {