Optimizer Rules
The Optimizer can break up large applications into lots of small lazy-loadable chunks. In addition, the Optimizer can lazy-load function closure, which lexically captures variables. However, there are limits to what can be achieved, and therefore the Optimizer comes with a set of rules. Not all valid Javascript is valid Optimizer code. This section describes the rules that developer needs to follow for successful Optimizer transformation.
The $
is not only a marker for the Optimizer but also a marker for the developer to follow these rules.
NOTE: There are plans for a linter that will be able to enforce these rules eagerly.
Imports
RULE: If a function that is being extracted by Optimizer refers to a top-level symbol, that symbol must either be imported or exported.
import { importedFn } from '...';
export exportedFn = () => {...};
const salutation = "Hello";
someApi$(() => {
importedFn(); // OK
exportedFn(); // OK
salutation; // Error: salutation not imported/exported
})
The reason for the above rule becomes obvious when the output is examined.
import { importedFn } from '...';
export exportedFn = () => { ... };
const salutation = "Hello";
someApi(qrl('./chunk-a.js', 'someApi_1'));
chunk-a.js
:
import { importedFn } from '...';
import { exportedFn } from './originalFile';
export const someApi_1 = () => {
importedFn(); // OK
exportedFn(); // OK
salutation; // Error: no way to get reference to this.
};
Closures
RULE: If a function lexically captures a variable (or parameter), that variable must be (1) a const
and (2) the value must be serializable.
function somefn() {
let count = 0;
list.foreach((item) => {
count++;
const currentCount = count;
someApi$(() => {
item; // OK (assuming serializable)
count; // ERROR: count not const
currentCount; // OK (assuming serializable)
});
});
}
Again looking at the generated code reveals why these rules must be so:
function somefn() {
let count = 0;
list.foreach((item) => {
count++;
const currentCount = count;
someApi$(qrl('./chunk-a.js', '_1', [
item,
count,
currentCount,
]));
});
}
chunk-a.js
:
export _1 = () => {
const [item, count, currentCount] = useLexicalScope();
item; // OK (assuming serializable)
count; // ERROR: count not const
currentCount; // OK (assuming serializable)
};
See serialization for discussion of what is serializable.