Skip to content

Instantly share code, notes, and snippets.

@adamrneary
Created September 23, 2017 22:52
Show Gist options
  • Save adamrneary/6e6d802de2f7f78e6be186b5ada14c91 to your computer and use it in GitHub Desktop.
Save adamrneary/6e6d802de2f7f78e6be186b5ada14c91 to your computer and use it in GitHub Desktop.
import Tracking from 'airbnb-tracking';
import { PerformanceAirbnbWebInteractiveEvent } from 'airbnb-jitney-schemas/logging_performance_airbnb_web_interactive_v1';
import { UniversalPageImpressionEvent } from 'airbnb-jitney-schemas/logging_universal_page_impression_v1';
import { PageRequestMethodType } from 'airbnb-jitney-schemas/logging_type_page_request_method_type_v1';
import windowPerformance, { performanceNowFromEpoch } from '../../utils/windowPerformance';
export const VALIDATED_AIRBNB_INTERACTIVE = 'validated-airbnb-interactive';
export const NEVER_INTERACTIVE = 'never-interactive';
function hasActiveServiceWorker() {
if (!('serviceWorker' in navigator)) return Promise.resolve(false);
if (!navigator.serviceWorker.getRegistration) return Promise.resolve(false);
return navigator.serviceWorker.getRegistration('/').then((registration) => {
if (registration) {
return true;
}
return false;
});
}
function prepareWindowPerformanceForWebPerformance({
navigationStart,
unloadEventStart,
unloadEventEnd,
redirectStart,
redirectEnd,
fetchStart,
domainLookupStart,
domainLookupEnd,
connectStart,
connectEnd,
secureConnectionStart,
requestStart,
responseStart,
responseEnd,
domLoading,
domInteractive,
domContentLoadedEventStart,
domContentLoadedEventEnd,
domComplete,
loadEventStart,
loadEventEnd,
}) {
return {
navigation_start_timestamp_in_ms: navigationStart,
time_to_unload_event_start_in_ms: unloadEventStart,
time_to_unload_event_end_in_ms: unloadEventEnd,
time_to_redirect_start_in_ms: redirectStart,
time_to_redirect_end_in_ms: redirectEnd,
time_to_fetch_start_in_ms: fetchStart,
time_to_domain_lookup_start_in_ms: domainLookupStart,
time_to_domain_lookup_end_in_ms: domainLookupEnd,
time_to_connect_start_in_ms: connectStart,
time_to_connect_end_in_ms: connectEnd,
time_to_secure_connection_start_in_ms: secureConnectionStart,
time_to_request_start_in_ms: requestStart,
time_to_response_start_in_ms: responseStart,
time_to_response_end_in_ms: responseEnd,
time_to_dom_loading_in_ms: domLoading,
time_to_dom_interactive_in_ms: domInteractive,
time_to_dom_content_loaded_event_start_in_ms: domContentLoadedEventStart,
time_to_dom_content_loaded_event_end_in_ms: domContentLoadedEventEnd,
time_to_dom_complete_in_ms: domComplete,
time_to_load_event_start_in_ms: loadEventStart,
time_to_load_event_end_in_ms: loadEventEnd,
};
}
class AirbnbInteractiveLogger {
constructor() {
this.pageTransitionStart = undefined;
}
getPageRequestMethod() {
return hasActiveServiceWorker().then((serviceWorker) => {
let pageRequestMethod;
if (this.pageTransitionStart) {
pageRequestMethod = PageRequestMethodType.ClientRouteRequest;
} else if (serviceWorker) {
pageRequestMethod = PageRequestMethodType.ServiceWorkerFulfilledRequest;
} else {
pageRequestMethod = PageRequestMethodType.DirectRequest;
}
return pageRequestMethod;
});
}
logImpression({ universalPageName, extraEventData }) {
if (typeof window !== 'undefined') {
this.getPageRequestMethod().then((pageRequestMethod) => {
const jitneyData = {
schema: UniversalPageImpressionEvent,
event_data: {
page_name: universalPageName,
referrer: document.referrer || 'unknown',
page_request_method: pageRequestMethod,
eventData: extraEventData,
},
};
Tracking.logJitneyEvent(jitneyData);
});
}
}
logAirbnbInteractive({ methodology, extraEventData = {}, universalPageName }) {
const performance = global.window && windowPerformance();
if (!performance || !performance.timing) {
return;
}
const endTime = performanceNowFromEpoch();
let totalTime;
if (this.pageTransitionStart) {
totalTime = endTime - this.pageTransitionStart.startTime;
} else {
totalTime = endTime - performance.timing.requestStart;
}
performance.measure('Time to AirbnbInteractive');
this.logTime({ methodology, tti: totalTime, extraEventData, universalPageName });
}
logTime({ methodology, tti, extraEventData = {}, universalPageName }) {
const performance = global.window && windowPerformance();
const path = global.location.pathname;
const domain = global.location.host;
const timing = prepareWindowPerformanceForWebPerformance(performance.timing || {});
this.getPageRequestMethod().then((pageRequestMethod) => {
const information = {
methodology,
...extraEventData,
};
Tracking.logJitneyEvent({
schema: PerformanceAirbnbWebInteractiveEvent,
event_data: {
information,
domain_and_path: `${domain}${path}`,
page_request_method: pageRequestMethod,
time_to_airbnb_interactive_in_ms: tti,
web_performance_timing: timing,
universal_page_name: universalPageName,
},
});
});
}
logStartPageTransition({ universalPageName, extraEventData }) {
if (!global.window) {
return;
}
this.pageTransitionStart = {
valid: true,
initialRoute: universalPageName,
extraEventData,
startTime: performanceNowFromEpoch(),
};
}
}
export default new AirbnbInteractiveLogger();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment