]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: cache fileToScope + improve vue file offset
authorEvan You <yyx990803@gmail.com>
Thu, 13 Apr 2023 14:38:00 +0000 (22:38 +0800)
committerEvan You <yyx990803@gmail.com>
Sat, 15 Apr 2023 14:08:39 +0000 (22:08 +0800)
packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts
packages/compiler-sfc/src/cache.ts
packages/compiler-sfc/src/index.ts
packages/compiler-sfc/src/script/context.ts
packages/compiler-sfc/src/script/resolveType.ts

index c686a99ff936e6d476014e78f7accf696f99efb3..3e2a5ee17763650baf96cb180da543f5d89efa6f 100644 (file)
@@ -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
index 510dfee3547bc661c19d9bcd0a6c99131839bee6..eb6bad0f86de8f1bf28da1f81b0414f285026688 100644 (file)
@@ -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>
 }
index 6ba097b2466885092f2e28f11059c32cf7c463d2..0b936553a32f6790dd2ecd5312129f7d96425b41 100644 (file)
@@ -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,
index efdf1368c340e33eaf512e171c5c06cf7240e0dc..ec6bbe8d0f17472d230cd5f24468bb80bcc6d868 100644 (file)
@@ -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
index f885b970212868f4b9ea68e52fa31384c4f8d50e..c48e192f64140dc120443adfe0050ae737f32e3e 100644 (file)
@@ -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 {