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:

committed by
Chuck Jazdzewski

parent
c4704c8abc
commit
c3a52697f5
@ -9,10 +9,10 @@ import {AUTO_STYLE, AnimateTimings, AnimationAnimateChildMetadata, AnimationAnim
|
||||
|
||||
import {AnimationDriver} from '../render/animation_driver';
|
||||
import {getOrSetAsInMap} from '../render/shared';
|
||||
import {ENTER_SELECTOR, LEAVE_SELECTOR, NG_ANIMATING_SELECTOR, NG_TRIGGER_SELECTOR, SUBSTITUTION_EXPR_START, copyObj, extractStyleParams, iteratorToArray, normalizeAnimationEntry, resolveTiming, validateStyleParams} from '../util';
|
||||
import {ENTER_SELECTOR, LEAVE_SELECTOR, NG_ANIMATING_SELECTOR, NG_TRIGGER_SELECTOR, SUBSTITUTION_EXPR_START, copyObj, extractStyleParams, iteratorToArray, normalizeAnimationEntry, resolveTiming, validateStyleParams, visitDslNode} from '../util';
|
||||
|
||||
import {AnimateAst, AnimateChildAst, AnimateRefAst, Ast, DynamicTimingAst, GroupAst, KeyframesAst, QueryAst, ReferenceAst, SequenceAst, StaggerAst, StateAst, StyleAst, TimingAst, TransitionAst, TriggerAst} from './animation_ast';
|
||||
import {AnimationDslVisitor, visitAnimationNode} from './animation_dsl_visitor';
|
||||
import {AnimationDslVisitor} from './animation_dsl_visitor';
|
||||
import {parseTransitionExpr} from './animation_transition_expr';
|
||||
|
||||
const SELF_TOKEN = ':self';
|
||||
@ -56,7 +56,7 @@ const SELF_TOKEN_REGEX = new RegExp(`\s*${SELF_TOKEN}\s*,?`, 'g');
|
||||
*/
|
||||
export function buildAnimationAst(
|
||||
driver: AnimationDriver, metadata: AnimationMetadata | AnimationMetadata[],
|
||||
errors: any[]): Ast {
|
||||
errors: any[]): Ast<AnimationMetadataType> {
|
||||
return new AnimationAstBuilderVisitor(driver).build(metadata, errors);
|
||||
}
|
||||
|
||||
@ -69,10 +69,12 @@ const ROOT_SELECTOR = '';
|
||||
export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
|
||||
constructor(private _driver: AnimationDriver) {}
|
||||
|
||||
build(metadata: AnimationMetadata|AnimationMetadata[], errors: any[]): Ast {
|
||||
build(metadata: AnimationMetadata|AnimationMetadata[], errors: any[]):
|
||||
Ast<AnimationMetadataType> {
|
||||
const context = new AnimationAstBuilderContext(errors);
|
||||
this._resetContextStyleTimingState(context);
|
||||
return visitAnimationNode(this, normalizeAnimationEntry(metadata), context) as Ast;
|
||||
return <Ast<AnimationMetadataType>>visitDslNode(
|
||||
this, normalizeAnimationEntry(metadata), context);
|
||||
}
|
||||
|
||||
private _resetContextStyleTimingState(context: AnimationAstBuilderContext) {
|
||||
@ -108,11 +110,12 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
|
||||
'only state() and transition() definitions can sit inside of a trigger()');
|
||||
}
|
||||
});
|
||||
const ast = new TriggerAst(metadata.name, states, transitions);
|
||||
ast.options = normalizeAnimationOptions(metadata.options);
|
||||
ast.queryCount = queryCount;
|
||||
ast.depCount = depCount;
|
||||
return ast;
|
||||
|
||||
return {
|
||||
type: AnimationMetadataType.Trigger,
|
||||
name: metadata.name, states, transitions, queryCount, depCount,
|
||||
options: null
|
||||
};
|
||||
}
|
||||
|
||||
visitState(metadata: AnimationStateMetadata, context: AnimationAstBuilderContext): StateAst {
|
||||
@ -140,31 +143,38 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
const stateAst = new StateAst(metadata.name, styleAst);
|
||||
if (astParams) {
|
||||
stateAst.options = {params: astParams};
|
||||
}
|
||||
return stateAst;
|
||||
return {
|
||||
type: AnimationMetadataType.State,
|
||||
name: metadata.name,
|
||||
style: styleAst,
|
||||
options: astParams ? {params: astParams} : null
|
||||
};
|
||||
}
|
||||
|
||||
visitTransition(metadata: AnimationTransitionMetadata, context: AnimationAstBuilderContext):
|
||||
TransitionAst {
|
||||
context.queryCount = 0;
|
||||
context.depCount = 0;
|
||||
const entry = visitAnimationNode(this, normalizeAnimationEntry(metadata.animation), context);
|
||||
const animation = visitDslNode(this, normalizeAnimationEntry(metadata.animation), context);
|
||||
const matchers = parseTransitionExpr(metadata.expr, context.errors);
|
||||
const ast = new TransitionAst(matchers, entry);
|
||||
ast.options = normalizeAnimationOptions(metadata.options);
|
||||
ast.queryCount = context.queryCount;
|
||||
ast.depCount = context.depCount;
|
||||
return ast;
|
||||
|
||||
return {
|
||||
type: AnimationMetadataType.Transition,
|
||||
matchers,
|
||||
animation,
|
||||
queryCount: context.queryCount,
|
||||
depCount: context.depCount,
|
||||
options: normalizeAnimationOptions(metadata.options)
|
||||
};
|
||||
}
|
||||
|
||||
visitSequence(metadata: AnimationSequenceMetadata, context: AnimationAstBuilderContext):
|
||||
SequenceAst {
|
||||
const ast = new SequenceAst(metadata.steps.map(s => visitAnimationNode(this, s, context)));
|
||||
ast.options = normalizeAnimationOptions(metadata.options);
|
||||
return ast;
|
||||
return {
|
||||
type: AnimationMetadataType.Sequence,
|
||||
steps: metadata.steps.map(s => visitDslNode(this, s, context)),
|
||||
options: normalizeAnimationOptions(metadata.options)
|
||||
};
|
||||
}
|
||||
|
||||
visitGroup(metadata: AnimationGroupMetadata, context: AnimationAstBuilderContext): GroupAst {
|
||||
@ -172,15 +182,17 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
|
||||
let furthestTime = 0;
|
||||
const steps = metadata.steps.map(step => {
|
||||
context.currentTime = currentTime;
|
||||
const innerAst = visitAnimationNode(this, step, context);
|
||||
const innerAst = visitDslNode(this, step, context);
|
||||
furthestTime = Math.max(furthestTime, context.currentTime);
|
||||
return innerAst;
|
||||
});
|
||||
|
||||
context.currentTime = furthestTime;
|
||||
const ast = new GroupAst(steps);
|
||||
ast.options = normalizeAnimationOptions(metadata.options);
|
||||
return ast;
|
||||
return {
|
||||
type: AnimationMetadataType.Group,
|
||||
steps,
|
||||
options: normalizeAnimationOptions(metadata.options)
|
||||
};
|
||||
}
|
||||
|
||||
visitAnimate(metadata: AnimationAnimateMetadata, context: AnimationAstBuilderContext):
|
||||
@ -188,10 +200,10 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
|
||||
const timingAst = constructTimingAst(metadata.timings, context.errors);
|
||||
context.currentAnimateTimings = timingAst;
|
||||
|
||||
let styles: StyleAst|KeyframesAst;
|
||||
let styleAst: StyleAst|KeyframesAst;
|
||||
let styleMetadata: AnimationMetadata = metadata.styles ? metadata.styles : style({});
|
||||
if (styleMetadata.type == AnimationMetadataType.Keyframes) {
|
||||
styles = this.visitKeyframes(styleMetadata as AnimationKeyframesSequenceMetadata, context);
|
||||
styleAst = this.visitKeyframes(styleMetadata as AnimationKeyframesSequenceMetadata, context);
|
||||
} else {
|
||||
let styleMetadata = metadata.styles as AnimationStyleMetadata;
|
||||
let isEmpty = false;
|
||||
@ -204,13 +216,18 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
|
||||
styleMetadata = style(newStyleData);
|
||||
}
|
||||
context.currentTime += timingAst.duration + timingAst.delay;
|
||||
const styleAst = this.visitStyle(styleMetadata, context);
|
||||
styleAst.isEmptyStep = isEmpty;
|
||||
styles = styleAst;
|
||||
const _styleAst = this.visitStyle(styleMetadata, context);
|
||||
_styleAst.isEmptyStep = isEmpty;
|
||||
styleAst = _styleAst;
|
||||
}
|
||||
|
||||
context.currentAnimateTimings = null;
|
||||
return new AnimateAst(timingAst, styles);
|
||||
return {
|
||||
type: AnimationMetadataType.Animate,
|
||||
timings: timingAst,
|
||||
style: styleAst,
|
||||
options: null
|
||||
};
|
||||
}
|
||||
|
||||
visitStyle(metadata: AnimationStyleMetadata, context: AnimationAstBuilderContext): StyleAst {
|
||||
@ -260,9 +277,13 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
|
||||
}
|
||||
});
|
||||
|
||||
const ast = new StyleAst(styles, collectedEasing, metadata.offset);
|
||||
ast.containsDynamicStyles = containsDynamicStyles;
|
||||
return ast;
|
||||
return {
|
||||
type: AnimationMetadataType.Style,
|
||||
styles,
|
||||
easing: collectedEasing,
|
||||
offset: metadata.offset, containsDynamicStyles,
|
||||
options: null
|
||||
};
|
||||
}
|
||||
|
||||
private _validateStyleAst(ast: StyleAst, context: AnimationAstBuilderContext): void {
|
||||
@ -313,9 +334,10 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
|
||||
|
||||
visitKeyframes(metadata: AnimationKeyframesSequenceMetadata, context: AnimationAstBuilderContext):
|
||||
KeyframesAst {
|
||||
const ast: KeyframesAst = {type: AnimationMetadataType.Keyframes, styles: [], options: null};
|
||||
if (!context.currentAnimateTimings) {
|
||||
context.errors.push(`keyframes() must be placed inside of a call to animate()`);
|
||||
return new KeyframesAst([]);
|
||||
return ast;
|
||||
}
|
||||
|
||||
const MAX_KEYFRAME_OFFSET = 1;
|
||||
@ -369,33 +391,38 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
|
||||
currentAnimateTimings.duration = durationUpToThisFrame;
|
||||
this._validateStyleAst(kf, context);
|
||||
kf.offset = offset;
|
||||
|
||||
ast.styles.push(kf);
|
||||
});
|
||||
|
||||
return new KeyframesAst(keyframes);
|
||||
return ast;
|
||||
}
|
||||
|
||||
visitReference(metadata: AnimationReferenceMetadata, context: AnimationAstBuilderContext):
|
||||
ReferenceAst {
|
||||
const entry = visitAnimationNode(this, normalizeAnimationEntry(metadata.animation), context);
|
||||
const ast = new ReferenceAst(entry);
|
||||
ast.options = normalizeAnimationOptions(metadata.options);
|
||||
return ast;
|
||||
return {
|
||||
type: AnimationMetadataType.Reference,
|
||||
animation: visitDslNode(this, normalizeAnimationEntry(metadata.animation), context),
|
||||
options: normalizeAnimationOptions(metadata.options)
|
||||
};
|
||||
}
|
||||
|
||||
visitAnimateChild(metadata: AnimationAnimateChildMetadata, context: AnimationAstBuilderContext):
|
||||
AnimateChildAst {
|
||||
context.depCount++;
|
||||
const ast = new AnimateChildAst();
|
||||
ast.options = normalizeAnimationOptions(metadata.options);
|
||||
return ast;
|
||||
return {
|
||||
type: AnimationMetadataType.AnimateChild,
|
||||
options: normalizeAnimationOptions(metadata.options)
|
||||
};
|
||||
}
|
||||
|
||||
visitAnimateRef(metadata: AnimationAnimateRefMetadata, context: AnimationAstBuilderContext):
|
||||
AnimateRefAst {
|
||||
const animation = this.visitReference(metadata.animation, context);
|
||||
const ast = new AnimateRefAst(animation);
|
||||
ast.options = normalizeAnimationOptions(metadata.options);
|
||||
return ast;
|
||||
return {
|
||||
type: AnimationMetadataType.AnimateRef,
|
||||
animation: this.visitReference(metadata.animation, context),
|
||||
options: normalizeAnimationOptions(metadata.options)
|
||||
};
|
||||
}
|
||||
|
||||
visitQuery(metadata: AnimationQueryMetadata, context: AnimationAstBuilderContext): QueryAst {
|
||||
@ -409,14 +436,18 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
|
||||
parentSelector.length ? (parentSelector + ' ' + selector) : selector;
|
||||
getOrSetAsInMap(context.collectedStyles, context.currentQuerySelector, {});
|
||||
|
||||
const entry = visitAnimationNode(this, normalizeAnimationEntry(metadata.animation), context);
|
||||
const animation = visitDslNode(this, normalizeAnimationEntry(metadata.animation), context);
|
||||
context.currentQuery = null;
|
||||
context.currentQuerySelector = parentSelector;
|
||||
|
||||
const ast = new QueryAst(selector, options.limit || 0, !!options.optional, includeSelf, entry);
|
||||
ast.originalSelector = metadata.selector;
|
||||
ast.options = normalizeAnimationOptions(metadata.options);
|
||||
return ast;
|
||||
return {
|
||||
type: AnimationMetadataType.Query,
|
||||
selector,
|
||||
limit: options.limit || 0,
|
||||
optional: !!options.optional, includeSelf, animation,
|
||||
originalSelector: metadata.selector,
|
||||
options: normalizeAnimationOptions(metadata.options)
|
||||
};
|
||||
}
|
||||
|
||||
visitStagger(metadata: AnimationStaggerMetadata, context: AnimationAstBuilderContext):
|
||||
@ -427,9 +458,12 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor {
|
||||
const timings = metadata.timings === 'full' ?
|
||||
{duration: 0, delay: 0, easing: 'full'} :
|
||||
resolveTiming(metadata.timings, context.errors, true);
|
||||
const animation =
|
||||
visitAnimationNode(this, normalizeAnimationEntry(metadata.animation), context);
|
||||
return new StaggerAst(timings, animation);
|
||||
|
||||
return {
|
||||
type: AnimationMetadataType.Stagger,
|
||||
animation: visitDslNode(this, normalizeAnimationEntry(metadata.animation), context), timings,
|
||||
options: null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -501,17 +535,20 @@ function constructTimingAst(value: string | number | AnimateTimings, errors: any
|
||||
timings = value as AnimateTimings;
|
||||
} else if (typeof value == 'number') {
|
||||
const duration = resolveTiming(value as number, errors).duration;
|
||||
return new TimingAst(value as number, 0, '');
|
||||
return makeTimingAst(duration as number, 0, '');
|
||||
}
|
||||
|
||||
const strValue = value as string;
|
||||
const isDynamic = strValue.split(/\s+/).some(v => v.charAt(0) == '{' && v.charAt(1) == '{');
|
||||
if (isDynamic) {
|
||||
return new DynamicTimingAst(strValue);
|
||||
const ast = makeTimingAst(0, 0, '') as any;
|
||||
ast.dynamic = true;
|
||||
ast.strValue = strValue;
|
||||
return ast as DynamicTimingAst;
|
||||
}
|
||||
|
||||
timings = timings || resolveTiming(strValue, errors);
|
||||
return new TimingAst(timings.duration, timings.delay, timings.easing);
|
||||
return makeTimingAst(timings.duration, timings.delay, timings.easing);
|
||||
}
|
||||
|
||||
function normalizeAnimationOptions(options: AnimationOptions | null): AnimationOptions {
|
||||
@ -525,3 +562,7 @@ function normalizeAnimationOptions(options: AnimationOptions | null): AnimationO
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
function makeTimingAst(duration: number, delay: number, easing: string | null): TimingAst {
|
||||
return {duration, delay, easing};
|
||||
}
|
||||
|
Reference in New Issue
Block a user