Skip to content

Commit

Permalink
perf: incremental SFC parser
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsoncodehk committed Aug 28, 2022
1 parent a0ab1d2 commit b196176
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 7 deletions.
45 changes: 43 additions & 2 deletions packages/vue-language-core/src/plugins/file-vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,48 @@ const plugin: VueLanguagePlugin = () => {

return parse(content, { sourceMap: false, ignoreEmpty: false });
}
}
},

updateSFC(sfc, change) {

// avoid broken @vue/compiler-sfc cache
if (!(sfc as any).__volar_clone) {
sfc = JSON.parse(JSON.stringify(sfc));
(sfc as any).__volar_clone = true;
}

const blocks = [
sfc.descriptor.template,
sfc.descriptor.script,
sfc.descriptor.scriptSetup,
...sfc.descriptor.styles,
...sfc.descriptor.customBlocks,
].filter((block): block is NonNullable<typeof block> => !!block);

const hitBlock = blocks.find(block => change.start >= block.loc.start.offset && change.end <= block.loc.end.offset);

if (!hitBlock) {
return;
}

hitBlock.content =
hitBlock.content.substring(0, change.start - hitBlock.loc.start.offset)
+ change.newText
+ hitBlock.content.substring(change.end - hitBlock.loc.start.offset);

const lengthDiff = change.newText.length - (change.end - change.start);

for (const block of blocks) {
if (block.loc.start.offset >= change.end) {
block.loc.start.offset += lengthDiff;
}
if (block.loc.end.offset >= change.end) {
block.loc.end.offset += lengthDiff;
}
}

return sfc;
},
};
}
};
export = plugin;
39 changes: 34 additions & 5 deletions packages/vue-language-core/src/sourceFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type VueLanguagePlugin = (ctx: {
}) => {
order?: number;
parseSFC?(fileName: string, content: string): SFCParseResult | undefined;
updateSFC?(oldResult: SFCParseResult, textChange: { start: number, end: number, newText: string; }): SFCParseResult | undefined;
compileSFCTemplate?(lang: string, template: string, options?: CompilerDom.CompilerOptions): CompilerDom.CodegenResult | undefined;
getEmbeddedFileNames?(fileName: string, sfc: Sfc): string[];
resolveEmbeddedFile?(fileName: string, sfc: Sfc, embeddedFile: EmbeddedFile): void;
Expand Down Expand Up @@ -109,6 +110,13 @@ export function createSourceFile(
}) as unknown as Sfc['scriptSetupAst'],
}) as Sfc /* avoid Sfc unwrap in .d.ts by reactive */;

// cache
let parsedSfcCache: {
snapshot: ts.IScriptSnapshot,
sfc: SFCParseResult,
plugin: ReturnType<VueLanguagePlugin>,
} | undefined;

// use
const scriptAst = computed(() => {
if (sfc.script) {
Expand All @@ -121,9 +129,28 @@ export function createSourceFile(
}
});
const parsedSfc = computed(() => {

// incremental update
if (parsedSfcCache?.plugin.updateSFC) {
const change = snapshot.value.getChangeRange(parsedSfcCache.snapshot);
if (change) {
const newSfc = parsedSfcCache.plugin.updateSFC(parsedSfcCache.sfc, {
start: change.span.start,
end: change.span.start + change.span.length,
newText: snapshot.value.getText(change.span.start, change.span.start + change.newLength),
});
if (newSfc) {
parsedSfcCache.snapshot = snapshot.value;
parsedSfcCache.sfc = newSfc;
return newSfc;
}
}
}

for (const plugin of plugins) {
const sfc = plugin.parseSFC?.(fileName, fileContent.value);
if (sfc) {
parsedSfcCache = { snapshot: snapshot.value, sfc, plugin };
return sfc;
}
}
Expand Down Expand Up @@ -404,13 +431,8 @@ export function createSourceFile(
return;
}

const change = newScriptSnapshot.getChangeRange(snapshot.value);
snapshot.value = newScriptSnapshot;

if (change) {
// TODO
}

// TODO: wait for https://github.com/vuejs/core/pull/5912
if (parsedSfc.value) {
updateTemplate(parsedSfc.value.descriptor.template);
Expand All @@ -419,6 +441,13 @@ export function createSourceFile(
updateStyles(parsedSfc.value.descriptor.styles);
updateCustomBlocks(parsedSfc.value.descriptor.customBlocks);
}
else {
updateTemplate(null);
updateScript(null);
updateScriptSetup(null);
updateStyles([]);
updateCustomBlocks([]);
}

function updateTemplate(block: SFCTemplateBlock | null) {

Expand Down

0 comments on commit b196176

Please sign in to comment.