Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade TS "target" to es2017 for ES module build #33

Merged
merged 1 commit into from
Apr 25, 2022
Merged

Conversation

ajhyndman
Copy link
Member

It's not clear if this is an improvement or not.

The main difference here is that this allows us to output async/await keywords natively. Without this change, the code in "lib/" will contain a generated TS helper that polyfills async/await functionality.

Before

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { InViewportMutationObserver } from './inViewportMutationObserver';
import { waitForPageLoad } from './util';
import { requestAllIdleCallback } from './requestAllIdleCallback';
import { InViewportImageObserver } from './inViewportImageObserver';
import { Logger } from './util/logger';
/**
 * TODO: Document
 */
class VisuallyCompleteCalculator {
    constructor() {
        this.debug = false;
        this.idleTimeout = 200;
        // measurement state
        this.lastMutationTimestamp = 0;
        this.lastImageLoadTimestamp = 0;
        this.subscribers = new Set();
        this.navigationCount = 0;
        /** subscribe to Visually Complete metrics */
        this.getTTVC = (subscriber) => {
            // register subscriber callback
            this.subscribers.add(subscriber);
            // return an unsubscribe function
            return () => this.subscribers.delete(subscriber);
        };
        if (!VisuallyCompleteCalculator.isSupportedEnvironment()) {
            throw new Error('VisuallyCompleteCalculator: This browser/runtime is not supported.');
        }
        this.inViewportMutationObserver = new InViewportMutationObserver((mutation) => (this.lastMutationTimestamp = Math.max(this.lastMutationTimestamp, mutation.timestamp)));
        this.inViewportImageObserver = new InViewportImageObserver((timestamp) => (this.lastImageLoadTimestamp = Math.max(this.lastImageLoadTimestamp, timestamp)));
    }
    /**
     * Determine whether the calculator should run in the current environment
     */
    static isSupportedEnvironment() {
        var _a;
        return (window !== undefined &&
            'MutationObserver' in window &&
            'IntersectionObserver' in window &&
            typeof document.querySelectorAll === 'function' &&
            ((_a = window.performance) === null || _a === void 0 ? void 0 : _a.timing));
    }
    /** begin measuring a new navigation */
    start(start = 0) {
        return __awaiter(this, void 0, void 0, function* () {
            const navigationIndex = (this.navigationCount += 1);
            Logger.info('VisuallyCompleteCalculator.start()');
            // setup
            let shouldCancel = false;
            const cancel = () => (shouldCancel = true);
            this.inViewportImageObserver.observe();
            this.inViewportMutationObserver.observe(document.documentElement);
            window.addEventListener('pagehide', cancel);
            window.addEventListener('visibilitychange', cancel);
            window.addEventListener('locationchange', cancel);
            // attach user interaction listeners next tick (we don't want to pick up the SPA navigation click)
            window.setTimeout(() => {
                window.addEventListener('click', cancel);
                window.addEventListener('keydown', cancel);
            }, 0);
            // wait for page to be definitely DONE
            // - wait for window.on("load")
            yield waitForPageLoad();
            // - wait for simultaneous network and CPU idle
            const didNetworkTimeOut = yield new Promise(requestAllIdleCallback);
            if (!shouldCancel) {
                // identify timestamp of last visible change
                const end = Math.max(this.lastImageLoadTimestamp, this.lastMutationTimestamp);
                // report result to subscribers
                this.next({
                    start,
                    end,
                    duration: end - start,
                    detail: { didNetworkTimeOut },
                });
            }
            // cleanup
            window.removeEventListener('pagehide', cancel);
            window.removeEventListener('visibilitychange', cancel);
            window.removeEventListener('locationchange', cancel);
            window.removeEventListener('click', cancel);
            window.removeEventListener('keydown', cancel);
            // only disconnect observers if this is the most recent navigation
            if (navigationIndex === this.navigationCount) {
                this.inViewportImageObserver.disconnect();
                this.inViewportMutationObserver.disconnect();
            }
        });
    }
    next(measurement) {
        Logger.debug('VisuallyCompleteCalculator.next()', '::', 'lastImageLoadTimestamp =', this.lastImageLoadTimestamp, 'lastMutationTimestamp =', this.lastMutationTimestamp);
        Logger.info('TTVC:', measurement);
        this.subscribers.forEach((subscriber) => subscriber(measurement));
    }
}
// export calculator singleton
let calculator;
export const getVisuallyCompleteCalculator = () => {
    if (!calculator) {
        calculator = new VisuallyCompleteCalculator();
    }
    return calculator;
};

After

