mirror of
https://github.com/hanzoai/react.git
synced 2026-09-24 17:02:27 +00:00
JSX Outlining (#30956)
Currently, the react compiler can not compile within callbacks which can
potentially cause over rendering. Consider this example:
```jsx
function Component(countries, onDelete) {
const name = useFoo();
return countries.map(() => {
return (
<Foo>
<Bar name={name}/>
<Baz onclick={onDelete} />
</Foo>
);
});
}
```
In this case, there's no memoization of the nested jsx elements. But
instead if we were to manually refactor the nested jsx into separate
component like this:
```jsx
function Component(countries, onDelete) {
const name = useFoo();
return countries.map(() => {
return <Temp name={name} onDelete={onDelete} />;
});
}
function Temp({ name, onDelete }) {
return (
<Foo>
<Bar name={name} />
<Baz onclick={onDelete} />
</Foo>
);
}
```
The compiler can now optimise both these components:
```jsx
function Component(countries, onDelete) {
const $ = _c(4);
const name = useFoo();
let t0;
if ($[0] !== name || $[1] !== onDelete || $[2] !== countries) {
t0 = countries.map(() => <Temp name={name} onDelete={onDelete} />);
$[0] = name;
$[1] = onDelete;
$[2] = countries;
$[3] = t0;
} else {
t0 = $[3];
}
return t0;
}
function Temp(t0) {
const $ = _c(7);
const { name, onDelete } = t0;
let t1;
if ($[0] !== name) {
t1 = <Bar name={name} />;
$[0] = name;
$[1] = t1;
} else {
t1 = $[1];
}
let t2;
if ($[2] !== onDelete) {
t2 = <Baz onclick={onDelete} />;
$[2] = onDelete;
$[3] = t2;
} else {
t2 = $[3];
}
let t3;
if ($[4] !== t1 || $[5] !== t2) {
t3 = (
<Foo>
{t1}
{t2}
</Foo>
);
$[4] = t1;
$[5] = t2;
$[6] = t3;
} else {
t3 = $[6];
}
return t3;
}
```
Now, when `countries` is updated by adding one single value, only the
newly added value is re-rendered and not the entire list. Rather than
having to do this manually, this PR teaches the react compiler to do
this transformation.
This PR adds a new pass (`OutlineJsx`) to capture nested jsx statements
and outline them in a separate component. This newly outlined component
can then by memoized by the compiler, giving us more fine grained
rendering.
This commit is contained in:
committed by
GitHub
parent
93077b5c6f
commit
97a5049c44
@@ -103,6 +103,7 @@ import {lowerContextAccess} from '../Optimization/LowerContextAccess';
|
||||
import {validateNoSetStateInPassiveEffects} from '../Validation/ValidateNoSetStateInPassiveEffects';
|
||||
import {validateNoJSXInTryStatement} from '../Validation/ValidateNoJSXInTryStatement';
|
||||
import {propagateScopeDependenciesHIR} from '../HIR/PropagateScopeDependenciesHIR';
|
||||
import {outlineJSX} from '../Optimization/OutlineJsx';
|
||||
|
||||
export type CompilerPipelineValue =
|
||||
| {kind: 'ast'; name: string; value: CodegenFunction}
|
||||
@@ -278,6 +279,10 @@ function* runWithEnvironment(
|
||||
value: hir,
|
||||
});
|
||||
|
||||
if (env.config.enableJsxOutlining) {
|
||||
outlineJSX(hir);
|
||||
}
|
||||
|
||||
if (env.config.enableFunctionOutlining) {
|
||||
outlineFunctions(hir, fbtOperands);
|
||||
yield log({kind: 'hir', name: 'OutlineFunctions', value: hir});
|
||||
|
||||
@@ -199,7 +199,7 @@ function insertNewOutlinedFunctionNode(
|
||||
program: NodePath<t.Program>,
|
||||
originalFn: BabelFn,
|
||||
compiledFn: CodegenFunction,
|
||||
): NodePath<t.Function> {
|
||||
): BabelFn {
|
||||
switch (originalFn.type) {
|
||||
case 'FunctionDeclaration': {
|
||||
return originalFn.insertAfter(
|
||||
@@ -491,18 +491,11 @@ export function compileProgram(
|
||||
fn.skip();
|
||||
ALREADY_COMPILED.add(fn.node);
|
||||
if (outlined.type !== null) {
|
||||
CompilerError.throwTodo({
|
||||
reason: `Implement support for outlining React functions (components/hooks)`,
|
||||
loc: outlined.fn.loc,
|
||||
queue.push({
|
||||
kind: 'outlined',
|
||||
fn,
|
||||
fnType: outlined.type,
|
||||
});
|
||||
/*
|
||||
* Above should be as simple as the following, but needs testing:
|
||||
* queue.push({
|
||||
* kind: "outlined",
|
||||
* fn,
|
||||
* fnType: outlined.type,
|
||||
* });
|
||||
*/
|
||||
}
|
||||
}
|
||||
compiledFns.push({
|
||||
|
||||
@@ -354,6 +354,54 @@ const EnvironmentConfigSchema = z.object({
|
||||
*/
|
||||
enableFunctionOutlining: z.boolean().default(true),
|
||||
|
||||
/**
|
||||
* If enabled, this will outline nested JSX into a separate component.
|
||||
*
|
||||
* This will enable the compiler to memoize the separate component, giving us
|
||||
* the same behavior as compiling _within_ the callback.
|
||||
*
|
||||
* ```
|
||||
* function Component(countries, onDelete) {
|
||||
* const name = useFoo();
|
||||
* return countries.map(() => {
|
||||
* return (
|
||||
* <Foo>
|
||||
* <Bar>{name}</Bar>
|
||||
* <Button onclick={onDelete}>delete</Button>
|
||||
* </Foo>
|
||||
* );
|
||||
* });
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* will be transpiled to:
|
||||
*
|
||||
* ```
|
||||
* function Component(countries, onDelete) {
|
||||
* const name = useFoo();
|
||||
* return countries.map(() => {
|
||||
* return (
|
||||
* <Temp name={name} onDelete={onDelete} />
|
||||
* );
|
||||
* });
|
||||
* }
|
||||
*
|
||||
* function Temp({name, onDelete}) {
|
||||
* return (
|
||||
* <Foo>
|
||||
* <Bar>{name}</Bar>
|
||||
* <Button onclick={onDelete}>delete</Button>
|
||||
* </Foo>
|
||||
* );
|
||||
* }
|
||||
*
|
||||
* Both, `Component` and `Temp` will then be memoized by the compiler.
|
||||
*
|
||||
* With this change, when `countries` is updated by adding one single value,
|
||||
* only the newly added value is re-rendered and not the entire list.
|
||||
*/
|
||||
enableJsxOutlining: z.boolean().default(false),
|
||||
|
||||
/*
|
||||
* Enables instrumentation codegen. This emits a dev-mode only call to an
|
||||
* instrumentation function, for components and hooks that Forget compiles.
|
||||
|
||||
@@ -920,15 +920,7 @@ export type InstructionValue =
|
||||
type: Type;
|
||||
loc: SourceLocation;
|
||||
}
|
||||
| {
|
||||
kind: 'JsxExpression';
|
||||
tag: Place | BuiltinTag;
|
||||
props: Array<JsxAttribute>;
|
||||
children: Array<Place> | null; // null === no children
|
||||
loc: SourceLocation;
|
||||
openingLoc: SourceLocation;
|
||||
closingLoc: SourceLocation;
|
||||
}
|
||||
| JsxExpression
|
||||
| {
|
||||
kind: 'ObjectExpression';
|
||||
properties: Array<ObjectProperty | SpreadPattern>;
|
||||
@@ -1074,6 +1066,16 @@ export type InstructionValue =
|
||||
loc: SourceLocation;
|
||||
};
|
||||
|
||||
export type JsxExpression = {
|
||||
kind: 'JsxExpression';
|
||||
tag: Place | BuiltinTag;
|
||||
props: Array<JsxAttribute>;
|
||||
children: Array<Place> | null; // null === no children
|
||||
loc: SourceLocation;
|
||||
openingLoc: SourceLocation;
|
||||
closingLoc: SourceLocation;
|
||||
};
|
||||
|
||||
export type JsxAttribute =
|
||||
| {kind: 'JsxSpreadAttribute'; argument: Place}
|
||||
| {kind: 'JsxAttribute'; name: string; place: Place};
|
||||
|
||||
@@ -0,0 +1,466 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import invariant from 'invariant';
|
||||
import {Environment} from '../HIR';
|
||||
import {
|
||||
BasicBlock,
|
||||
GeneratedSource,
|
||||
HIRFunction,
|
||||
IdentifierId,
|
||||
Instruction,
|
||||
InstructionId,
|
||||
InstructionKind,
|
||||
JsxAttribute,
|
||||
JsxExpression,
|
||||
LoadGlobal,
|
||||
makeBlockId,
|
||||
makeIdentifierName,
|
||||
makeInstructionId,
|
||||
makeType,
|
||||
ObjectProperty,
|
||||
Place,
|
||||
promoteTemporary,
|
||||
promoteTemporaryJsxTag,
|
||||
} from '../HIR/HIR';
|
||||
import {createTemporaryPlace} from '../HIR/HIRBuilder';
|
||||
import {printIdentifier} from '../HIR/PrintHIR';
|
||||
import {deadCodeElimination} from './DeadCodeElimination';
|
||||
import {assertExhaustive} from '../Utils/utils';
|
||||
|
||||
export function outlineJSX(fn: HIRFunction): void {
|
||||
const outlinedFns: Array<HIRFunction> = [];
|
||||
outlineJsxImpl(fn, outlinedFns);
|
||||
|
||||
for (const outlinedFn of outlinedFns) {
|
||||
fn.env.outlineFunction(outlinedFn, 'Component');
|
||||
}
|
||||
}
|
||||
|
||||
type JsxInstruction = Instruction & {value: JsxExpression};
|
||||
type LoadGlobalInstruction = Instruction & {value: LoadGlobal};
|
||||
type LoadGlobalMap = Map<IdentifierId, LoadGlobalInstruction>;
|
||||
|
||||
type State = {
|
||||
jsx: Array<JsxInstruction>;
|
||||
children: Set<IdentifierId>;
|
||||
};
|
||||
|
||||
function outlineJsxImpl(
|
||||
fn: HIRFunction,
|
||||
outlinedFns: Array<HIRFunction>,
|
||||
): void {
|
||||
const globals: LoadGlobalMap = new Map();
|
||||
|
||||
function processAndOutlineJSX(
|
||||
state: State,
|
||||
rewriteInstr: Map<InstructionId, Array<Instruction>>,
|
||||
): void {
|
||||
if (state.jsx.length <= 1) {
|
||||
return;
|
||||
}
|
||||
const result = process(
|
||||
fn,
|
||||
[...state.jsx].sort((a, b) => a.id - b.id),
|
||||
globals,
|
||||
);
|
||||
if (result) {
|
||||
outlinedFns.push(result.fn);
|
||||
rewriteInstr.set(state.jsx.at(0)!.id, result.instrs);
|
||||
}
|
||||
}
|
||||
|
||||
for (const [, block] of fn.body.blocks) {
|
||||
const rewriteInstr = new Map();
|
||||
let state: State = {
|
||||
jsx: [],
|
||||
children: new Set(),
|
||||
};
|
||||
|
||||
for (let i = block.instructions.length - 1; i >= 0; i--) {
|
||||
const instr = block.instructions[i];
|
||||
const {value, lvalue} = instr;
|
||||
switch (value.kind) {
|
||||
case 'LoadGlobal': {
|
||||
globals.set(lvalue.identifier.id, instr as LoadGlobalInstruction);
|
||||
break;
|
||||
}
|
||||
case 'FunctionExpression': {
|
||||
outlineJsxImpl(value.loweredFunc.func, outlinedFns);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'JsxExpression': {
|
||||
if (!state.children.has(lvalue.identifier.id)) {
|
||||
processAndOutlineJSX(state, rewriteInstr);
|
||||
|
||||
state = {
|
||||
jsx: [],
|
||||
children: new Set(),
|
||||
};
|
||||
}
|
||||
state.jsx.push(instr as JsxInstruction);
|
||||
if (value.children) {
|
||||
for (const child of value.children) {
|
||||
state.children.add(child.identifier.id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'ArrayExpression':
|
||||
case 'Await':
|
||||
case 'BinaryExpression':
|
||||
case 'CallExpression':
|
||||
case 'ComputedDelete':
|
||||
case 'ComputedLoad':
|
||||
case 'ComputedStore':
|
||||
case 'Debugger':
|
||||
case 'DeclareContext':
|
||||
case 'DeclareLocal':
|
||||
case 'Destructure':
|
||||
case 'FinishMemoize':
|
||||
case 'GetIterator':
|
||||
case 'IteratorNext':
|
||||
case 'JSXText':
|
||||
case 'JsxFragment':
|
||||
case 'LoadContext':
|
||||
case 'LoadLocal':
|
||||
case 'MetaProperty':
|
||||
case 'MethodCall':
|
||||
case 'NewExpression':
|
||||
case 'NextPropertyOf':
|
||||
case 'ObjectExpression':
|
||||
case 'ObjectMethod':
|
||||
case 'PostfixUpdate':
|
||||
case 'PrefixUpdate':
|
||||
case 'Primitive':
|
||||
case 'PropertyDelete':
|
||||
case 'PropertyLoad':
|
||||
case 'PropertyStore':
|
||||
case 'RegExpLiteral':
|
||||
case 'StartMemoize':
|
||||
case 'StoreContext':
|
||||
case 'StoreGlobal':
|
||||
case 'StoreLocal':
|
||||
case 'TaggedTemplateExpression':
|
||||
case 'TemplateLiteral':
|
||||
case 'TypeCastExpression':
|
||||
case 'UnsupportedNode':
|
||||
case 'UnaryExpression': {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assertExhaustive(value, `Unexpected instruction: ${value}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
processAndOutlineJSX(state, rewriteInstr);
|
||||
|
||||
if (rewriteInstr.size > 0) {
|
||||
const newInstrs = [];
|
||||
for (let i = 0; i < block.instructions.length; i++) {
|
||||
// InstructionId's are one-indexed, so add one to account for them.
|
||||
const id = i + 1;
|
||||
if (rewriteInstr.has(id)) {
|
||||
const instrs = rewriteInstr.get(id);
|
||||
newInstrs.push(...instrs);
|
||||
} else {
|
||||
newInstrs.push(block.instructions[i]);
|
||||
}
|
||||
}
|
||||
block.instructions = newInstrs;
|
||||
}
|
||||
deadCodeElimination(fn);
|
||||
}
|
||||
}
|
||||
|
||||
type OutlinedResult = {
|
||||
instrs: Array<Instruction>;
|
||||
fn: HIRFunction;
|
||||
};
|
||||
|
||||
function process(
|
||||
fn: HIRFunction,
|
||||
jsx: Array<JsxInstruction>,
|
||||
globals: LoadGlobalMap,
|
||||
): OutlinedResult | null {
|
||||
/**
|
||||
* In the future, add a check for backedge to outline jsx inside loops in a
|
||||
* top level component. For now, only outline jsx in callbacks.
|
||||
*/
|
||||
if (fn.fnType === 'Component') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const props = collectProps(jsx);
|
||||
if (!props) return null;
|
||||
|
||||
const outlinedTag = fn.env.generateGloballyUniqueIdentifierName(null).value;
|
||||
const newInstrs = emitOutlinedJsx(fn.env, jsx, props, outlinedTag);
|
||||
if (!newInstrs) return null;
|
||||
|
||||
const outlinedFn = emitOutlinedFn(fn.env, jsx, props, globals);
|
||||
if (!outlinedFn) return null;
|
||||
outlinedFn.id = outlinedTag;
|
||||
|
||||
return {instrs: newInstrs, fn: outlinedFn};
|
||||
}
|
||||
|
||||
function collectProps(
|
||||
instructions: Array<JsxInstruction>,
|
||||
): Array<JsxAttribute> | null {
|
||||
const attributes: Array<JsxAttribute> = [];
|
||||
const jsxIds = new Set(instructions.map(i => i.lvalue.identifier.id));
|
||||
const seen: Set<string> = new Set();
|
||||
for (const instr of instructions) {
|
||||
const {value} = instr;
|
||||
|
||||
for (const at of value.props) {
|
||||
if (at.kind === 'JsxSpreadAttribute') {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(gsn): Handle attributes that have same value across
|
||||
* the outlined jsx instructions.
|
||||
*/
|
||||
if (seen.has(at.name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (at.kind === 'JsxAttribute') {
|
||||
seen.add(at.name);
|
||||
attributes.push(at);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(gsn): Add support for children that are not jsx expressions
|
||||
if (
|
||||
value.children &&
|
||||
value.children.some(child => !jsxIds.has(child.identifier.id))
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
function emitOutlinedJsx(
|
||||
env: Environment,
|
||||
instructions: Array<Instruction>,
|
||||
props: Array<JsxAttribute>,
|
||||
outlinedTag: string,
|
||||
): Array<Instruction> {
|
||||
const loadJsx: Instruction = {
|
||||
id: makeInstructionId(0),
|
||||
loc: GeneratedSource,
|
||||
lvalue: createTemporaryPlace(env, GeneratedSource),
|
||||
value: {
|
||||
kind: 'LoadGlobal',
|
||||
binding: {
|
||||
kind: 'ModuleLocal',
|
||||
name: outlinedTag,
|
||||
},
|
||||
loc: GeneratedSource,
|
||||
},
|
||||
};
|
||||
promoteTemporaryJsxTag(loadJsx.lvalue.identifier);
|
||||
const jsxExpr: Instruction = {
|
||||
id: makeInstructionId(0),
|
||||
loc: GeneratedSource,
|
||||
lvalue: instructions.at(-1)!.lvalue,
|
||||
value: {
|
||||
kind: 'JsxExpression',
|
||||
tag: {...loadJsx.lvalue},
|
||||
props,
|
||||
children: null,
|
||||
loc: GeneratedSource,
|
||||
openingLoc: GeneratedSource,
|
||||
closingLoc: GeneratedSource,
|
||||
},
|
||||
};
|
||||
|
||||
return [loadJsx, jsxExpr];
|
||||
}
|
||||
|
||||
function emitOutlinedFn(
|
||||
env: Environment,
|
||||
jsx: Array<JsxInstruction>,
|
||||
oldProps: Array<JsxAttribute>,
|
||||
globals: LoadGlobalMap,
|
||||
): HIRFunction | null {
|
||||
const instructions: Array<Instruction> = [];
|
||||
const oldToNewProps = createOldToNewPropsMapping(env, oldProps);
|
||||
|
||||
const propsObj: Place = createTemporaryPlace(env, GeneratedSource);
|
||||
promoteTemporary(propsObj.identifier);
|
||||
|
||||
const destructurePropsInstr = emitDestructureProps(env, propsObj, [
|
||||
...oldToNewProps.values(),
|
||||
]);
|
||||
instructions.push(destructurePropsInstr);
|
||||
|
||||
const updatedJsxInstructions = emitUpdatedJsx(jsx, oldToNewProps);
|
||||
const loadGlobalInstrs = emitLoadGlobals(jsx, globals);
|
||||
if (!loadGlobalInstrs) {
|
||||
return null;
|
||||
}
|
||||
instructions.push(...loadGlobalInstrs);
|
||||
instructions.push(...updatedJsxInstructions);
|
||||
|
||||
const block: BasicBlock = {
|
||||
kind: 'block',
|
||||
id: makeBlockId(0),
|
||||
instructions,
|
||||
terminal: {
|
||||
id: makeInstructionId(0),
|
||||
kind: 'return',
|
||||
loc: GeneratedSource,
|
||||
value: instructions.at(-1)!.lvalue,
|
||||
},
|
||||
preds: new Set(),
|
||||
phis: new Set(),
|
||||
};
|
||||
|
||||
const fn: HIRFunction = {
|
||||
loc: GeneratedSource,
|
||||
id: null,
|
||||
fnType: 'Other',
|
||||
env,
|
||||
params: [propsObj],
|
||||
returnTypeAnnotation: null,
|
||||
returnType: makeType(),
|
||||
context: [],
|
||||
effects: null,
|
||||
body: {
|
||||
entry: block.id,
|
||||
blocks: new Map([[block.id, block]]),
|
||||
},
|
||||
generator: false,
|
||||
async: false,
|
||||
directives: [],
|
||||
};
|
||||
return fn;
|
||||
}
|
||||
|
||||
function emitLoadGlobals(
|
||||
jsx: Array<JsxInstruction>,
|
||||
globals: LoadGlobalMap,
|
||||
): Array<Instruction> | null {
|
||||
const instructions: Array<Instruction> = [];
|
||||
for (const {value} of jsx) {
|
||||
// Add load globals instructions for jsx tags
|
||||
if (value.tag.kind === 'Identifier') {
|
||||
const loadGlobalInstr = globals.get(value.tag.identifier.id);
|
||||
if (!loadGlobalInstr) {
|
||||
return null;
|
||||
}
|
||||
instructions.push(loadGlobalInstr);
|
||||
}
|
||||
}
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
function emitUpdatedJsx(
|
||||
jsx: Array<JsxInstruction>,
|
||||
oldToNewProps: Map<IdentifierId, ObjectProperty>,
|
||||
): Array<JsxInstruction> {
|
||||
const newInstrs: Array<JsxInstruction> = [];
|
||||
|
||||
for (const instr of jsx) {
|
||||
const {value} = instr;
|
||||
const newProps: Array<JsxAttribute> = [];
|
||||
// Update old props references to use the newly destructured props param
|
||||
for (const prop of value.props) {
|
||||
invariant(
|
||||
prop.kind === 'JsxAttribute',
|
||||
`Expected only attributes but found ${prop.kind}`,
|
||||
);
|
||||
if (prop.name === 'key') {
|
||||
continue;
|
||||
}
|
||||
const newProp = oldToNewProps.get(prop.place.identifier.id);
|
||||
invariant(
|
||||
newProp !== undefined,
|
||||
`Expected a new property for ${printIdentifier(prop.place.identifier)}`,
|
||||
);
|
||||
newProps.push({
|
||||
...prop,
|
||||
place: newProp.place,
|
||||
});
|
||||
}
|
||||
|
||||
newInstrs.push({
|
||||
...instr,
|
||||
value: {
|
||||
...value,
|
||||
props: newProps,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return newInstrs;
|
||||
}
|
||||
|
||||
function createOldToNewPropsMapping(
|
||||
env: Environment,
|
||||
oldProps: Array<JsxAttribute>,
|
||||
): Map<IdentifierId, ObjectProperty> {
|
||||
const oldToNewProps = new Map();
|
||||
|
||||
for (const oldProp of oldProps) {
|
||||
invariant(
|
||||
oldProp.kind === 'JsxAttribute',
|
||||
`Expected only attributes but found ${oldProp.kind}`,
|
||||
);
|
||||
|
||||
// Do not read key prop in the outlined component
|
||||
if (oldProp.name === 'key') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newProp: ObjectProperty = {
|
||||
kind: 'ObjectProperty',
|
||||
key: {
|
||||
kind: 'string',
|
||||
name: oldProp.name,
|
||||
},
|
||||
type: 'property',
|
||||
place: createTemporaryPlace(env, GeneratedSource),
|
||||
};
|
||||
newProp.place.identifier.name = makeIdentifierName(oldProp.name);
|
||||
oldToNewProps.set(oldProp.place.identifier.id, newProp);
|
||||
}
|
||||
|
||||
return oldToNewProps;
|
||||
}
|
||||
|
||||
function emitDestructureProps(
|
||||
env: Environment,
|
||||
propsObj: Place,
|
||||
properties: Array<ObjectProperty>,
|
||||
): Instruction {
|
||||
const destructurePropsInstr: Instruction = {
|
||||
id: makeInstructionId(0),
|
||||
lvalue: createTemporaryPlace(env, GeneratedSource),
|
||||
loc: GeneratedSource,
|
||||
value: {
|
||||
kind: 'Destructure',
|
||||
lvalue: {
|
||||
pattern: {
|
||||
kind: 'ObjectPattern',
|
||||
properties,
|
||||
},
|
||||
kind: InstructionKind.Let,
|
||||
},
|
||||
loc: GeneratedSource,
|
||||
value: propsObj,
|
||||
},
|
||||
};
|
||||
return destructurePropsInstr;
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableJsxOutlining
|
||||
function Component(arr) {
|
||||
const x = useX();
|
||||
return arr.map(i => {
|
||||
<>
|
||||
{arr.map((i, id) => {
|
||||
let child = (
|
||||
<Bar x={x}>
|
||||
<Baz i={i}></Baz>
|
||||
</Bar>
|
||||
);
|
||||
|
||||
let jsx = <div>{child}</div>;
|
||||
return jsx;
|
||||
})}
|
||||
</>;
|
||||
});
|
||||
}
|
||||
|
||||
function Bar({x, children}) {
|
||||
return (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Baz({i}) {
|
||||
return <>{i}</>;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return 'x';
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{arr: ['foo', 'bar']}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining
|
||||
function Component(arr) {
|
||||
const $ = _c(3);
|
||||
const x = useX();
|
||||
let t0;
|
||||
if ($[0] !== arr || $[1] !== x) {
|
||||
t0 = arr.map((i) => {
|
||||
arr.map((i_0, id) => {
|
||||
const T0 = _temp;
|
||||
const child = <T0 i={i_0} x={x} />;
|
||||
|
||||
const jsx = <div>{child}</div>;
|
||||
return jsx;
|
||||
});
|
||||
});
|
||||
$[0] = arr;
|
||||
$[1] = x;
|
||||
$[2] = t0;
|
||||
} else {
|
||||
t0 = $[2];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
function _temp(t0) {
|
||||
const $ = _c(5);
|
||||
const { i: i, x: x } = t0;
|
||||
let t1;
|
||||
if ($[0] !== i) {
|
||||
t1 = <Baz i={i} />;
|
||||
$[0] = i;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
let t2;
|
||||
if ($[2] !== x || $[3] !== t1) {
|
||||
t2 = <Bar x={x}>{t1}</Bar>;
|
||||
$[2] = x;
|
||||
$[3] = t1;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
function Bar(t0) {
|
||||
const $ = _c(3);
|
||||
const { x, children } = t0;
|
||||
let t1;
|
||||
if ($[0] !== x || $[1] !== children) {
|
||||
t1 = (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
$[0] = x;
|
||||
$[1] = children;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
function Baz(t0) {
|
||||
const $ = _c(2);
|
||||
const { i } = t0;
|
||||
let t1;
|
||||
if ($[0] !== i) {
|
||||
t1 = <>{i}</>;
|
||||
$[0] = i;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return "x";
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ arr: ["foo", "bar"] }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: exception) arr.map is not a function
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// @enableJsxOutlining
|
||||
function Component(arr) {
|
||||
const x = useX();
|
||||
return arr.map(i => {
|
||||
<>
|
||||
{arr.map((i, id) => {
|
||||
let child = (
|
||||
<Bar x={x}>
|
||||
<Baz i={i}></Baz>
|
||||
</Bar>
|
||||
);
|
||||
|
||||
let jsx = <div>{child}</div>;
|
||||
return jsx;
|
||||
})}
|
||||
</>;
|
||||
});
|
||||
}
|
||||
|
||||
function Bar({x, children}) {
|
||||
return (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Baz({i}) {
|
||||
return <>{i}</>;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return 'x';
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{arr: ['foo', 'bar']}],
|
||||
};
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableJsxOutlining
|
||||
function Component({arr}) {
|
||||
const x = useX();
|
||||
return (
|
||||
<>
|
||||
{arr.map((i, id) => {
|
||||
let jsx = (
|
||||
<Bar key={id} x={x}>
|
||||
<Baz i={i}></Baz>
|
||||
</Bar>
|
||||
);
|
||||
return jsx;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Bar({x, children}) {
|
||||
return (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Baz({i}) {
|
||||
return i;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return 'x';
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{arr: ['foo', 'bar']}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining
|
||||
function Component(t0) {
|
||||
const $ = _c(7);
|
||||
const { arr } = t0;
|
||||
const x = useX();
|
||||
let t1;
|
||||
if ($[0] !== x || $[1] !== arr) {
|
||||
let t2;
|
||||
if ($[3] !== x) {
|
||||
t2 = (i, id) => {
|
||||
const T0 = _temp;
|
||||
const jsx = <T0 i={i} key={id} x={x} />;
|
||||
return jsx;
|
||||
};
|
||||
$[3] = x;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
t1 = arr.map(t2);
|
||||
$[0] = x;
|
||||
$[1] = arr;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
let t2;
|
||||
if ($[5] !== t1) {
|
||||
t2 = <>{t1}</>;
|
||||
$[5] = t1;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
function _temp(t0) {
|
||||
const $ = _c(5);
|
||||
const { i: i, x: x } = t0;
|
||||
let t1;
|
||||
if ($[0] !== i) {
|
||||
t1 = <Baz i={i} />;
|
||||
$[0] = i;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
let t2;
|
||||
if ($[2] !== x || $[3] !== t1) {
|
||||
t2 = <Bar x={x}>{t1}</Bar>;
|
||||
$[2] = x;
|
||||
$[3] = t1;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
function Bar(t0) {
|
||||
const $ = _c(3);
|
||||
const { x, children } = t0;
|
||||
let t1;
|
||||
if ($[0] !== x || $[1] !== children) {
|
||||
t1 = (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
$[0] = x;
|
||||
$[1] = children;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
function Baz(t0) {
|
||||
const { i } = t0;
|
||||
return i;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return "x";
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ arr: ["foo", "bar"] }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) xfooxbar
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
// @enableJsxOutlining
|
||||
function Component({arr}) {
|
||||
const x = useX();
|
||||
return (
|
||||
<>
|
||||
{arr.map((i, id) => {
|
||||
let jsx = (
|
||||
<Bar key={id} x={x}>
|
||||
<Baz i={i}></Baz>
|
||||
</Bar>
|
||||
);
|
||||
return jsx;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Bar({x, children}) {
|
||||
return (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Baz({i}) {
|
||||
return i;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return 'x';
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{arr: ['foo', 'bar']}],
|
||||
};
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableJsxOutlining
|
||||
function Component({arr}) {
|
||||
const x = useX();
|
||||
return (
|
||||
<>
|
||||
{arr.map((i, id) => {
|
||||
return (
|
||||
<Bar key={id} x={x}>
|
||||
<Baz i={i}></Baz>
|
||||
<Joe j={i}></Joe>
|
||||
<Foo k={i}></Foo>
|
||||
</Bar>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
function Bar({x, children}) {
|
||||
return (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Baz({i}) {
|
||||
return i;
|
||||
}
|
||||
|
||||
function Joe({j}) {
|
||||
return j;
|
||||
}
|
||||
|
||||
function Foo({k}) {
|
||||
return k;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return 'x';
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{arr: ['foo', 'bar']}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining
|
||||
function Component(t0) {
|
||||
const $ = _c(7);
|
||||
const { arr } = t0;
|
||||
const x = useX();
|
||||
let t1;
|
||||
if ($[0] !== x || $[1] !== arr) {
|
||||
let t2;
|
||||
if ($[3] !== x) {
|
||||
t2 = (i, id) => {
|
||||
const T0 = _temp;
|
||||
return <T0 i={i} j={i} k={i} key={id} x={x} />;
|
||||
};
|
||||
$[3] = x;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
t1 = arr.map(t2);
|
||||
$[0] = x;
|
||||
$[1] = arr;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
let t2;
|
||||
if ($[5] !== t1) {
|
||||
t2 = <>{t1}</>;
|
||||
$[5] = t1;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
function _temp(t0) {
|
||||
const $ = _c(11);
|
||||
const { i: i, j: j, k: k, x: x } = t0;
|
||||
let t1;
|
||||
if ($[0] !== i) {
|
||||
t1 = <Baz i={i} />;
|
||||
$[0] = i;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
let t2;
|
||||
if ($[2] !== j) {
|
||||
t2 = <Joe j={j} />;
|
||||
$[2] = j;
|
||||
$[3] = t2;
|
||||
} else {
|
||||
t2 = $[3];
|
||||
}
|
||||
let t3;
|
||||
if ($[4] !== k) {
|
||||
t3 = <Foo k={k} />;
|
||||
$[4] = k;
|
||||
$[5] = t3;
|
||||
} else {
|
||||
t3 = $[5];
|
||||
}
|
||||
let t4;
|
||||
if ($[6] !== x || $[7] !== t1 || $[8] !== t2 || $[9] !== t3) {
|
||||
t4 = (
|
||||
<Bar x={x}>
|
||||
{t1}
|
||||
{t2}
|
||||
{t3}
|
||||
</Bar>
|
||||
);
|
||||
$[6] = x;
|
||||
$[7] = t1;
|
||||
$[8] = t2;
|
||||
$[9] = t3;
|
||||
$[10] = t4;
|
||||
} else {
|
||||
t4 = $[10];
|
||||
}
|
||||
return t4;
|
||||
}
|
||||
|
||||
function Bar(t0) {
|
||||
const $ = _c(3);
|
||||
const { x, children } = t0;
|
||||
let t1;
|
||||
if ($[0] !== x || $[1] !== children) {
|
||||
t1 = (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
$[0] = x;
|
||||
$[1] = children;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
function Baz(t0) {
|
||||
const { i } = t0;
|
||||
return i;
|
||||
}
|
||||
|
||||
function Joe(t0) {
|
||||
const { j } = t0;
|
||||
return j;
|
||||
}
|
||||
|
||||
function Foo(t0) {
|
||||
const { k } = t0;
|
||||
return k;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return "x";
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ arr: ["foo", "bar"] }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) xfoofoofooxbarbarbar
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// @enableJsxOutlining
|
||||
function Component({arr}) {
|
||||
const x = useX();
|
||||
return (
|
||||
<>
|
||||
{arr.map((i, id) => {
|
||||
return (
|
||||
<Bar key={id} x={x}>
|
||||
<Baz i={i}></Baz>
|
||||
<Joe j={i}></Joe>
|
||||
<Foo k={i}></Foo>
|
||||
</Bar>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
function Bar({x, children}) {
|
||||
return (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Baz({i}) {
|
||||
return i;
|
||||
}
|
||||
|
||||
function Joe({j}) {
|
||||
return j;
|
||||
}
|
||||
|
||||
function Foo({k}) {
|
||||
return k;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return 'x';
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{arr: ['foo', 'bar']}],
|
||||
};
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableJsxOutlining
|
||||
function Component({arr}) {
|
||||
const x = useX();
|
||||
return (
|
||||
<>
|
||||
{arr.map((i, id) => {
|
||||
return (
|
||||
<Bar key={id} x={x}>
|
||||
<Baz i={i}></Baz>
|
||||
</Bar>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
function Bar({x, children}) {
|
||||
return (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Baz({i}) {
|
||||
return i;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return 'x';
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{arr: ['foo', 'bar']}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining
|
||||
function Component(t0) {
|
||||
const $ = _c(7);
|
||||
const { arr } = t0;
|
||||
const x = useX();
|
||||
let t1;
|
||||
if ($[0] !== x || $[1] !== arr) {
|
||||
let t2;
|
||||
if ($[3] !== x) {
|
||||
t2 = (i, id) => {
|
||||
const T0 = _temp;
|
||||
return <T0 i={i} key={id} x={x} />;
|
||||
};
|
||||
$[3] = x;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
t1 = arr.map(t2);
|
||||
$[0] = x;
|
||||
$[1] = arr;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
let t2;
|
||||
if ($[5] !== t1) {
|
||||
t2 = <>{t1}</>;
|
||||
$[5] = t1;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
function _temp(t0) {
|
||||
const $ = _c(5);
|
||||
const { i: i, x: x } = t0;
|
||||
let t1;
|
||||
if ($[0] !== i) {
|
||||
t1 = <Baz i={i} />;
|
||||
$[0] = i;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
let t2;
|
||||
if ($[2] !== x || $[3] !== t1) {
|
||||
t2 = <Bar x={x}>{t1}</Bar>;
|
||||
$[2] = x;
|
||||
$[3] = t1;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
function Bar(t0) {
|
||||
const $ = _c(3);
|
||||
const { x, children } = t0;
|
||||
let t1;
|
||||
if ($[0] !== x || $[1] !== children) {
|
||||
t1 = (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
$[0] = x;
|
||||
$[1] = children;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
function Baz(t0) {
|
||||
const { i } = t0;
|
||||
return i;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return "x";
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ arr: ["foo", "bar"] }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) xfooxbar
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// @enableJsxOutlining
|
||||
function Component({arr}) {
|
||||
const x = useX();
|
||||
return (
|
||||
<>
|
||||
{arr.map((i, id) => {
|
||||
return (
|
||||
<Bar key={id} x={x}>
|
||||
<Baz i={i}></Baz>
|
||||
</Bar>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
function Bar({x, children}) {
|
||||
return (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Baz({i}) {
|
||||
return i;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return 'x';
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{arr: ['foo', 'bar']}],
|
||||
};
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableJsxOutlining
|
||||
function Component({arr}) {
|
||||
const x = useX();
|
||||
return (
|
||||
<>
|
||||
{arr.map((i, id) => {
|
||||
return (
|
||||
<Bar key={id} x={x}>
|
||||
<Baz i={i}>Test</Baz>
|
||||
</Bar>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
function Bar({x, children}) {
|
||||
return (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Baz({i}) {
|
||||
return i;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return 'x';
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{arr: ['foo', 'bar']}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining
|
||||
function Component(t0) {
|
||||
const $ = _c(7);
|
||||
const { arr } = t0;
|
||||
const x = useX();
|
||||
let t1;
|
||||
if ($[0] !== x || $[1] !== arr) {
|
||||
let t2;
|
||||
if ($[3] !== x) {
|
||||
t2 = (i, id) => (
|
||||
<Bar key={id} x={x}>
|
||||
<Baz i={i}>Test</Baz>
|
||||
</Bar>
|
||||
);
|
||||
$[3] = x;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
t1 = arr.map(t2);
|
||||
$[0] = x;
|
||||
$[1] = arr;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
let t2;
|
||||
if ($[5] !== t1) {
|
||||
t2 = <>{t1}</>;
|
||||
$[5] = t1;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
function Bar(t0) {
|
||||
const $ = _c(3);
|
||||
const { x, children } = t0;
|
||||
let t1;
|
||||
if ($[0] !== x || $[1] !== children) {
|
||||
t1 = (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
$[0] = x;
|
||||
$[1] = children;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
function Baz(t0) {
|
||||
const { i } = t0;
|
||||
return i;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return "x";
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ arr: ["foo", "bar"] }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) xfooxbar
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// @enableJsxOutlining
|
||||
function Component({arr}) {
|
||||
const x = useX();
|
||||
return (
|
||||
<>
|
||||
{arr.map((i, id) => {
|
||||
return (
|
||||
<Bar key={id} x={x}>
|
||||
<Baz i={i}>Test</Baz>
|
||||
</Bar>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
function Bar({x, children}) {
|
||||
return (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Baz({i}) {
|
||||
return i;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return 'x';
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{arr: ['foo', 'bar']}],
|
||||
};
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @enableJsxOutlining
|
||||
function Component({arr}) {
|
||||
const x = useX();
|
||||
return (
|
||||
<>
|
||||
{arr.map((i, id) => {
|
||||
return (
|
||||
<Bar key={id} x={x}>
|
||||
<Baz i={i}></Baz>
|
||||
<Foo i={i}></Foo>
|
||||
</Bar>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
function Bar({x, children}) {
|
||||
return (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Baz({i}) {
|
||||
return i;
|
||||
}
|
||||
|
||||
function Foo({k}) {
|
||||
return k;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return 'x';
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{arr: ['foo', 'bar']}],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import { c as _c } from "react/compiler-runtime"; // @enableJsxOutlining
|
||||
function Component(t0) {
|
||||
const $ = _c(7);
|
||||
const { arr } = t0;
|
||||
const x = useX();
|
||||
let t1;
|
||||
if ($[0] !== x || $[1] !== arr) {
|
||||
let t2;
|
||||
if ($[3] !== x) {
|
||||
t2 = (i, id) => (
|
||||
<Bar key={id} x={x}>
|
||||
<Baz i={i} />
|
||||
<Foo i={i} />
|
||||
</Bar>
|
||||
);
|
||||
$[3] = x;
|
||||
$[4] = t2;
|
||||
} else {
|
||||
t2 = $[4];
|
||||
}
|
||||
t1 = arr.map(t2);
|
||||
$[0] = x;
|
||||
$[1] = arr;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
let t2;
|
||||
if ($[5] !== t1) {
|
||||
t2 = <>{t1}</>;
|
||||
$[5] = t1;
|
||||
$[6] = t2;
|
||||
} else {
|
||||
t2 = $[6];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
|
||||
function Bar(t0) {
|
||||
const $ = _c(3);
|
||||
const { x, children } = t0;
|
||||
let t1;
|
||||
if ($[0] !== x || $[1] !== children) {
|
||||
t1 = (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
$[0] = x;
|
||||
$[1] = children;
|
||||
$[2] = t1;
|
||||
} else {
|
||||
t1 = $[2];
|
||||
}
|
||||
return t1;
|
||||
}
|
||||
|
||||
function Baz(t0) {
|
||||
const { i } = t0;
|
||||
return i;
|
||||
}
|
||||
|
||||
function Foo(t0) {
|
||||
const { k } = t0;
|
||||
return k;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return "x";
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{ arr: ["foo", "bar"] }],
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Eval output
|
||||
(kind: ok) xfooxbar
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// @enableJsxOutlining
|
||||
function Component({arr}) {
|
||||
const x = useX();
|
||||
return (
|
||||
<>
|
||||
{arr.map((i, id) => {
|
||||
return (
|
||||
<Bar key={id} x={x}>
|
||||
<Baz i={i}></Baz>
|
||||
<Foo i={i}></Foo>
|
||||
</Bar>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
function Bar({x, children}) {
|
||||
return (
|
||||
<>
|
||||
{x}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Baz({i}) {
|
||||
return i;
|
||||
}
|
||||
|
||||
function Foo({k}) {
|
||||
return k;
|
||||
}
|
||||
|
||||
function useX() {
|
||||
return 'x';
|
||||
}
|
||||
|
||||
export const FIXTURE_ENTRYPOINT = {
|
||||
fn: Component,
|
||||
params: [{arr: ['foo', 'bar']}],
|
||||
};
|
||||
Reference in New Issue
Block a user