Skip to content

Commit 7d2e603

Browse files
authored
perf(language-core): precompile attribute glob matchers (#6227)
1 parent e39a242 commit 7d2e603

3 files changed

Lines changed: 25 additions & 11 deletions

File tree

‎packages/language-core/lib/codegen/template/elementProps.ts‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as CompilerDOM from '@vue/compiler-dom';
22
import { camelize } from '@vue/shared';
3-
import { isMatch } from 'picomatch';
43
import type { Code, VueCodeInformation, VueCompilerOptions } from '../../types';
54
import { hyphenateAttr, hyphenateTag, normalizeAttributeValue } from '../../utils/shared';
65
import { codeFeatures } from '../codeFeatures';
@@ -95,7 +94,7 @@ export function* generateElementProps(
9594

9695
if (
9796
propName === undefined
98-
|| options.vueCompilerOptions.dataAttributes.some(pattern => isMatch(propName!, pattern))
97+
|| options.vueCompilerOptions.isDataAttribute(propName)
9998
) {
10099
if (prop.exp && prop.exp.constType !== CompilerDOM.ConstantTypes.CAN_STRINGIFY) {
101100
failedPropExps?.push({ node: prop.exp, prefix: `(`, suffix: `)` });
@@ -170,7 +169,7 @@ export function* generateElementProps(
170169
}
171170
}
172171
else if (prop.type === CompilerDOM.NodeTypes.ATTRIBUTE) {
173-
if (options.vueCompilerOptions.dataAttributes.some(pattern => isMatch(prop.name, pattern))) {
172+
if (options.vueCompilerOptions.isDataAttribute(prop.name)) {
174173
continue;
175174
}
176175

@@ -325,7 +324,7 @@ function getShouldCamelize(
325324
&& hyphenateAttr(propName) === propName
326325
&& (
327326
node.tagType === CompilerDOM.ElementTypes.SLOT
328-
|| !options.vueCompilerOptions.htmlAttributes.some(pattern => isMatch(propName, pattern))
327+
|| !options.vueCompilerOptions.isHtmlAttribute(propName)
329328
);
330329
}
331330

‎packages/language-core/lib/compilerOptions.ts‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { camelize } from '@vue/shared';
22
import { posix as path } from 'path-browserify';
3+
import picomatch from 'picomatch';
34
import type * as ts from 'typescript';
45
import type { RawPlugin, RawVueCompilerOptions, VueCompilerOptions, VueLanguagePlugin } from './types';
56
import { hyphenateTag } from './utils/shared';
@@ -200,6 +201,9 @@ export class CompilerOptionsResolver {
200201
).map(([k, v]) => [camelize(k), v]),
201202
),
202203
};
204+
// Compiling a glob costs far more than testing it, and codegen tests every prop against these
205+
resolvedOptions.isDataAttribute = picomatch(resolvedOptions.dataAttributes);
206+
resolvedOptions.isHtmlAttribute = picomatch(resolvedOptions.htmlAttributes);
203207

204208
return resolvedOptions;
205209
}
@@ -257,6 +261,9 @@ export function getDefaultCompilerOptions(
257261
? path.join(__dirname.replace(/\\/g, '/'), '..', 'types')
258262
: '@vue/language-core/types',
259263
): VueCompilerOptions {
264+
const dataAttributes: string[] = [];
265+
const htmlAttributes = ['aria-*'];
266+
260267
return {
261268
target,
262269
lib,
@@ -289,8 +296,10 @@ export function getDefaultCompilerOptions(
289296
'Teleport',
290297
'Suspense',
291298
],
292-
dataAttributes: [],
293-
htmlAttributes: ['aria-*'],
299+
dataAttributes,
300+
htmlAttributes,
301+
isDataAttribute: picomatch(dataAttributes),
302+
isHtmlAttribute: picomatch(htmlAttributes),
294303
optionsWrapper: [`(await import('${lib}')).defineComponent(`, `)`],
295304
macros: {
296305
defineProps: ['defineProps'],

‎packages/language-core/lib/types.ts‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@ export type { SFCParseResult } from '@vue/compiler-sfc';
99

1010
export { VueEmbeddedCode };
1111

12-
export type RawVueCompilerOptions = Partial<Omit<VueCompilerOptions, 'target' | 'plugins'>> & {
13-
strictTemplates?: boolean;
14-
target?: 'auto' | 3 | 3.3 | 3.5 | 3.6 | 99 | number;
15-
plugins?: RawPlugin[];
16-
};
12+
export type RawVueCompilerOptions =
13+
& Partial<
14+
Omit<VueCompilerOptions, 'target' | 'plugins' | 'isDataAttribute' | 'isHtmlAttribute'>
15+
>
16+
& {
17+
strictTemplates?: boolean;
18+
target?: 'auto' | 3 | 3.3 | 3.5 | 3.6 | 99 | number;
19+
plugins?: RawPlugin[];
20+
};
1721

1822
export type RawPlugin =
1923
| string
@@ -59,6 +63,8 @@ export interface VueCompilerOptions {
5963
fallthroughComponentNames: string[];
6064
dataAttributes: string[];
6165
htmlAttributes: string[];
66+
isDataAttribute: (name: string) => boolean;
67+
isHtmlAttribute: (name: string) => boolean;
6268
optionsWrapper: [string, string] | [];
6369
macros: {
6470
defineProps: string[];

0 commit comments

Comments
 (0)