import { InViewportMutationObserver } from './inViewportMutationObserver';
import { waitForPageLoad } from './util';
import { requestAllIdleCallback } from './requestAllIdleCallback';
import { InViewportImageObserver } from './inViewportImageObserver';
import { Logger } from './util/logger';
/**
 * TODO: Document
 */
class VisuallyCompleteCalculator {
    constructor() {
        this.debug = false;
        this.idleTimeout = 200;
        // measurement state
        this.lastMutationTimestamp = 0;
        this.lastImageLoadTimestamp = 0;
        this.subscribers = new Set();
        this.navigationCount = 0;
        /** subscribe to Visually Complete metrics */
        this.getTTVC = (subscriber) => {
            // register subscriber callback
            this.subscribers.add(subscriber);
            // return an unsubscribe function
            return () => this.subscribers.delete(subscriber);
        };
        if (!VisuallyCompleteCalculator.isSupportedEnvironment()) {
            throw new Error('VisuallyCompleteCalculator: This browser/runtime is not supported.');
        }
        this.inViewportMutationObserver = new InViewportMutationObserver((mutation) => (this.lastMutationTimestamp = Math.max(this.lastMutationTimestamp, mutation.timestamp)));
        this.inViewportImageObserver = new InViewportImageObserver((timestamp) => (this.lastImageLoadTimestamp = Math.max(this.lastImageLoadTimestamp, timestamp)));
    }
    /**
     * Determine whether the calculator should run in the current environment
     */
    static isSupportedEnvironment() {
        var _a;
        return (window !== undefined &&
            'MutationObserver' in window &&
            'IntersectionObserver' in window &&
            typeof document.querySelectorAll === 'function' &&
            ((_a = window.performance) === null || _a === void 0 ? void 0 : _a.timing));
    }
    /** begin measuring a new navigation */
    async start(start = 0) {
        const navigationIndex = (this.navigationCount += 1);
        Logger.info('VisuallyCompleteCalculator.start()');
        // setup
        let shouldCancel = false;
        const cancel = () => (shouldCancel = true);
        this.inViewportImageObserver.observe();
        this.inViewportMutationObserver.observe(document.documentElement);
        window.addEventListener('pagehide', cancel);
        window.addEventListener('visibilitychange', cancel);
        window.addEventListener('locationchange', cancel);
        // attach user interaction listeners next tick (we don't want to pick up the SPA navigation click)
        window.setTimeout(() => {
            window.addEventListener('click', cancel);
            window.addEventListener('keydown', cancel);
        }, 0);
        // wait for page to be definitely DONE
        // - wait for window.on("load")
        await waitForPageLoad();
        // - wait for simultaneous network and CPU idle
        const didNetworkTimeOut = await new Promise(requestAllIdleCallback);
        if (!shouldCancel) {
            // identify timestamp of last visible change
            const end = Math.max(this.lastImageLoadTimestamp, this.lastMutationTimestamp);
            // report result to subscribers
            this.next({
                start,
                end,
                duration: end - start,
                detail: { didNetworkTimeOut },
            });
        }
        // cleanup
        window.removeEventListener('pagehide', cancel);
        window.removeEventListener('visibilitychange', cancel);
        window.removeEventListener('locationchange', cancel);
        window.removeEventListener('click', cancel);
        window.removeEventListener('keydown', cancel);
        // only disconnect observers if this is the most recent navigation
        if (navigationIndex === this.navigationCount) {
            this.inViewportImageObserver.disconnect();
            this.inViewportMutationObserver.disconnect();
        }
    }
    next(measurement) {
        Logger.debug('VisuallyCompleteCalculator.next()', '::', 'lastImageLoadTimestamp =', this.lastImageLoadTimestamp, 'lastMutationTimestamp =', this.lastMutationTimestamp);
        Logger.info('TTVC:', measurement);
        this.subscribers.forEach((subscriber) => subscriber(measurement));
    }
}
// export calculator singleton
let calculator;
export const getVisuallyCompleteCalculator = () => {
    if (!calculator) {
        calculator = new VisuallyCompleteCalculator();
    }
    return calculator;
};

@ajhyndman ajhyndman marked this pull request as draft April 22, 2022 18:18
@ajhyndman ajhyndman marked this pull request as ready for review April 25, 2022 17:21
@umairnadeem umairnadeem self-requested a review April 25, 2022 19:18
Copy link

@umairnadeem umairnadeem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ajhyndman ajhyndman merged commit 202e5eb into main Apr 25, 2022
@ajhyndman ajhyndman deleted the lib-es2017 branch April 25, 2022 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants