docs(ivy): add feature principle doc (#21565)

PR Close #21565
This commit is contained in:
Miško Hevery 2018-01-16 11:38:42 -08:00 committed by Chuck Jazdzewski
parent 47b7898697
commit 1ccc3242f1
1 changed files with 73 additions and 0 deletions

View File

@ -0,0 +1,73 @@
# Tree Shaking Principles
When designing code please keep these principles in mind
## Enums for features are not-tree-shakable
Here is an example of code which is not tree shakable.
```
export function query<T>(
predicate: Type<any>| string[], descend?: boolean,
read?: QueryReadType | Type<T>): QueryList<T> {
ngDevMode && assertPreviousIsParent();
const queryList = new QueryList<T>();
const query = currentQuery || (currentQuery = new LQuery_());
query.track(queryList, predicate, descend, read);
return queryList;
}
```
Notice that `query()` takes the `QueryReadType` as enumeration.
```
function readFromNodeInjector(
nodeInjector: LInjector, node: LNode, read: QueryReadType | Type<any>): any {
if (read === QueryReadType.ElementRef) {
return getOrCreateElementRef(nodeInjector);
}
if (read === QueryReadType.ViewContainerRef) {
return getOrCreateContainerRef(nodeInjector);
}
if (read === QueryReadType.TemplateRef) {
return getOrCreateTemplateRef(nodeInjector);
}
const matchingIdx = geIdxOfMatchingDirective(node, read);
if (matchingIdx !== null) {
return node.view.data[matchingIdx];
}
return null;
}
```
Sometimes later in the above code the `readFromNodeInjector` takes the `QueryReadType` enumeration and performs specific behavior.
The issue is that once the `query` instruction is pulled in it will pull in `ElementRef`, `ContainerRef`, and `TemplateRef` regardless if the `query` instruction queries for them.
A better way to do this is to encapsulate the work into an object or function which will then be passed into the `query` instead of the enumeration.
```
function queryElementRefFeature() {...}
function queryContainerRefFeature() {...}
function queryTemplateRefFeature() {...}
query(predicate, descend, queryElementRefFeature) {...}
```
this would allow the `readFromNodeInjector` to simply call the `read` function (or object) like so.
```
function readFromNodeInjector(
nodeInjector: LInjector, node: LNode, readFn: (injector: Injector) => any) | Type<any>): any {
if (isFeature(readFn)) {
return readFn(nodeInjector);
}
const matchingIdx = geIdxOfMatchingDirective(node, readFn);
if (matchingIdx !== null) {
return node.view.data[matchingIdx];
}
return null;
}
```
This approach allows us to preserve the tree-shaking. In essence the if statement has moved from runtime (non-tree-shakable) to compile time (tree-shakable) position.