فهرست منبع

wip: cache fileToScope + improve vue file offset

Evan You 3 سال پیش
والد
کامیت
8451b92a7a

+ 5 - 0
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<string, string> = {}) {
     }
   })
 
+  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

+ 7 - 3
packages/compiler-sfc/src/cache.ts

@@ -1,7 +1,11 @@
 import LRU from 'lru-cache'
 
 export function createCache<T>(size = 500) {
-  return __GLOBAL__ || __ESM_BROWSER__
-    ? new Map<string, T>()
-    : (new LRU(size) as any as Map<string, T>)
+  if (__GLOBAL__ || __ESM_BROWSER__) {
+    return new 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>
 }

+ 1 - 0
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,

+ 1 - 1
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

+ 40 - 11
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<ImportBinding, 'source' | 'imported'>
 
@@ -539,23 +540,35 @@ function resolveExt(
   )
 }
 
+const fileToScopeCache = createCache<TypeScope>()
+
+export function invalidateTypeCache(filename: string) {
+  fileToScopeCache.delete(filename)
+}
+
 function fileToScope(
   ctx: ScriptCompileContext,
   filename: string,
   fs: NonNullable<SFCScriptCompileOptions['fs']>
 ): 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 {