wip: cache fileToScope + improve vue file offset

This commit is contained in:
Evan You 2023-04-13 22:38:00 +08:00
parent c93c11710e
commit 8451b92a7a
5 changed files with 54 additions and 15 deletions

View File

@ -3,6 +3,7 @@ import { parse } from '../../src'
import { ScriptCompileContext } from '../../src/script/context' import { ScriptCompileContext } from '../../src/script/context'
import { import {
inferRuntimeType, inferRuntimeType,
invalidateTypeCache,
recordImports, recordImports,
resolveTypeElements resolveTypeElements
} from '../../src/script/resolveType' } from '../../src/script/resolveType'
@ -369,6 +370,10 @@ function resolve(code: string, files: Record<string, string> = {}) {
} }
}) })
for (const file in files) {
invalidateTypeCache(file)
}
// ctx.userImports is collected when calling compileScript(), but we are // ctx.userImports is collected when calling compileScript(), but we are
// skipping that here, so need to manually register imports // skipping that here, so need to manually register imports
ctx.userImports = recordImports(ctx.scriptSetupAst!.body) as any ctx.userImports = recordImports(ctx.scriptSetupAst!.body) as any

View File

@ -1,7 +1,11 @@
import LRU from 'lru-cache' import LRU from 'lru-cache'
export function createCache<T>(size = 500) { export function createCache<T>(size = 500) {
return __GLOBAL__ || __ESM_BROWSER__ if (__GLOBAL__ || __ESM_BROWSER__) {
? new Map<string, T>() return new Map<string, T>()
: (new LRU(size) as any as Map<string, T>) }
const cache = new LRU(size)
// @ts-expect-error
cache.delete = cache.del.bind(cache)
return cache as any as Map<string, T>
} }

View File

@ -6,6 +6,7 @@ export { compileTemplate } from './compileTemplate'
export { compileStyle, compileStyleAsync } from './compileStyle' export { compileStyle, compileStyleAsync } from './compileStyle'
export { compileScript } from './compileScript' export { compileScript } from './compileScript'
export { rewriteDefault, rewriteDefaultAST } from './rewriteDefault' export { rewriteDefault, rewriteDefaultAST } from './rewriteDefault'
export { invalidateTypeCache } from './script/resolveType'
export { export {
shouldTransform as shouldTransformRef, shouldTransform as shouldTransformRef,
transform as transformRef, transform as transformRef,

View File

@ -126,7 +126,7 @@ export class ScriptCompileContext {
} }
error(msg: string, node: Node & WithScope, scope?: TypeScope): never { 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( throw new Error(
`[@vue/compiler-sfc] ${msg}\n\n${ `[@vue/compiler-sfc] ${msg}\n\n${
(scope || this.descriptor).filename (scope || this.descriptor).filename

View File

@ -27,6 +27,7 @@ import { capitalize, hasOwn } from '@vue/shared'
import path from 'path' import path from 'path'
import { parse as babelParse } from '@babel/parser' import { parse as babelParse } from '@babel/parser'
import { parse } from '../parse' import { parse } from '../parse'
import { createCache } from '../cache'
type Import = Pick<ImportBinding, 'source' | 'imported'> type Import = Pick<ImportBinding, 'source' | 'imported'>
@ -539,23 +540,35 @@ function resolveExt(
) )
} }
const fileToScopeCache = createCache<TypeScope>()
export function invalidateTypeCache(filename: string) {
fileToScopeCache.delete(filename)
}
function fileToScope( function fileToScope(
ctx: ScriptCompileContext, ctx: ScriptCompileContext,
filename: string, filename: string,
fs: NonNullable<SFCScriptCompileOptions['fs']> fs: NonNullable<SFCScriptCompileOptions['fs']>
): TypeScope { ): TypeScope {
// TODO cache const cached = fileToScopeCache.get(filename)
if (cached) {
return cached
}
const source = fs.readFile(filename) const source = fs.readFile(filename)
const [body, offset] = parseFile(ctx, filename, source) const body = parseFile(ctx, filename, source)
const scope: TypeScope = { const scope: TypeScope = {
filename, filename,
source, source,
offset, offset: 0,
types: Object.create(null), types: Object.create(null),
exportedTypes: Object.create(null), exportedTypes: Object.create(null),
imports: recordImports(body) imports: recordImports(body)
} }
recordTypes(body, scope) recordTypes(body, scope)
fileToScopeCache.set(filename, scope)
return scope return scope
} }
@ -563,12 +576,10 @@ function parseFile(
ctx: ScriptCompileContext, ctx: ScriptCompileContext,
filename: string, filename: string,
content: string content: string
): [Statement[], number] { ): Statement[] {
let body: Statement[] = []
let offset = 0
const ext = path.extname(filename) const ext = path.extname(filename)
if (ext === '.ts' || ext === '.tsx') { if (ext === '.ts' || ext === '.tsx') {
body = babelParse(content, { return babelParse(content, {
plugins: resolveParserPlugins( plugins: resolveParserPlugins(
ext.slice(1), ext.slice(1),
ctx.options.babelParserPlugins ctx.options.babelParserPlugins
@ -579,15 +590,33 @@ function parseFile(
const { const {
descriptor: { script, scriptSetup } descriptor: { script, scriptSetup }
} = parse(content) } = 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 const lang = script?.lang || scriptSetup?.lang
body = babelParse(scriptContent, { return babelParse(scriptContent, {
plugins: resolveParserPlugins(lang!, ctx.options.babelParserPlugins), plugins: resolveParserPlugins(lang!, ctx.options.babelParserPlugins),
sourceType: 'module' sourceType: 'module'
}).program.body }).program.body
offset = scriptSetup ? scriptSetup.loc.start.offset : 0
} }
return [body, offset] return []
} }
function ctxToScope(ctx: ScriptCompileContext): TypeScope { function ctxToScope(ctx: ScriptCompileContext): TypeScope {