Capturing the lexical scope
The Optimizer extracts expressions (usually functions) into new files and leaves behind a QRL
pointing to the lazy-loaded location.
Let's look at a simple case:
const Greeter = component$(() => {
return (
<span>Hello World!</span>
);
});
this will result in:
const Greeter = component(qrl('./chunk-a.js', 'Greeter_onMount'));
chunk-a.js
:
const Greeter_onMount = () => {
return qrl('./chunk-b.js', 'Greeter_onRender');
};
chunk-b.js
:
const Greeter_onRender = () => <span>Hello World!</span>;
The above is for simple cases where the extracted function closure does not capture any variables. Let's look at a more complicated case where the extracted function closure lexically captures variables.
const Greeter = component$((props: { name: string }) => {
const salutation = 'Hello';
return (
<span>{salutation} {props.name}!</span>
);
})
The naive way to extract functions will not work.
const Greeter = component(qrl('./chunk-a.js', 'Greeter_onMount'));
chunk-a.js
:
const Greeter_onMount = (props) => {
const salutation = 'Hello';
return qrl('./chunk-b.js', 'Greeter_onRender');
};
chunk-b.js
:
const Greeter_onRender = () => (
<span>
{salutation} {props.name}!
</span>
);
The issue can be seen in chunk-b.js
. The extracted function refers to salutation
and props
, which are no longer in the lexical scope of the function. For this reason, the generated code must be slightly different.
chunk-a.js
:
const Greeter_onMount = (props) => {
const salutation = 'Hello';
return qrl('./chunk-b.js', 'Greeter_onRender', [salutation, props]);
};
chunk-b.js
:
const Greeter_onRender = () => {
const [salutation, props] = useLexicalScope();
return (
<span>
{salutation} {props.name}!
</span>
);
};
Notice two changes:
- The
QRL
inGreeter_onMount
now stores thesalutation
andprops
. This performs the role of capturing the constants inside closures. - The generated closure
Greeter_onRender
now has a preamble which restores thesalutation
andprops
(const [salutation, props] = useLexicalScope()
.)
The ability for the Optimizer (and Qwik runtime) to capture lexically scoped constants significantly improves which functions can be extracted into lazy-loaded resources. It is a powerful tool for breaking up complex applications into smaller lazy-loadable chunks.