Skip to content

refactor: refining vapor mode #13148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 30 commits into
base: vapor
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4972e17
refactor(reactivity): associate effects and effect scopes based on do…
johnsoncodehk Apr 2, 2025
1b0d881
refactor(runtime-core): decouple pre type scheduler job processing
johnsoncodehk Apr 5, 2025
7a907d5
refactor(runtime-vapor): rewrite renderEffect as a class
johnsoncodehk Apr 6, 2025
8178e99
feat(benchmark): add fast-bench script
johnsoncodehk Apr 6, 2025
2c83f9a
feat(compiler-vapor, runtime-vapor): recognize selector pattern and k…
johnsoncodehk Apr 11, 2025
5f10bfe
refactor(reactivity): execute effect stop in unlink
johnsoncodehk Apr 11, 2025
e4c548c
refactor(runtime-vapor): redo v-for updating
johnsoncodehk Apr 13, 2025
63f4328
refactor: minor code adjustments
johnsoncodehk Apr 15, 2025
6744e6f
refactor: make effect scope enable/disable logic symmetric
johnsoncodehk Apr 15, 2025
679b779
refactor(runtime-vapor): move moveOrMount function
johnsoncodehk Apr 15, 2025
6a439c8
perf(runtime-vapor): remove reliance on onScopeDispose in useSelector
johnsoncodehk Apr 15, 2025
621044a
fix(runtime-vapor): setup minimum valid length of pendingNews
johnsoncodehk Apr 16, 2025
a3647c0
refactor(reactivity): rename "callback" to "fn" in ReactiveEffect
johnsoncodehk Apr 16, 2025
706f283
refactor(reactivity): remove SubscriberFlags.Propagated
johnsoncodehk Apr 16, 2025
9b1acbd
refactor(reactivity): do not use effect active getter
johnsoncodehk Apr 16, 2025
da80efb
perf(runtime-vapor): fast path to replace all rows
johnsoncodehk Apr 16, 2025
0545b64
Revert "feat(benchmark): add fast-bench script"
johnsoncodehk Apr 17, 2025
34cb64c
fix(runtime-vapor): add simpleSetCurrentInstance to address performan…
johnsoncodehk May 1, 2025
2b186d3
refactor(reactivity): optimize dirty flag checks
johnsoncodehk Apr 18, 2025
46048c0
perf(runtime-vapor): preallocate memory
johnsoncodehk Apr 25, 2025
52804c7
pref(runtime-vapor): add fast path for append rows
johnsoncodehk Apr 26, 2025
335a450
refactor(runtime-core): improve scheduler code reusability
johnsoncodehk Apr 27, 2025
cd12350
refactor(reactivity): simplify Effect, EffectScope cleanup behavior
johnsoncodehk Apr 17, 2025
281e1f9
refactor(runtime-core): pre-refactoring of scheduling rewrite
johnsoncodehk Apr 18, 2025
7a410ad
refactor(runtime-core): reduce the abstraction of base watcher
johnsoncodehk Apr 27, 2025
7a161f1
perf(reactivity): use fast path for notify a single effect
johnsoncodehk Apr 28, 2025
8e2d140
refactor(reactivity): fix cleanup performance regression
johnsoncodehk May 2, 2025
0ab95b7
refactor(runtime-vapor): replace apply with spread operator for key e…
johnsoncodehk May 2, 2025
b4c4fef
refactor(runtime-core): update queueJob to accept order parameter for…
johnsoncodehk May 2, 2025
4765af3
refactor(reactivity): alien-signals 2.0.1
johnsoncodehk May 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,27 @@ export function render(_ctx) {
}"
`;

exports[`compiler: v-for > key only binding pattern 1`] = `
"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, createFor as _createFor, template as _template } from 'vue';
const t0 = _template("<tr> </tr>", true)

