perf(many): reduce delay when performing overlay or page transitions (#26189)

resolves #24346
This commit is contained in:
Liam DeBeasi
2022-11-01 12:08:27 -05:00
committed by GitHub
parent eea6ba996c
commit 30e3a1485d
8 changed files with 57 additions and 56 deletions

View File

@ -271,7 +271,6 @@ export class StackController {
if ((containerEl as any).commit) { if ((containerEl as any).commit) {
return containerEl.commit(enteringEl, leavingEl, { return containerEl.commit(enteringEl, leavingEl, {
deepWait: true,
duration: direction === undefined ? 0 : undefined, duration: direction === undefined ? 0 : undefined,
direction, direction,
showGoBack, showGoBack,

View File

@ -17,7 +17,7 @@ import type {
} from '../../interface'; } from '../../interface';
import { findIonContent, printIonContentErrorMsg } from '../../utils/content'; import { findIonContent, printIonContentErrorMsg } from '../../utils/content';
import { CoreDelegate, attachComponent, detachComponent } from '../../utils/framework-delegate'; import { CoreDelegate, attachComponent, detachComponent } from '../../utils/framework-delegate';
import { raf, inheritAttributes } from '../../utils/helpers'; import { raf, inheritAttributes, hasLazyBuild } from '../../utils/helpers';
import type { Attributes } from '../../utils/helpers'; import type { Attributes } from '../../utils/helpers';
import { KEYBOARD_DID_OPEN } from '../../utils/keyboard/keyboard'; import { KEYBOARD_DID_OPEN } from '../../utils/keyboard/keyboard';
import { printIonWarning } from '../../utils/logging'; import { printIonWarning } from '../../utils/logging';
@ -436,7 +436,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
return; return;
} }
const { presentingElement } = this; const { presentingElement, el } = this;
/** /**
* When using an inline modal * When using an inline modal
@ -462,9 +462,8 @@ export class Modal implements ComponentInterface, OverlayInterface {
}; };
const { inline, delegate } = this.getDelegate(true); const { inline, delegate } = this.getDelegate(true);
this.usersElement = await attachComponent(delegate, this.el, this.component, ['ion-page'], data, inline); this.usersElement = await attachComponent(delegate, el, this.component, ['ion-page'], data, inline);
hasLazyBuild(el) && (await deepReady(this.usersElement));
await deepReady(this.usersElement);
writeTask(() => this.el.classList.add('show-modal')); writeTask(() => this.el.classList.add('show-modal'));

View File

@ -16,7 +16,7 @@ import type {
TriggerAction, TriggerAction,
} from '../../interface'; } from '../../interface';
import { CoreDelegate, attachComponent, detachComponent } from '../../utils/framework-delegate'; import { CoreDelegate, attachComponent, detachComponent } from '../../utils/framework-delegate';
import { addEventListener, raf } from '../../utils/helpers'; import { addEventListener, raf, hasLazyBuild } from '../../utils/helpers';
import { BACKDROP, dismiss, eventMethod, focusFirstDescendant, prepareOverlay, present } from '../../utils/overlays'; import { BACKDROP, dismiss, eventMethod, focusFirstDescendant, prepareOverlay, present } from '../../utils/overlays';
import { isPlatform } from '../../utils/platform'; import { isPlatform } from '../../utils/platform';
import { getClassMap } from '../../utils/theme'; import { getClassMap } from '../../utils/theme';
@ -431,14 +431,16 @@ export class Popover implements ComponentInterface, PopoverInterface {
await this.currentTransition; await this.currentTransition;
} }
const { el } = this;
const data = { const data = {
...this.componentProps, ...this.componentProps,
popover: this.el, popover: this.el,
}; };
const { inline, delegate } = this.getDelegate(true); const { inline, delegate } = this.getDelegate(true);
this.usersElement = await attachComponent(delegate, this.el, this.component, ['popover-viewport'], data, inline); this.usersElement = await attachComponent(delegate, el, this.component, ['popover-viewport'], data, inline);
await deepReady(this.usersElement); hasLazyBuild(el) && (await deepReady(this.usersElement));
if (!this.keyboardEvents) { if (!this.keyboardEvents) {
this.configureKeyboardInteraction(); this.configureKeyboardInteraction();

View File

@ -19,7 +19,7 @@ import type {
} from '../../interface'; } from '../../interface';
import { getTimeGivenProgression } from '../../utils/animation/cubic-bezier'; import { getTimeGivenProgression } from '../../utils/animation/cubic-bezier';
import { attachComponent, detachComponent } from '../../utils/framework-delegate'; import { attachComponent, detachComponent } from '../../utils/framework-delegate';
import { shallowEqualStringMap } from '../../utils/helpers'; import { shallowEqualStringMap, hasLazyBuild } from '../../utils/helpers';
import { transition } from '../../utils/transition'; import { transition } from '../../utils/transition';
@Component({ @Component({
@ -238,6 +238,13 @@ export class RouterOutlet implements ComponentInterface, NavOutlet {
enteringEl, enteringEl,
leavingEl, leavingEl,
baseEl: el, baseEl: el,
/**
* We need to wait for all Stencil components
* to be ready only when using the lazy
* loaded bundle.
*/
deepWait: hasLazyBuild(el),
progressCallback: opts.progressAnimation progressCallback: opts.progressAnimation
? (ani) => { ? (ani) => {
/** /**

View File

@ -76,6 +76,15 @@ export const componentOnReady = (el: any, callback: any) => {
} }
}; };
/**
* This functions checks if a Stencil component is using
* the lazy loaded build of Stencil. Returns `true` if
* the component is lazy loaded. Returns `false` otherwise.
*/
export const hasLazyBuild = (stencilEl: HTMLElement) => {
return (stencilEl as any).componentOnReady !== undefined;
};
export type Attributes = { [key: string]: any }; export type Attributes = { [key: string]: any };
/** /**

View File

@ -7,7 +7,7 @@ import {
LIFECYCLE_WILL_LEAVE, LIFECYCLE_WILL_LEAVE,
} from '../../components/nav/constants'; } from '../../components/nav/constants';
import type { Animation, AnimationBuilder, NavDirection, NavOptions } from '../../interface'; import type { Animation, AnimationBuilder, NavDirection, NavOptions } from '../../interface';
import { componentOnReady, raf } from '../helpers'; import { raf } from '../helpers';
const iosTransitionAnimation = () => import('./ios.transition'); const iosTransitionAnimation = () => import('./ios.transition');
const mdTransitionAnimation = () => import('./md.transition'); const mdTransitionAnimation = () => import('./md.transition');
@ -135,11 +135,11 @@ const noAnimation = async (opts: TransitionOptions): Promise<TransitionResult> =
const waitForReady = async (opts: TransitionOptions, defaultDeep: boolean) => { const waitForReady = async (opts: TransitionOptions, defaultDeep: boolean) => {
const deep = opts.deepWait !== undefined ? opts.deepWait : defaultDeep; const deep = opts.deepWait !== undefined ? opts.deepWait : defaultDeep;
const promises = deep
? [deepReady(opts.enteringEl), deepReady(opts.leavingEl)]
: [shallowReady(opts.enteringEl), shallowReady(opts.leavingEl)];
await Promise.all(promises); if (deep) {
await Promise.all([deepReady(opts.enteringEl), deepReady(opts.leavingEl)]);
}
await notifyViewReady(opts.viewIsReady, opts.enteringEl); await notifyViewReady(opts.viewIsReady, opts.enteringEl);
}; };
@ -195,13 +195,6 @@ export const lifecycle = (el: HTMLElement | undefined, eventName: string) => {
} }
}; };
const shallowReady = (el: Element | undefined): Promise<any> => {
if (el) {
return new Promise((resolve) => componentOnReady(el, resolve));
}
return Promise.resolve();
};
export const deepReady = async (el: any | undefined): Promise<void> => { export const deepReady = async (el: any | undefined): Promise<void> => {
const element = el as any; const element = el as any;
if (element) { if (element) {

View File

@ -365,7 +365,6 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
} }
await routerOutlet.commit(enteringEl, leavingEl, { await routerOutlet.commit(enteringEl, leavingEl, {
deepWait: true,
duration: skipTransition || directionToUse === undefined ? 0 : undefined, duration: skipTransition || directionToUse === undefined ? 0 : undefined,
direction: directionToUse, direction: directionToUse,
showGoBack: !!routeInfo.pushedByRoute, showGoBack: !!routeInfo.pushedByRoute,

View File

@ -195,7 +195,7 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
} }
}); });
const transition = ( const transition = async (
enteringEl: HTMLElement, enteringEl: HTMLElement,
leavingEl: HTMLElement, leavingEl: HTMLElement,
direction: any, // TODO types direction: any, // TODO types
@ -203,23 +203,19 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
progressAnimation: boolean, progressAnimation: boolean,
animationBuilder?: AnimationBuilder animationBuilder?: AnimationBuilder
) => { ) => {
return new Promise(resolve => {
if (skipTransition) { if (skipTransition) {
skipTransition = false; skipTransition = false;
return resolve(false); return Promise.resolve(false);
} }
if (enteringEl === leavingEl) { if (enteringEl === leavingEl) {
return resolve(false); return Promise.resolve(false);
} }
requestAnimationFrame(() => {
requestAnimationFrame(async () => {
enteringEl.classList.add('ion-page-invisible'); enteringEl.classList.add('ion-page-invisible');
const hasRootDirection = direction === undefined || direction === 'root' || direction === 'none'; const hasRootDirection = direction === undefined || direction === 'root' || direction === 'none';
const result = await ionRouterOutlet.value.commit(enteringEl, leavingEl, { const result = await ionRouterOutlet.value.commit(enteringEl, leavingEl, {
deepWait: true,
/** /**
* replace operations result in a direction of none. * replace operations result in a direction of none.
* These typically do not have need animations, so we set * These typically do not have need animations, so we set
@ -235,10 +231,7 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
animationBuilder animationBuilder
}); });
return resolve(result); return result;
});
});
});
} }
const handlePageTransition = async () => { const handlePageTransition = async () => {