diff --git a/integration/_payload-limits.json b/integration/_payload-limits.json index 1b13ca56bd..9d62c9f0fa 100644 --- a/integration/_payload-limits.json +++ b/integration/_payload-limits.json @@ -21,7 +21,7 @@ "master": { "uncompressed": { "runtime": 1440, - "main": 146225, + "main": 147764, "polyfills": 43567 } } diff --git a/packages/compiler/src/render3/view/compiler.ts b/packages/compiler/src/render3/view/compiler.ts index 92dcd4cf53..7ea88f0221 100644 --- a/packages/compiler/src/render3/view/compiler.ts +++ b/packages/compiler/src/render3/view/compiler.ts @@ -13,7 +13,6 @@ import {BindingForm, convertPropertyBinding} from '../../compiler_util/expressio import {ConstantPool, DefinitionKind} from '../../constant_pool'; import * as core from '../../core'; import {AST, ParsedEvent, ParsedEventType, ParsedProperty} from '../../expression_parser/ast'; -import {LifecycleHooks} from '../../lifecycle_reflector'; import {DEFAULT_INTERPOLATION_CONFIG} from '../../ml_parser/interpolation_config'; import * as o from '../../output/output_ast'; import {ParseError, ParseSourceSpan, typeSourceSpan} from '../../parse_util'; @@ -725,6 +724,7 @@ function createHostBindingsFunction( // the update block of a component/directive templateFn/hostBindingsFn so that the bindings // are evaluated and updated for the element. styleBuilder.buildUpdateLevelInstructions(getValueConverter()).forEach(instruction => { + totalHostVarsCount += instruction.allocateBindingSlots; updateStatements.push(createStylingStmt(instruction, bindingContext, bindingFn)); }); } diff --git a/packages/compiler/src/render3/view/styling_builder.ts b/packages/compiler/src/render3/view/styling_builder.ts index 0260b29f1f..b355d20cb7 100644 --- a/packages/compiler/src/render3/view/styling_builder.ts +++ b/packages/compiler/src/render3/view/styling_builder.ts @@ -15,6 +15,7 @@ import * as t from '../r3_ast'; import {Identifiers as R3} from '../r3_identifiers'; import {parse as parseStyle} from './style_parser'; +import {compilerIsNewStylingInUse} from './styling_state'; import {ValueConverter} from './template'; const IMPORTANT_FLAG = '!important'; @@ -389,6 +390,11 @@ export class StylingBuilder { const bindingIndex: number = mapIndex.get(input.name !) !; const value = input.value.visit(valueConverter); totalBindingSlotsRequired += (value instanceof Interpolation) ? value.expressions.length : 0; + if (compilerIsNewStylingInUse()) { + // the old implementation does not reserve slot values for + // binding entries. The new one does. + totalBindingSlotsRequired++; + } return { sourceSpan: input.sourceSpan, allocateBindingSlots: totalBindingSlotsRequired, reference, diff --git a/packages/compiler/src/render3/view/styling_state.ts b/packages/compiler/src/render3/view/styling_state.ts new file mode 100644 index 0000000000..c63ab6d8e6 --- /dev/null +++ b/packages/compiler/src/render3/view/styling_state.ts @@ -0,0 +1,37 @@ +/** +* @license +* Copyright Google Inc. All Rights Reserved. +* +* Use of this source code is governed by an MIT-style license that can be +* found in the LICENSE file at https://angular.io/license +*/ + +/** + * A temporary enum of states that inform the core whether or not + * to defer all styling instruction calls to the old or new + * styling implementation. + */ +export const enum CompilerStylingMode { + UseOld = 0, + UseBothOldAndNew = 1, + UseNew = 2, +} + +let _stylingMode = 0; + +/** + * Temporary function used to inform the existing styling algorithm + * code to delegate all styling instruction calls to the new refactored + * styling code. + */ +export function compilerSetStylingMode(mode: CompilerStylingMode) { + _stylingMode = mode; +} + +export function compilerIsNewStylingInUse() { + return _stylingMode > CompilerStylingMode.UseOld; +} + +export function compilerAllowOldStyling() { + return _stylingMode < CompilerStylingMode.UseNew; +} diff --git a/packages/core/src/render3/debug.ts b/packages/core/src/render3/debug.ts index f0cf7258ed..e8d9997b76 100644 --- a/packages/core/src/render3/debug.ts +++ b/packages/core/src/render3/debug.ts @@ -15,11 +15,10 @@ import {LQueries} from './interfaces/query'; import {RComment, RElement} from './interfaces/renderer'; import {StylingContext} from './interfaces/styling'; import {BINDING_INDEX, CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTENT_QUERIES, CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, INJECTOR, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, SANITIZER, TVIEW, T_HOST} from './interfaces/view'; -import {getTNode, unwrapRNode} from './util/view_utils'; - -function attachDebugObject(obj: any, debug: any) { - Object.defineProperty(obj, 'debug', {value: debug, enumerable: false}); -} +import {runtimeIsNewStylingInUse} from './styling_next/state'; +import {DebugStyling as DebugNewStyling, NodeStylingDebug} from './styling_next/styling_debug'; +import {attachDebugObject} from './util/debug_utils'; +import {getTNode, isStylingContext, unwrapRNode} from './util/view_utils'; /* * This file contains conditionally attached classes which provide human readable (debug) level @@ -171,6 +170,8 @@ export class LViewDebug { export interface DebugNode { html: string|null; native: Node; + styles: DebugNewStyling|null; + classes: DebugNewStyling|null; nodes: DebugNode[]|null; component: LViewDebug|null; } @@ -188,12 +189,21 @@ export function toDebugNodes(tNode: TNode | null, lView: LView): DebugNode[]|nul while (tNodeCursor) { const rawValue = lView[tNode.index]; const native = unwrapRNode(rawValue); - const componentLViewDebug = toDebug(readLViewValue(rawValue)); + const componentLViewDebug = + isStylingContext(rawValue) ? null : toDebug(readLViewValue(rawValue)); + + let styles: DebugNewStyling|null = null; + let classes: DebugNewStyling|null = null; + if (runtimeIsNewStylingInUse()) { + styles = tNode.newStyles ? new NodeStylingDebug(tNode.newStyles, lView) : null; + classes = tNode.newClasses ? new NodeStylingDebug(tNode.newClasses, lView) : null; + } + debugNodes.push({ html: toHtml(native), - native: native as any, + native: native as any, styles, classes, nodes: toDebugNodes(tNode.child, lView), - component: componentLViewDebug + component: componentLViewDebug, }); tNodeCursor = tNodeCursor.next; } diff --git a/packages/core/src/render3/instructions/element.ts b/packages/core/src/render3/instructions/element.ts index 5f8e81a8c7..2fdb61954e 100644 --- a/packages/core/src/render3/instructions/element.ts +++ b/packages/core/src/render3/instructions/element.ts @@ -21,6 +21,8 @@ import {applyOnCreateInstructions} from '../node_util'; import {decreaseElementDepthCount, getElementDepthCount, getIsParent, getLView, getPreviousOrParentTNode, getSelectedIndex, increaseElementDepthCount, setIsParent, setPreviousOrParentTNode} from '../state'; import {getInitialClassNameValue, getInitialStyleStringValue, initializeStaticContext, patchContextWithStaticAttrs, renderInitialClasses, renderInitialStyles} from '../styling/class_and_style_bindings'; import {getStylingContextFromLView, hasClassInput, hasStyleInput} from '../styling/util'; +import {registerInitialStylingIntoContext} from '../styling_next/instructions'; +import {runtimeIsNewStylingInUse} from '../styling_next/state'; import {NO_CHANGE} from '../tokens'; import {attrsStylingIndexOf, setUpAttributes} from '../util/attrs_utils'; import {renderStringify} from '../util/misc_utils'; @@ -63,8 +65,9 @@ export function ΔelementStart( let initialStylesIndex = 0; let initialClassesIndex = 0; + let lastAttrIndex = -1; if (attrs) { - const lastAttrIndex = setUpAttributes(native, attrs); + lastAttrIndex = setUpAttributes(native, attrs); // it's important to only prepare styling-related datastructures once for a given // tNode and not each time an element is created. Also, the styling code is designed @@ -116,6 +119,10 @@ export function ΔelementStart( renderInitialStyles(native, tNode.stylingTemplate, renderer, initialStylesIndex); } + if (runtimeIsNewStylingInUse() && lastAttrIndex >= 0) { + registerInitialStylingIntoContext(tNode, attrs as TAttributes, lastAttrIndex); + } + const currentQueries = lView[QUERIES]; if (currentQueries) { currentQueries.addNode(tNode); diff --git a/packages/core/src/render3/instructions/shared.ts b/packages/core/src/render3/instructions/shared.ts index df17271738..d3a849e7a0 100644 --- a/packages/core/src/render3/instructions/shared.ts +++ b/packages/core/src/render3/instructions/shared.ts @@ -777,6 +777,10 @@ export function createTNode( stylingTemplate: null, projection: null, onElementCreationFns: null, + // TODO (matsko): rename this to `styles` once the old styling impl is gone + newStyles: null, + // TODO (matsko): rename this to `classes` once the old styling impl is gone + newClasses: null, }; } diff --git a/packages/core/src/render3/instructions/styling.ts b/packages/core/src/render3/instructions/styling.ts index 2d2911ba95..6fd0186849 100644 --- a/packages/core/src/render3/instructions/styling.ts +++ b/packages/core/src/render3/instructions/styling.ts @@ -17,6 +17,9 @@ import {BoundPlayerFactory} from '../styling/player_factory'; import {DEFAULT_TEMPLATE_DIRECTIVE_INDEX} from '../styling/shared'; import {getCachedStylingContext, setCachedStylingContext} from '../styling/state'; import {allocateOrUpdateDirectiveIntoContext, createEmptyStylingContext, forceClassesAsString, forceStylesAsString, getStylingContextFromLView, hasClassInput, hasStyleInput} from '../styling/util'; +import {classProp as newClassProp, styleProp as newStyleProp, stylingApply as newStylingApply, stylingInit as newStylingInit} from '../styling_next/instructions'; +import {runtimeAllowOldStyling, runtimeIsNewStylingInUse} from '../styling_next/state'; +import {getBindingNameFromIndex} from '../styling_next/util'; import {NO_CHANGE} from '../tokens'; import {renderStringify} from '../util/misc_utils'; import {getRootContext} from '../util/view_traversal_utils'; @@ -73,6 +76,13 @@ export function Δstyling( const directiveStylingIndex = getActiveDirectiveStylingIndex(); if (directiveStylingIndex) { + // this is temporary hack to get the existing styling instructions to + // play ball with the new refactored implementation. + // TODO (matsko): remove this once the old implementation is not needed. + if (runtimeIsNewStylingInUse()) { + newStylingInit(); + } + // despite the binding being applied in a queue (below), the allocation // of the directive into the context happens right away. The reason for // this is to retain the ordering of the directives (which is important @@ -81,7 +91,7 @@ export function Δstyling( const fns = tNode.onElementCreationFns = tNode.onElementCreationFns || []; fns.push(() => { - initstyling( + initStyling( tNode, classBindingNames, styleBindingNames, styleSanitizer, directiveStylingIndex); registerHostDirective(tNode.stylingTemplate !, directiveStylingIndex); }); @@ -92,13 +102,13 @@ export function Δstyling( // components) then they will be applied at the end of the `elementEnd` // instruction (because directives are created first before styling is // executed for a new element). - initstyling( + initStyling( tNode, classBindingNames, styleBindingNames, styleSanitizer, DEFAULT_TEMPLATE_DIRECTIVE_INDEX); } } -function initstyling( +function initStyling( tNode: TNode, classBindingNames: string[] | null | undefined, styleBindingNames: string[] | null | undefined, styleSanitizer: StyleSanitizeFn | null | undefined, directiveStylingIndex: number): void { @@ -148,6 +158,15 @@ export function ΔstyleProp( updatestyleProp( stylingContext, styleIndex, valueToAdd, DEFAULT_TEMPLATE_DIRECTIVE_INDEX, forceOverride); } + + if (runtimeIsNewStylingInUse()) { + const prop = getBindingNameFromIndex(stylingContext, styleIndex, directiveStylingIndex, false); + + // the reason why we cast the value as `boolean` is + // because the new styling refactor does not yet support + // sanitization or animation players. + newStyleProp(prop, value as string | number, suffix); + } } function resolveStylePropValue( @@ -206,6 +225,15 @@ export function ΔclassProp( updateclassProp( stylingContext, classIndex, input, DEFAULT_TEMPLATE_DIRECTIVE_INDEX, forceOverride); } + + if (runtimeIsNewStylingInUse()) { + const prop = getBindingNameFromIndex(stylingContext, classIndex, directiveStylingIndex, true); + + // the reason why we cast the value as `boolean` is + // because the new styling refactor does not yet support + // sanitization or animation players. + newClassProp(prop, input as boolean); + } } @@ -324,11 +352,14 @@ export function ΔstylingApply(): void { const renderer = tNode.type === TNodeType.Element ? lView[RENDERER] : null; const isFirstRender = (lView[FLAGS] & LViewFlags.FirstLViewPass) !== 0; const stylingContext = getStylingContext(index, lView); - const totalPlayersQueued = renderStyling( - stylingContext, renderer, lView, isFirstRender, null, null, directiveStylingIndex); - if (totalPlayersQueued > 0) { - const rootContext = getRootContext(lView); - scheduleTick(rootContext, RootContextFlags.FlushPlayers); + + if (runtimeAllowOldStyling()) { + const totalPlayersQueued = renderStyling( + stylingContext, renderer, lView, isFirstRender, null, null, directiveStylingIndex); + if (totalPlayersQueued > 0) { + const rootContext = getRootContext(lView); + scheduleTick(rootContext, RootContextFlags.FlushPlayers); + } } // because select(n) may not run between every instruction, the cached styling @@ -339,6 +370,10 @@ export function ΔstylingApply(): void { // cleared because there is no code in Angular that applies more styling code after a // styling flush has occurred. Note that this will be fixed once FW-1254 lands. setCachedStylingContext(null); + + if (runtimeIsNewStylingInUse()) { + newStylingApply(); + } } export function getActiveDirectiveStylingIndex() { diff --git a/packages/core/src/render3/interfaces/node.ts b/packages/core/src/render3/interfaces/node.ts index c4f476ce7c..cb6f99b466 100644 --- a/packages/core/src/render3/interfaces/node.ts +++ b/packages/core/src/render3/interfaces/node.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ - +import {TStylingContext} from '../styling_next/interfaces'; import {CssSelector} from './projection'; import {RNode} from './renderer'; import {StylingContext} from './styling'; @@ -438,6 +438,10 @@ export interface TNode { * with functions each time the creation block is called. */ onElementCreationFns: Function[]|null; + // TODO (matsko): rename this to `styles` once the old styling impl is gone + newStyles: TStylingContext|null; + // TODO (matsko): rename this to `classes` once the old styling impl is gone + newClasses: TStylingContext|null; } /** Static data for an element */ diff --git a/packages/core/src/render3/jit/environment.ts b/packages/core/src/render3/jit/environment.ts index 1518a0e7f6..c246c12672 100644 --- a/packages/core/src/render3/jit/environment.ts +++ b/packages/core/src/render3/jit/environment.ts @@ -6,10 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ -import {ΔdefineInjectable, ΔdefineInjector,} from '../../di/interface/defs'; import {Δinject} from '../../di/injector_compatibility'; -import * as r3 from '../index'; +import {ΔdefineInjectable, ΔdefineInjector} from '../../di/interface/defs'; import * as sanitization from '../../sanitization/sanitization'; +import * as r3 from '../index'; + /** diff --git a/packages/core/src/render3/state.ts b/packages/core/src/render3/state.ts index 7234afc2c2..647446ae32 100644 --- a/packages/core/src/render3/state.ts +++ b/packages/core/src/render3/state.ts @@ -245,6 +245,27 @@ export function adjustActiveDirectiveSuperClassDepthPosition(delta: number) { Math.max(activeDirectiveSuperClassHeight, activeDirectiveSuperClassDepthPosition); } +/** + * Returns he current depth of the super/sub class inheritance chain. + * + * This will return how many inherited directive/component classes + * exist in the current chain. + * + * ```typescript + * @Directive({ selector: '[super-dir]' }) + * class SuperDir {} + * + * @Directive({ selector: '[sub-dir]' }) + * class SubDir extends SuperDir {} + * + * // if `