export function render(_ctx) {
const n0 = _createFor(() => (_ctx.rows), (_for_item0) => {
const n2 = t0()
const x2 = _child(n2)
let _row, _row_id
{
_row = _for_item0.value
_row_id = _row.id

}
_setText(x2, _toDisplayString(_row_id + _row_id))
return n2
}, (row) => (row.id))
return n0
}"
`;

exports[`compiler: v-for > multi effect 1`] = `
"import { setProp as _setProp, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
const t0 = _template("<div></div>", true)
Expand Down Expand Up @@ -115,6 +136,75 @@ export function render(_ctx) {
}"
`;

exports[`compiler: v-for > selector pattern 1`] = `
"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, createFor as _createFor, template as _template } from 'vue';
const t0 = _template("<tr> </tr>", true)

export function render(_ctx) {
const n0 = _createFor(() => (_ctx.rows), (_for_item0) => {
const n2 = t0()
const x2 = _child(n2)
_selector0_0(() => {
_setText(x2, _toDisplayString(_ctx.selected === _for_item0.value.id ? 'danger' : ''))
})
return n2
}, (row) => (row.id))
const _selector0_0 = n0.useSelector(() => _ctx.selected)
return n0
}"
`;

exports[`compiler: v-for > selector pattern 2`] = `
"import { setClass as _setClass, createFor as _createFor, template as _template } from 'vue';
const t0 = _template("<tr></tr>", true)

export function render(_ctx) {
const n0 = _createFor(() => (_ctx.rows), (_for_item0) => {
const n2 = t0()
_selector0_0(() => {
_setClass(n2, _ctx.selected === _for_item0.value.id ? 'danger' : '')
})
return n2
}, (row) => (row.id))
const _selector0_0 = n0.useSelector(() => _ctx.selected)
return n0
}"
`;

exports[`compiler: v-for > selector pattern 3`] = `
"import { setClass as _setClass, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
const t0 = _template("<tr></tr>", true)

export function render(_ctx) {
const n0 = _createFor(() => (_ctx.rows), (_for_item0) => {
const n2 = t0()
_renderEffect(() => {
const _row = _for_item0.value
_setClass(n2, _row.label === _row.id ? 'danger' : '')
})
return n2
}, (row) => (row.id))
return n0
}"
`;

exports[`compiler: v-for > selector pattern 4`] = `
"import { setClass as _setClass, createFor as _createFor, template as _template } from 'vue';
const t0 = _template("<tr></tr>", true)

export function render(_ctx) {
const n0 = _createFor(() => (_ctx.rows), (_for_item0) => {
const n2 = t0()
_selector0_0(() => {
_setClass(n2, { danger: _for_item0.value.id === _ctx.selected })
})
return n2
}, (row) => (row.id))
const _selector0_0 = n0.useSelector(() => _ctx.selected)
return n0
}"
`;

exports[`compiler: v-for > v-for aliases w/ complex expressions 1`] = `
"import { getDefaultValue as _getDefaultValue, child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue';
const t0 = _template("<div> </div>", true)
Expand Down
67 changes: 67 additions & 0 deletions packages/compiler-vapor/__tests__/transforms/vFor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,73 @@ describe('compiler: v-for', () => {
).lengthOf(1)
})

test('key only binding pattern', () => {
expect(
compileWithVFor(
`
<tr
v-for="row of rows"
:key="row.id"
>
{{ row.id + row.id }}
</tr>
`,
).code,
).matchSnapshot()
})

test('selector pattern', () => {
expect(
compileWithVFor(
`
<tr
v-for="row of rows"
:key="row.id"
>
{{ selected === row.id ? 'danger' : '' }}
</tr>
`,
).code,
).matchSnapshot()

expect(
compileWithVFor(
`
<tr
v-for="row of rows"
:key="row.id"
:class="selected === row.id ? 'danger' : ''"
></tr>
`,
).code,
).matchSnapshot()

// Should not be optimized because row.label is not from parent scope
expect(
compileWithVFor(
`
<tr
v-for="row of rows"
:key="row.id"
:class="row.label === row.id ? 'danger' : ''"
></tr>
`,
).code,
).matchSnapshot()

expect(
compileWithVFor(
`
<tr
v-for="row of rows"
:key="row.id"
:class="{ danger: row.id === selected }"
></tr>
`,
).code,
).matchSnapshot()
})

