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
feat(core): add initial view engine #14014
Conversation
bded18a
to
0e4cee4
Compare
@@ -8,7 +8,7 @@ | |||
"moduleResolution": "node", | |||
"outDir": "../dist/all/", | |||
"noImplicitAny": true, | |||
"noFallthroughCasesInSwitch": true, | |||
"noFallthroughCasesInSwitch": false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this allowed in G3?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, for third party code.
providerDef(NodeFlags.None, TreeComponent, [], null, () => TreeComponent_0), | ||
], | ||
null, | ||
new RenderComponentType('TreeComponent_Host', 'someUrl', 0, ViewEncapsulation.None, [], {}), ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we use directDom
we don't need this here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
viewFlags, | ||
[ | ||
elementDef(NodeFlags.None, 1, 'tree'), | ||
providerDef(NodeFlags.None, TreeComponent, [], {'data': 0}, () => TreeComponent_0), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should not be quoted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check the spec what happens with JavaScript keywords:
- required quoting for an object literal vs allow to use via
.x
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checked in IE11 and Firefox, both allow var x = {function: 1}
as well as x.function
NodeFlags.None, 1, 'span', null, [[BindingType.ElementStyle, 'backgroundColor', null]]), | ||
textDef([' ', ' ']), | ||
anchorDef(NodeFlags.HasEmbeddedViews, 1, TreeComponent_1), | ||
providerDef(NodeFlags.None, NgIf, [ViewContainerRef, TemplateRef], {'ngIf': 0}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't quote the properties
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
updater.checkInline(view, 3, cmp.data.left != null); | ||
updater.checkInline(view, 5, cmp.data.right != null); | ||
}, | ||
new RenderComponentType('TreeComponent_0', 'someUrl', 0, ViewEncapsulation.None, [], {}), ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove RendercomponentType
in this example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
export interface NodeUpdater { | ||
checkInline( | ||
view: ViewData, index: number, v0?: any, v1?: any, v2?: any, v3?: any, v4?: any, v5?: any, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nodeIndex
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
export interface TextDef { prefix: string; } | ||
|
||
export interface NodeDef { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this up, think about order
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
export type ViewUpdateFn = (updater: NodeUpdater, view: ViewData, component: any, context: any) => | ||
void; | ||
|
||
export interface ViewDefinition { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
void; | ||
|
||
export interface ViewDefinition { | ||
nodeFlags: NodeFlags; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add comment: aggregation of flags of all nodes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
nodeFlags: NodeFlags; | ||
flags: ViewFlags; | ||
nodes: NodeDef[]; | ||
reverseChildNodes: NodeDef[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment: providers are always after elements / anchors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
export interface ViewDefinition { | ||
nodeFlags: NodeFlags; | ||
flags: ViewFlags; | ||
nodes: NodeDef[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment: providers are always before elements / anchors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
bindingIndex: number; | ||
bindings: BindingDef[]; | ||
element: ElementDef; | ||
providerIndices: {[tokenKey: string]: number}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move into ProviderDef
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Decided against it
embeddedViews: ViewData[]; | ||
} | ||
|
||
export interface ViewData { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add comment: performance sensitive (numbe rof properties)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
// Data | ||
// ------------------------------------- | ||
|
||
export interface NodeData { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add comment: performance sensitive (numbe rof properties)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
setElementAttribute(view, binding, renderNode, name, value); | ||
break; | ||
case BindingType.ElementClass: | ||
if (view.renderer) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move into helpe ras well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
if (view.renderer) { | ||
view.renderer.setElementAttribute(renderNode, name, renderValue); | ||
} else { | ||
renderNode.setAttribute(name, renderValue); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add code for atribute removal (see DomRenderer)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
if (view.renderer) { | ||
view.renderer.setElementStyle(renderNode, name, renderValue); | ||
} else { | ||
renderNode.style[name] = renderValue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check style removal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
import {checkAndUpdateBinding, checkAndUpdateBindingWithChange, setBindingDebugInfo} from './util'; | ||
|
||
let _tokenKeyCache = new Map<any, string>(); | ||
let _nextTokenKeyIndex = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove, use the size of the map
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
if (Array.isArray(value)) { | ||
[flags, token] = value; | ||
} else { | ||
token = value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
flags = 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
return key; | ||
} | ||
|
||
export function resolveDep( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move to createIOnstance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
view: ViewData, elIndex: number, depDef: DepDef, | ||
notFoundValue: any = Injector.THROW_IF_NOT_FOUND): any { | ||
const tokenKey = depDef.tokenKey; | ||
let elDef = view.def.nodes[elIndex]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move into if
below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
} | ||
|
||
while (view) { | ||
elDef = view.def.nodes[elIndex]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make const
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
view: ViewData, def: NodeDef, v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, | ||
v7: any, v8: any, v9: any) { | ||
const provider = view.nodes[def.index].provider; | ||
let changes: {[prop: string]: SimpleChange}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use SimpleChanges
type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
if (changes) { | ||
provider.ngOnChanges(changes); | ||
} | ||
if ((def.flags & NodeFlags.OnInit) && view.firstChange) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move view.firstChange
first
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
if (changes) { | ||
provider.ngOnChanges(changes); | ||
} | ||
if ((def.flags & NodeFlags.OnInit) && view.firstChange) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move view.firstChagne
first
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
function checkAndUpdateProp( | ||
view: ViewData, provider: any, def: NodeDef, bindingIdx: number, value: any, | ||
changes: {[propName: string]: SimpleChange}): {[propName: string]: SimpleChange} { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use SimpleChanges
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
i + nodesWithoutIndices[i].childCount - (currentParent.index + 1); | ||
const parentEndIndexInReverseChildOrder = | ||
currentParent.reverseChildIndex + currentParent.childCount; | ||
reverseChildIndex = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move outside of if
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
let componentView: ViewData; | ||
if (nodeDef.component) { | ||
const compViewDef = nodeDef.component(); | ||
const services = view.services; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inline
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
} | ||
|
||
const CheckAndUpdate: NodeUpdater = { | ||
checkInline( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to checkInline: (...)
?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
}; | ||
|
||
export function destroyView(view: ViewData) { | ||
execComponentViewsAction(view, ViewAction.Destroy); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add comment: Bottom up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
export function destroyView(view: ViewData) { | ||
execComponentViewsAction(view, ViewAction.Destroy); | ||
execEmbeddedViewsAction(view, ViewAction.Destroy); | ||
callLifecycleHooksChildrenFirst(view, NodeFlags.OnDestroy); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
call destroy
before the views are destroyed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
const nextSibling = prevRenderNode.nextSibling; | ||
if (parentNode) { | ||
directDomAttachDetachSiblingRenderNodes( | ||
view, 0, nextSibling ? DirectDomAction.InsertBefore : DirectDomAction.AppendChild, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move action into const
before
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
} | ||
} | ||
} | ||
i += nodeDef.childCount; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add comment: This jumps to the next sibling
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
} | ||
} | ||
} | ||
i += nodeDef.childCount; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add comment: This jumps to the next sibling
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -0,0 +1,212 @@ | |||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
[BindingType.ElementAttribute, 'a2', SecurityContext.NONE] | ||
]), | ||
], | ||
(updater, view) => updater.checkDynamic(view, 0, ['v1', 'v2']))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactor these tests into 1 test or a generic test that just takes the updater as argument
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
expect(instance.b).toBe('v2'); | ||
}); | ||
|
||
it('should update via array', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fold into 1 test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
}); | ||
|
||
describe('change text', () => { | ||
it('should update inline', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
merge into 1 test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
export function main() { | ||
describe('viewDef', () => { | ||
describe('reverseChild oreder', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
it('should reverse child order for mixed levels', () => { | ||
const vd = viewDef(ViewFlags.None, [ | ||
textDef(['a']), // level 0 | ||
elementDef(NodeFlags.None, 5, 'span'), // level 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
level 0, adjust others
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add indices to the comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add a comment to the tsconfig.json so that nobody copies that option. otherwise lgtm
3861e93
to
4653203
Compare
The new view engine allows our codegen to produce less code, as it can interpret view definitions during runtime. The view engine is not feature complete yet, but already allows to implement a tree benchmark based on it. Part of angular#14013
The new view engine allows our codegen to produce less code, as it can interpret view definitions during runtime. The view engine is not feature complete yet, but already allows to implement a tree benchmark based on it. Part of angular#14013
The new view engine allows our codegen to produce less code, as it can interpret view definitions during runtime. The view engine is not feature complete yet, but already allows to implement a tree benchmark based on it. Part of angular#14013
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
The new view engine allows our codegen to produce less code,
as it can interpret view definitions during runtime.
The view engine is not feature complete yet, but already
allows to implement a tree benchmark based on it.
Part of #14013