perf(animations): reduce size of bundle by removing AST classes (#19539)

This CL refactors the animation AST code to make use of interfaces instead of classes. Given that interfaces are not persisted during runtime the removal of classes should nicely cut down on size for the animations-browser bundle.

-- before --
animations-browser.umd.js = 222kb
animations-browser.umd.min.js = 107kb

-- after --
animations-browser.umd.js = 213kb
animations-browser.umd.min.js = 102kb

PR Close #19539
This commit is contained in:
Matias Niemelä
2017-10-03 13:41:52 -07:00
committed by Chuck Jazdzewski
parent c4704c8abc
commit c3a52697f5
8 changed files with 254 additions and 239 deletions

View File

@ -5,10 +5,10 @@
* 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 {AUTO_STYLE, AnimateChildOptions, AnimateTimings, AnimationOptions, AnimationQueryOptions, ɵPRE_STYLE as PRE_STYLE, ɵStyleData} from '@angular/animations';
import {AUTO_STYLE, AnimateChildOptions, AnimateTimings, AnimationMetadataType, AnimationOptions, AnimationQueryOptions, ɵPRE_STYLE as PRE_STYLE, ɵStyleData} from '@angular/animations';
import {AnimationDriver} from '../render/animation_driver';
import {copyObj, copyStyles, interpolateParams, iteratorToArray, resolveTiming, resolveTimingValue} from '../util';
import {copyObj, copyStyles, interpolateParams, iteratorToArray, resolveTiming, resolveTimingValue, visitDslNode} from '../util';
import {AnimateAst, AnimateChildAst, AnimateRefAst, Ast, AstVisitor, DynamicTimingAst, GroupAst, KeyframesAst, QueryAst, ReferenceAst, SequenceAst, StaggerAst, StateAst, StyleAst, TimingAst, TransitionAst, TriggerAst} from './animation_ast';
import {AnimationTimelineInstruction, createTimelineInstruction} from './animation_timeline_instruction';
@ -101,8 +101,8 @@ const ONE_FRAME_IN_MILLISECONDS = 1;
* the `AnimationValidatorVisitor` code.
*/
export function buildAnimationTimelines(
driver: AnimationDriver, rootElement: any, ast: Ast, startingStyles: ɵStyleData = {},
finalStyles: ɵStyleData = {}, options: AnimationOptions,
driver: AnimationDriver, rootElement: any, ast: Ast<AnimationMetadataType>,
startingStyles: ɵStyleData = {}, finalStyles: ɵStyleData = {}, options: AnimationOptions,
subInstructions?: ElementInstructionMap, errors: any[] = []): AnimationTimelineInstruction[] {
return new AnimationTimelineBuilderVisitor().buildKeyframes(
driver, rootElement, ast, startingStyles, finalStyles, options, subInstructions, errors);
@ -110,15 +110,15 @@ export function buildAnimationTimelines(
export class AnimationTimelineBuilderVisitor implements AstVisitor {
buildKeyframes(
driver: AnimationDriver, rootElement: any, ast: Ast, startingStyles: ɵStyleData,
finalStyles: ɵStyleData, options: AnimationOptions, subInstructions?: ElementInstructionMap,
errors: any[] = []): AnimationTimelineInstruction[] {
driver: AnimationDriver, rootElement: any, ast: Ast<AnimationMetadataType>,
startingStyles: ɵStyleData, finalStyles: ɵStyleData, options: AnimationOptions,
subInstructions?: ElementInstructionMap, errors: any[] = []): AnimationTimelineInstruction[] {
subInstructions = subInstructions || new ElementInstructionMap();
const context = new AnimationTimelineContext(driver, rootElement, subInstructions, errors, []);
context.options = options;
context.currentTimeline.setStyles([startingStyles], null, context.errors, options);
ast.visit(this, context);
visitDslNode(this, ast, context);
// this checks to see if an actual animation happened
const timelines = context.timelines.filter(timeline => timeline.containsAnimation());
@ -193,7 +193,7 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
visitReference(ast: ReferenceAst, context: AnimationTimelineContext) {
context.updateOptions(ast.options, true);
ast.animation.visit(this, context);
visitDslNode(this, ast.animation, context);
context.previousNode = ast;
}
@ -207,7 +207,7 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
ctx.transformIntoNewTimeline();
if (options.delay != null) {
if (ctx.previousNode instanceof StyleAst) {
if (ctx.previousNode.type == AnimationMetadataType.Style) {
ctx.currentTimeline.snapshotCurrentStyles();
ctx.previousNode = DEFAULT_NOOP_PREVIOUS_NODE;
}
@ -218,7 +218,7 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
}
if (ast.steps.length) {
ast.steps.forEach(s => s.visit(this, ctx));
ast.steps.forEach(s => visitDslNode(this, s, ctx));
// this is here just incase the inner steps only contain or end with a style() call
ctx.currentTimeline.applyStylesToKeyframe();
@ -245,7 +245,7 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
innerContext.delayNextStep(delay);
}
s.visit(this, innerContext);
visitDslNode(this, s, innerContext);
furthestTime = Math.max(furthestTime, innerContext.currentTimeline.currentTime);
innerTimelines.push(innerContext.currentTimeline);
});
@ -259,19 +259,19 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
context.previousNode = ast;
}
visitTiming(ast: TimingAst, context: AnimationTimelineContext): AnimateTimings {
if (ast instanceof DynamicTimingAst) {
const strValue = context.params ?
interpolateParams(ast.value, context.params, context.errors) :
ast.value.toString();
return resolveTiming(strValue, context.errors);
private _visitTiming(ast: TimingAst, context: AnimationTimelineContext): AnimateTimings {
if ((ast as DynamicTimingAst).dynamic) {
const strValue = (ast as DynamicTimingAst).strValue;
const timingValue =
context.params ? interpolateParams(strValue, context.params, context.errors) : strValue;
return resolveTiming(timingValue, context.errors);
} else {
return {duration: ast.duration, delay: ast.delay, easing: ast.easing};
}
}
visitAnimate(ast: AnimateAst, context: AnimationTimelineContext) {
const timings = context.currentAnimateTimings = this.visitTiming(ast.timings, context);
const timings = context.currentAnimateTimings = this._visitTiming(ast.timings, context);
const timeline = context.currentTimeline;
if (timings.delay) {
context.incrementTime(timings.delay);
@ -279,7 +279,7 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
}
const style = ast.style;
if (style instanceof KeyframesAst) {
if (style.type == AnimationMetadataType.Keyframes) {
this.visitKeyframes(style, context);
} else {
context.incrementTime(timings.duration);
@ -343,7 +343,7 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
const options = (ast.options || {}) as AnimationQueryOptions;
const delay = options.delay ? resolveTimingValue(options.delay) : 0;
if (delay && (context.previousNode instanceof StyleAst ||
if (delay && (context.previousNode.type === AnimationMetadataType.Style ||
(startTime == 0 && context.currentTimeline.getCurrentStyleProperties().length))) {
context.currentTimeline.snapshotCurrentStyles();
context.previousNode = DEFAULT_NOOP_PREVIOUS_NODE;
@ -368,7 +368,7 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
sameElementTimeline = innerContext.currentTimeline;
}
ast.animation.visit(this, innerContext);
visitDslNode(this, ast.animation, innerContext);
// this is here just incase the inner steps only contain or end
// with a style() call (which is here to signal that this is a preparatory
@ -415,7 +415,7 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
}
const startingTime = timeline.currentTime;
ast.animation.visit(this, context);
visitDslNode(this, ast.animation, context);
context.previousNode = ast;
// time = duration + delay
@ -431,12 +431,12 @@ export declare type StyleAtTime = {
time: number; value: string | number;
};
const DEFAULT_NOOP_PREVIOUS_NODE = <Ast>{};
const DEFAULT_NOOP_PREVIOUS_NODE = <Ast<AnimationMetadataType>>{};
export class AnimationTimelineContext {
public parentContext: AnimationTimelineContext|null = null;
public currentTimeline: TimelineBuilder;
public currentAnimateTimings: AnimateTimings|null = null;
public previousNode: Ast = DEFAULT_NOOP_PREVIOUS_NODE;
public previousNode: Ast<AnimationMetadataType> = DEFAULT_NOOP_PREVIOUS_NODE;
public subContextCount = 0;
public options: AnimationOptions = {};
public currentQueryIndex: number = 0;
@ -489,7 +489,7 @@ export class AnimationTimelineContext {
const oldParams = this.options.params;
if (oldParams) {
const params: {[name: string]: any} = options['params'] = {};
Object.keys(this.options.params).forEach(name => { params[name] = oldParams[name]; });
Object.keys(oldParams).forEach(name => { params[name] = oldParams[name]; });
}
}
return options;