test('multi effect', () => {
const { code } = compileWithVFor(
`<div v-for="(item, index) of items" :item="item" :index="index" />`,
Expand Down
9 changes: 4 additions & 5 deletions packages/compiler-vapor/src/generators/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@ export function genBlock(
context: CodegenContext,
args: CodeFragment[] = [],
root?: boolean,
customReturns?: (returns: CodeFragment[]) => CodeFragment[],
): CodeFragment[] {
return [
'(',
...args,
') => {',
INDENT_START,
...genBlockContent(oper, context, root, customReturns),
...genBlockContent(oper, context, root),
INDENT_END,
NEWLINE,
'}',
Expand All @@ -37,7 +36,7 @@ export function genBlockContent(
block: BlockIRNode,
context: CodegenContext,
root?: boolean,
customReturns?: (returns: CodeFragment[]) => CodeFragment[],
genEffectsExtraFrag?: () => CodeFragment[],
): CodeFragment[] {
const [frag, push] = buildCodeFragment()
const { dynamic, effect, operation, returns } = block
Expand All @@ -56,7 +55,7 @@ export function genBlockContent(
}

push(...genOperations(operation, context))
push(...genEffects(effect, context))
push(...genEffects(effect, context, genEffectsExtraFrag))

push(NEWLINE, `return `)

Expand All @@ -65,7 +64,7 @@ export function genBlockContent(
returnNodes.length > 1
? genMulti(DELIMITERS_ARRAY, ...returnNodes)
: [returnNodes[0] || 'null']
push(...(customReturns ? customReturns(returnsCode) : returnsCode))
push(...returnsCode)

resetBlock()
return frag
Expand Down
24 changes: 20 additions & 4 deletions packages/compiler-vapor/src/generators/expression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ function canPrefix(name: string) {
type DeclarationResult = {
ids: Record<string, string>
frag: CodeFragment[]
varNames: string[]
}
type DeclarationValue = {
name: string
Expand All @@ -243,6 +244,7 @@ type DeclarationValue = {
export function processExpressions(
context: CodegenContext,
expressions: SimpleExpressionNode[],
shouldDeclareConst: boolean,
): DeclarationResult {
// analyze variables
const { seenVariable, variableToExpMap, expToVariableMap, seenIdentifier } =
Expand All @@ -266,7 +268,11 @@ export function processExpressions(
varDeclarations,
)

return genDeclarations([...varDeclarations, ...expDeclarations], context)
return genDeclarations(
[...varDeclarations, ...expDeclarations],
context,
shouldDeclareConst,
)
}

function analyzeExpressions(expressions: SimpleExpressionNode[]) {
Expand Down Expand Up @@ -507,31 +513,41 @@ function processRepeatedExpressions(
function genDeclarations(
declarations: DeclarationValue[],
context: CodegenContext,
shouldDeclareConst: boolean,
): DeclarationResult {
const [frag, push] = buildCodeFragment()
const ids: Record<string, string> = Object.create(null)
const varNames = new Set<string>()

// process identifiers first as expressions may rely on them
declarations.forEach(({ name, isIdentifier, value }) => {
if (isIdentifier) {
const varName = (ids[name] = `_${name}`)
push(`const ${varName} = `, ...genExpression(value, context), NEWLINE)
varNames.add(varName)
if (shouldDeclareConst) {
push(`const `)
}
push(`${varName} = `, ...genExpression(value, context), NEWLINE)
}
})

// process expressions
declarations.forEach(({ name, isIdentifier, value }) => {
if (!isIdentifier) {
const varName = (ids[name] = `_${name}`)
varNames.add(varName)
if (shouldDeclareConst) {
push(`const `)
}
push(
`const ${varName} = `,
`${varName} = `,
...context.withId(() => genExpression(value, context), ids),
NEWLINE,
)
}
})

return { ids, frag }
return { ids, frag, varNames: [...varNames] }
}

function escapeRegExp(string: string) {
Expand Down
Loading