Skip to content

Commit

Permalink
fix(lifecycles): async rendering in dist-module
Browse files Browse the repository at this point in the history
  • Loading branch information
manucorporat committed Oct 7, 2019
1 parent 0901698 commit 515df03
Show file tree
Hide file tree
Showing 13 changed files with 86 additions and 83 deletions.
28 changes: 12 additions & 16 deletions src/client/client-host-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,19 @@ export const registerInstance = (lazyInstance: any, hostRef: d.HostRef) =>
hostRefs.set(hostRef.$lazyInstance$ = lazyInstance, hostRef);

export const registerHost = (elm: d.HostElement) => {
if (BUILD.lazyLoad) {
const hostRef: d.HostRef = {
$flags$: 0,
$hostElement$: elm,
$instanceValues$: new Map()
};
if (BUILD.method) {
hostRef.$onInstancePromise$ = new Promise(r => hostRef.$onInstanceResolve$ = r);
}
const hostRef: d.HostRef = {
$flags$: 0,
$hostElement$: elm,
$instanceValues$: new Map()
};
if (BUILD.method && BUILD.lazyLoad) {
hostRef.$onInstancePromise$ = new Promise(r => hostRef.$onInstanceResolve$ = r);
}
if (BUILD.asyncLoading) {
hostRef.$onReadyPromise$ = new Promise(r => hostRef.$onReadyResolve$ = r);
return hostRefs.set(elm, hostRef);
} else {

return hostRefs.set(elm, {
$flags$: 0,
$instanceValues$: new Map()
});
elm['s-p'] = [];
elm['s-rc'] = [];
}
return hostRefs.set(elm, hostRef);
};
export const isMemberInElement = (elm: any, memberName: string) => memberName in elm;
5 changes: 3 additions & 2 deletions src/compiler/app-core/build-conditionals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export function getBuildFeatures(cmps: d.ComponentCompilerMeta[]) {
event: cmps.some(c => c.hasEvent),
hasRenderFn: cmps.some(c => c.hasRenderFn),
lifecycle: cmps.some(c => c.hasLifecycle),
asyncLoading: false,
hostListener: cmps.some(c => c.hasListener),
hostListenerTargetWindow: cmps.some(c => c.hasListenerTargetWindow),
hostListenerTargetDocument: cmps.some(c => c.hasListenerTargetDocument),
Expand Down Expand Up @@ -58,6 +59,7 @@ export function getBuildFeatures(cmps: d.ComponentCompilerMeta[]) {
watchCallback: cmps.some(c => c.hasWatchCallback),
taskQueue: true,
};
f.asyncLoading = f.cmpWillUpdate || f.cmpWillLoad || f.cmpWillRender;

return f;
}
Expand Down Expand Up @@ -118,9 +120,8 @@ export function updateBuildConditionals(config: d.Config, b: d.Build) {
b.hotModuleReplacement = !!(config.devMode && config.devServer && config.devServer.reloadStrategy === 'hmr' && !config._isTesting);
b.updatable = (b.updatable || b.hydrateClientSide || b.hotModuleReplacement);
b.member = (b.member || b.updatable || b.mode || b.lifecycle);
b.taskQueue = (b.updatable || b.mode || b.lifecycle);
b.constructableCSS = !b.hotModuleReplacement || !!config._isTesting;
b.initializeNextTick = true; // config.outputTargets.some(isOutputTargetAngular);
b.asyncLoading = !!(b.asyncLoading || b.lazyLoad || b.taskQueue || b.initializeNextTick);
b.cssAnnotations = true;
}

Expand Down
1 change: 1 addition & 0 deletions src/compiler/browser/build-conditionals-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const BUILD: Required<d.Build> = {
propNumber: true,
propString: true,
reflect: true,
asyncLoading: true,
scoped: true,
shadowDom: true,
slot: true,
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/component-lazy/generate-lazy-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ function getBuildConditionals(config: d.Config, cmps: d.ComponentCompilerMeta[])
build.lazyLoad = true;
build.hydrateServerSide = false;
build.cssVarShim = true;
build.initializeNextTick = true;
build.taskQueue = true;

const hasHydrateOutputTargets = config.outputTargets.some(isOutputTargetHydrate);
build.hydrateClientSide = hasHydrateOutputTargets;
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/output-targets/output-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ function getBuildConditionals(config: d.Config, cmps: d.ComponentCompilerMeta[])
build.hydrateClientSide = false;
build.hydrateServerSide = false;

updateBuildConditionals(config, build);
build.taskQueue = false;
updateBuildConditionals(config, build);

return build;
}
Expand Down
1 change: 1 addition & 0 deletions src/declarations/build-conditionals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export interface BuildFeatures {
cmpDidUnload: boolean;
connectedCallback: boolean;
disconnectedCallback: boolean;
asyncLoading: boolean;

// attr
observeAttribute: boolean;
Expand Down
2 changes: 2 additions & 0 deletions src/hydrate/platform/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ export const registerHost = (elm: d.HostElement) => {
};
hostRef.$onInstancePromise$ = new Promise(r => hostRef.$onInstanceResolve$ = r);
hostRef.$onReadyPromise$ = new Promise(r => hostRef.$onReadyResolve$ = r);
elm['s-p'] = [];
elm['s-rc'] = [];
return hostRefs.set(elm, hostRef);
};

Expand Down
4 changes: 2 additions & 2 deletions src/runtime/connected-callback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { doc, getHostRef, nextTick, plt, supportsShadowDom } from '@platform';
import { HYDRATE_ID, NODE_TYPE, PLATFORM_FLAGS } from './runtime-constants';
import { initializeClientHydrate } from './client-hydrate';
import { initializeComponent } from './initialize-component';
import { safeCall, attachToAncestor } from './update-component';
import { attachToAncestor, safeCall } from './update-component';

export const fireConnectedCallback = (instance: any) => {
if (BUILD.lazyLoad && BUILD.connectedCallback) {
Expand Down Expand Up @@ -57,7 +57,7 @@ export const connectedCallback = (elm: d.HostElement, cmpMeta: d.ComponentRuntim
}
}

if (BUILD.lifecycle || BUILD.lazyLoad) {
if (BUILD.asyncLoading) {
// find the first ancestor component (if there is one) and register
// this component as one of the actively loading child components for its ancestor
let ancestorComponent = elm;
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/initialize-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export const initializeComponent = async (elm: d.HostElement, hostRef: d.HostRef
const ancestorComponent = hostRef.$ancestorComponent$;
const schedule = () => scheduleUpdate(elm, hostRef, cmpMeta, true);

if (BUILD.lifecycle && BUILD.lazyLoad && ancestorComponent && ancestorComponent['s-rc']) {
if (BUILD.asyncLoading && ancestorComponent && ancestorComponent['s-rc']) {
// this is the intial load and this component it has an ancestor component
// but the ancestor component has NOT fired its will update lifecycle yet
// so let's just cool our jets and wait for the ancestor to continue first
Expand Down
117 changes: 57 additions & 60 deletions src/runtime/update-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import * as d from '../declarations';
import { attachStyles } from './styles';
import { BUILD } from '@build-conditionals';
import { CMP_FLAGS, HOST_FLAGS } from '@utils';
import { consoleError, doc, getHostRef, plt, writeTask, nextTick } from '@platform';
import { consoleError, doc, getHostRef, nextTick, plt, writeTask } from '@platform';
import { HYDRATED_CLASS, PLATFORM_FLAGS } from './runtime-constants';
import { renderVdom } from './vdom/vdom-render';

export const attachToAncestor = (hostRef: d.HostRef, ancestorComponent: d.HostElement) => {
if (ancestorComponent && !hostRef.$onRenderResolve$) {
if (BUILD.asyncLoading && ancestorComponent && !hostRef.$onRenderResolve$) {
ancestorComponent['s-p'].push(new Promise(r => hostRef.$onRenderResolve$ = r));
}
};
Expand All @@ -16,27 +16,25 @@ export const scheduleUpdate = (elm: d.HostElement, hostRef: d.HostRef, cmpMeta:
if (BUILD.taskQueue && BUILD.updatable) {
hostRef.$flags$ |= HOST_FLAGS.isQueuedForUpdate;
}
if (hostRef.$flags$ & HOST_FLAGS.isWaitingForChildren) {
if (BUILD.asyncLoading && hostRef.$flags$ & HOST_FLAGS.isWaitingForChildren) {
hostRef.$flags$ |= HOST_FLAGS.needsRerender;
return;
}

const ancestorComponent = hostRef.$ancestorComponent$;
const instance = BUILD.lazyLoad ? hostRef.$lazyInstance$ : elm as any;
const update = () => updateComponent(elm, hostRef, cmpMeta, instance, isInitialLoad);

if (BUILD.lifecycle || BUILD.lazyLoad) {
attachToAncestor(hostRef, ancestorComponent);
}
const rc = elm['s-rc'];
attachToAncestor(hostRef, ancestorComponent);

let promise: Promise<void>;
if (isInitialLoad) {
if (BUILD.hostListener) {
if (BUILD.lazyLoad && BUILD.hostListener) {
hostRef.$flags$ |= HOST_FLAGS.isListenReady;
}
if (BUILD.hostListener && hostRef.$queuedListeners$) {
hostRef.$queuedListeners$.forEach(([methodName, event]) => safeCall(instance, methodName, event));
hostRef.$queuedListeners$ = null;
if (hostRef.$queuedListeners$) {
hostRef.$queuedListeners$.forEach(([methodName, event]) => safeCall(instance, methodName, event));
hostRef.$queuedListeners$ = null;
}
}
emitLifecycleEvent(elm, 'componentWillLoad');
if (BUILD.cmpWillLoad) {
Expand All @@ -56,11 +54,11 @@ export const scheduleUpdate = (elm: d.HostElement, hostRef: d.HostRef, cmpMeta:
promise = then(promise, () => safeCall(instance, 'componentWillRender'));
}

if (BUILD.lifecycle && BUILD.lazyLoad && elm['s-rc']) {
if (BUILD.asyncLoading && rc) {
// ok, so turns out there are some child host elements
// waiting on this parent element to load
// let's fire off all update callbacks waiting
elm['s-rc'].forEach(cb => cb());
rc.forEach(cb => cb());
elm['s-rc'] = undefined;
}

Expand Down Expand Up @@ -125,7 +123,7 @@ const updateComponent = (elm: d.RenderNode, hostRef: d.HostRef, cmpMeta: d.Compo
hostRef.$flags$ |= HOST_FLAGS.hasRendered;
}

if (BUILD.lifecycle || BUILD.lazyLoad) {
if (BUILD.asyncLoading) {
const childrenPromises = elm['s-p'];
const postUpdate = () => postUpdateComponent(elm, hostRef, cmpMeta);
if (childrenPromises.length === 0) {
Expand All @@ -142,76 +140,75 @@ const updateComponent = (elm: d.RenderNode, hostRef: d.HostRef, cmpMeta: d.Compo


export const postUpdateComponent = (elm: d.HostElement, hostRef: d.HostRef, cmpMeta: d.ComponentRuntimeMeta) => {
if ((BUILD.lazyLoad || BUILD.lifecycle || BUILD.lifecycleDOMEvents)) {
const instance = BUILD.lazyLoad ? hostRef.$lazyInstance$ : elm as any;
const ancestorComponent = hostRef.$ancestorComponent$;

if (BUILD.cmpDidRender) {
safeCall(instance, 'componentDidRender');
}
emitLifecycleEvent(elm, 'componentDidRender');
const instance = BUILD.lazyLoad ? hostRef.$lazyInstance$ : elm as any;
const ancestorComponent = hostRef.$ancestorComponent$;

if (!(hostRef.$flags$ & HOST_FLAGS.hasLoadedComponent)) {
hostRef.$flags$ |= HOST_FLAGS.hasLoadedComponent;
if (BUILD.cmpDidRender) {
safeCall(instance, 'componentDidRender');
}
emitLifecycleEvent(elm, 'componentDidRender');

if (BUILD.lazyLoad && BUILD.cssAnnotations) {
// DOM WRITE!
// add the css class that this element has officially hydrated
elm.classList.add(HYDRATED_CLASS);
}
if (!(hostRef.$flags$ & HOST_FLAGS.hasLoadedComponent)) {
hostRef.$flags$ |= HOST_FLAGS.hasLoadedComponent;

if (BUILD.cmpDidLoad) {
safeCall(instance, 'componentDidLoad');
}
if (BUILD.asyncLoading && BUILD.cssAnnotations) {
// DOM WRITE!
// add the css class that this element has officially hydrated
elm.classList.add(HYDRATED_CLASS);
}

emitLifecycleEvent(elm, 'componentDidLoad');
if (BUILD.cmpDidLoad) {
safeCall(instance, 'componentDidLoad');
}

if (BUILD.lazyLoad) {
hostRef.$onReadyResolve$(elm);
}
emitLifecycleEvent(elm, 'componentDidLoad');

if (BUILD.lazyLoad && !ancestorComponent) {
if (BUILD.asyncLoading) {
hostRef.$onReadyResolve$(elm);
if (!ancestorComponent) {
appDidLoad();
}

} else {
if (BUILD.cmpDidUpdate) {
// we've already loaded this component
// fire off the user's componentDidUpdate method (if one was provided)
// componentDidUpdate runs AFTER render() has been called
// and all child components have finished updating
safeCall(instance, 'componentDidUpdate');
}
emitLifecycleEvent(elm, 'componentDidUpdate');
}

if (BUILD.hotModuleReplacement) {
elm['s-hmr-load'] && elm['s-hmr-load']();
} else {
if (BUILD.cmpDidUpdate) {
// we've already loaded this component
// fire off the user's componentDidUpdate method (if one was provided)
// componentDidUpdate runs AFTER render() has been called
// and all child components have finished updating
safeCall(instance, 'componentDidUpdate');
}
emitLifecycleEvent(elm, 'componentDidUpdate');
}

if (BUILD.method) {
hostRef.$onInstanceResolve$(elm);
}
// load events fire from bottom to top
// the deepest elements load first then bubbles up
if ((BUILD.lifecycle || BUILD.lazyLoad) && hostRef.$onRenderResolve$) {
if (BUILD.hotModuleReplacement) {
elm['s-hmr-load'] && elm['s-hmr-load']();
}

if (BUILD.method && BUILD.lazyLoad) {
hostRef.$onInstanceResolve$(elm);
}
// load events fire from bottom to top
// the deepest elements load first then bubbles up
if (BUILD.asyncLoading) {
if (hostRef.$onRenderResolve$) {
hostRef.$onRenderResolve$();
hostRef.$onRenderResolve$ = undefined;
}
if (hostRef.$flags$ & HOST_FLAGS.needsRerender) {
nextTick(() => scheduleUpdate(elm, hostRef, cmpMeta, false));
}
hostRef.$flags$ &= ~(HOST_FLAGS.isWaitingForChildren | HOST_FLAGS.needsRerender);
// ( •_•)
// ( •_•)>⌐■-■
// (⌐■_■)
}
// ( •_•)
// ( •_•)>⌐■-■
// (⌐■_■)
};

export const forceUpdate = (elm: d.RenderNode, cmpMeta: d.ComponentRuntimeMeta) => {
if (BUILD.updatable) {
const hostRef = getHostRef(elm);
if (hostRef.$flags$ & HOST_FLAGS.hasRendered) {
if ((hostRef.$flags$ & (HOST_FLAGS.hasRendered | HOST_FLAGS.isQueuedForUpdate)) === HOST_FLAGS.hasRendered) {
scheduleUpdate(
elm,
hostRef,
Expand Down
1 change: 1 addition & 0 deletions src/testing/build-conditionals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export function resetBuildConditionals(b: d.Build) {
b.scoped = true;
b.shadowDom = true;
b.slotRelocation = true;
b.asyncLoading = true;
b.svg = true;
b.updatable = true;
b.vdomAttribute = true;
Expand Down
2 changes: 2 additions & 0 deletions src/testing/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ export const registerHost = (elm: d.HostElement) => {
};
hostRef.$onInstancePromise$ = new Promise(r => hostRef.$onInstanceResolve$ = r);
hostRef.$onReadyPromise$ = new Promise(r => hostRef.$onReadyResolve$ = r);
elm['s-p'] = [];
elm['s-rc'] = [];
hostRefs.set(elm, hostRef);
};

Expand Down
2 changes: 1 addition & 1 deletion src/testing/spec-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export async function newSpecPage(opts: d.NewSpecPageOptions): Promise<d.SpecPag
}
});
}

bc.BUILD.asyncLoading = true;
if (opts.hydrateClientSide) {
bc.BUILD.hydrateClientSide = true;
bc.BUILD.hydrateServerSide = false;
Expand Down

0 comments on commit 515df03

Please sign in to comment.