Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

perfume.js

Package Overview
Dependencies
Maintainers
1
Versions
157
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

perfume.js - npm Package Compare versions

Comparing version 0.6.6 to 0.7.0

dist/perfume.es5.min.js

19

dist/es/emulated-performance.js
var EmulatedPerformance = /** @class */ (function () {
function EmulatedPerformance() {
function EmulatedPerformance(config) {
this.config = config;
}

@@ -8,3 +9,3 @@ /**

*
* @type {number}
* @return {number}
*/

@@ -23,3 +24,4 @@ EmulatedPerformance.prototype.now = function () {

* @param {string} metricName
* @param {object} metrics
* @param {Metrics} metrics
* @return {number}
*/

@@ -34,3 +36,3 @@ EmulatedPerformance.prototype.measure = function (metricName, metrics) {

*
* @param {any} cb
* @param {(entries: any[]) => void} cb
*/

@@ -48,3 +50,4 @@ EmulatedPerformance.prototype.firstContentfulPaint = function (cb) {

* @param {string} metricName
* @param {metrics} any
* @param {Metrics} metrics
* @return {number}
*/

@@ -59,3 +62,3 @@ EmulatedPerformance.prototype.getDurationByMetric = function (metricName, metrics) {

*
* @param {PerformancePaintTiming} performancePaintTiming
* @return {PerformancePaintTiming[]}
*/

@@ -66,4 +69,4 @@ EmulatedPerformance.prototype.getFirstPaint = function () {

duration: 0,
entryType: "paint",
name: "first-contentful-paint",
entryType: 'paint',
name: 'first-contentful-paint',
startTime: 0,

@@ -70,0 +73,0 @@ };

@@ -1,4 +0,5 @@

import ttiPolyfill from "tti-polyfill";
import ttiPolyfill from 'tti-polyfill';
var Performance = /** @class */ (function () {
function Performance() {
function Performance(config) {
this.config = config;
this.timeToInteractiveDuration = 0;

@@ -15,3 +16,3 @@ this.ttiPolyfill = ttiPolyfill;

*
* @type {boolean}
* @return {boolean}
*/

@@ -28,3 +29,3 @@ Performance.supported = function () {

*
* @type {boolean}
* @return {boolean}
*/

@@ -38,6 +39,6 @@ Performance.supportedPerformanceObserver = function () {

*
* @type {boolean}
* @return {boolean}
*/
Performance.supportedLongTask = function () {
return "PerformanceLongTaskTiming" in window;
return 'PerformanceLongTaskTiming' in window;
};

@@ -48,3 +49,3 @@ /**

* thousandths of a millisecond (5 microseconds).
* @type {number}
* @return {number}
*/

@@ -64,4 +65,4 @@ Performance.prototype.now = function () {

* @param {string} metricName
* @param {object} metrics
* @param {string} endMark
* @param {Metrics} metrics
* @return {number}
*/

@@ -81,9 +82,26 @@ Performance.prototype.measure = function (metricName, metrics) {

*
* @param {any} cb
* @param {(entries: any[]) => void} cb
*/
Performance.prototype.firstContentfulPaint = function (cb) {
this.perfObserver = new PerformanceObserver(this.performanceObserverCb.bind(this, cb));
this.perfObserver.observe({ entryTypes: ["paint"] });
this.perfObserver.observe({ entryTypes: ['paint'] });
};
/**
* The polyfill exposes a getFirstConsistentlyInteractive() method,
* which returns a promise that resolves with the TTI value.
*
* The getFirstConsistentlyInteractive() method accepts an optional
* startTime configuration option, allowing you to specify a lower bound
* for which you know your app cannot be interactive before.
* By default the polyfill uses DOMContentLoaded as the start time,
* but it's often more accurate to use something like the moment your hero elements
* are visible or the point when you know all your event listeners have been added.
*
* @param {number} minValue
* @return {Promise<number>}
*/
Performance.prototype.timeToInteractive = function (minValue) {
return this.ttiPolyfill.getFirstConsistentlyInteractive({ minValue: minValue });
};
/**
* Get the duration of the timing metric or -1 if there a measurement has

@@ -93,7 +111,8 @@ * not been made by the User Timing API

* @param {string} metricName
* @param {any} metrics
* @param {Metrics} metrics
* @return {number}
*/
Performance.prototype.getDurationByMetric = function (metricName, metrics) {
var entry = this.getMeasurementForGivenName(metricName);
if (entry && entry.entryType === "measure") {
if (entry && entry.entryType === 'measure') {
return entry.duration;

@@ -113,3 +132,3 @@ }

/**
* @param {any} cb
* @param {(entries: PerformanceEntry[]) => void} cb
* @param {PerformanceObserverEntryList} entryList

@@ -123,3 +142,3 @@ */

if (_this.config.firstContentfulPaint
&& performancePaintTiming.name === "first-contentful-paint") {
&& performancePaintTiming.name === 'first-contentful-paint') {
_this.perfObserver.disconnect();

@@ -129,19 +148,2 @@ }

};
/**
* The polyfill exposes a getFirstConsistentlyInteractive() method,
* which returns a promise that resolves with the TTI value.
*
* The getFirstConsistentlyInteractive() method accepts an optional
* startTime configuration option, allowing you to specify a lower bound
* for which you know your app cannot be interactive before.
* By default the polyfill uses DOMContentLoaded as the start time,
* but it's often more accurate to use something like the moment your hero elements
* are visible or the point when you know all your event listeners have been added.
*
* @param {number} minValue
* @param {any} cb
*/
Performance.prototype.timeToInteractive = function (minValue, cb) {
this.ttiPolyfill.getFirstConsistentlyInteractive({ minValue: minValue }).then(cb);
};
return Performance;

@@ -148,0 +150,0 @@ }());

/*!
* Perfume.js v0.6.4 (http://zizzamia.github.io/perfume)
* Perfume.js v0.7.0 (http://zizzamia.github.io/perfume)
* Copyright 2018 The Perfume Authors (https://github.com/Zizzamia/perfume.js/graphs/contributors)

@@ -7,7 +7,12 @@ * Licensed under MIT (https://github.com/Zizzamia/perfume.js/blob/master/LICENSE)

*/
import EmulatedPerformance from "./emulated-performance";
import Performance from "./performance";
import EmulatedPerformance from './emulated-performance';
import Performance from './performance';
var Perfume = /** @class */ (function () {
/**
* @constructor
* @param options
*/
function Perfume(options) {
if (options === void 0) { options = {}; }
var _this = this;
this.config = {

@@ -18,5 +23,5 @@ firstContentfulPaint: false,

enable: false,
timingVar: "name",
timingVar: 'name',
},
logPrefix: "⚡️ Perfume.js:",
logPrefix: '⚡️ Perfume.js:',
logging: true,

@@ -31,14 +36,25 @@ timeToInteractive: false,

// Init performance implementation
this.perf = Performance.supported() ? new Performance() : new EmulatedPerformance();
this.perf.config = this.config;
// Init First Contentful Paint
if (Performance.supportedPerformanceObserver()) {
this.perf.firstContentfulPaint(this.firstContentfulPaintCb.bind(this));
}
else {
this.perfEmulated = new EmulatedPerformance();
this.perfEmulated.firstContentfulPaint(this.firstContentfulPaintCb.bind(this));
}
this.perf = Performance.supported() ? new Performance(this.config) : new EmulatedPerformance(this.config);
this.timeToInteractivePromise = new Promise(function (resolve, reject) {
// Init First Contentful Paint
if (Performance.supportedPerformanceObserver()) {
_this.perf.firstContentfulPaint(function (entries) {
_this.firstContentfulPaintCb(entries, resolve, reject);
});
}
else {
_this.perfEmulated = new EmulatedPerformance(_this.config);
_this.perfEmulated.firstContentfulPaint(function (entries) {
_this.firstContentfulPaintCb(entries, resolve, reject);
});
}
});
}
/**
* @return {Promise<number>}
*/
Perfume.prototype.observeTimeToInteractive = function () {
return this.timeToInteractivePromise;
};
/**
* Start performance measurement

@@ -53,3 +69,3 @@ *

if (this.metrics[metricName]) {
window.console.warn(this.config.logPrefix, "Recording already started.");
window.console.warn(this.config.logPrefix, 'Recording already started.');
return;

@@ -61,3 +77,3 @@ }

};
this.perf.mark(metricName, "start");
this.perf.mark(metricName, 'start');
};

@@ -68,2 +84,3 @@ /**

* @param {string} metricName
* @return {void|number}
*/

@@ -75,7 +92,7 @@ Perfume.prototype.end = function (metricName) {

if (!this.metrics[metricName]) {
window.console.warn(this.config.logPrefix, "Recording already stopped.");
window.console.warn(this.config.logPrefix, 'Recording already stopped.');
return;
}
this.metrics[metricName].end = this.perf.now();
this.perf.mark(metricName, "end");
this.perf.mark(metricName, 'end');
var duration = this.perf.measure(metricName, this.metrics);

@@ -93,6 +110,7 @@ if (this.config.logging) {

* @param {string} metricName
* @return {Promise<number>}
*/
Perfume.prototype.endPaint = function (metricName) {
var _this = this;
return new Promise(function (resolve, reject) {
return new Promise(function (resolve) {
setTimeout(function () {

@@ -112,7 +130,7 @@ var duration = _this.end(metricName);

if (!metricName) {
window.console.warn(this.config.logPrefix, "Please provide a metric name");
window.console.warn(this.config.logPrefix, 'Please provide a metric name');
return;
}
var durationMs = duration.toFixed(2);
var style = "color: #ff6d00;font-size:12px;";
var style = 'color: #ff6d00;font-size:12px;';
var text = "%c " + this.config.logPrefix + " " + metricName + " " + durationMs + " ms";

@@ -123,2 +141,3 @@ window.console.log(text, style);

* @param {string} metricName
* @return {boolean}
*/

@@ -129,9 +148,11 @@ Perfume.prototype.checkMetricName = function (metricName) {

}
window.console.warn(this.config.logPrefix, "Please provide a metric name");
window.console.warn(this.config.logPrefix, 'Please provide a metric name');
return false;
};
/**
* @param {object} entry
* @param {Array<PerformancePaintTiming>} entries
* @param {(value: any) => void} resolve
* @param {(error: any) => void} reject
*/
Perfume.prototype.firstContentfulPaintCb = function (entries) {
Perfume.prototype.firstContentfulPaintCb = function (entries, resolve, reject) {
var _this = this;

@@ -141,10 +162,10 @@ var firstContentfulPaintDuration;

if (_this.config.firstPaint
&& performancePaintTiming.name === "first-paint") {
_this.logFCP(performancePaintTiming.startTime, "First Paint", "firstPaint");
&& performancePaintTiming.name === 'first-paint') {
_this.logFCP(performancePaintTiming.startTime, 'First Paint', 'firstPaint');
}
if (_this.config.firstContentfulPaint
&& performancePaintTiming.name === "first-contentful-paint") {
_this.logFCP(performancePaintTiming.startTime, "First Contentful Paint", "firstContentfulPaint");
&& performancePaintTiming.name === 'first-contentful-paint') {
_this.logFCP(performancePaintTiming.startTime, 'First Contentful Paint', 'firstContentfulPaint');
}
if (performancePaintTiming.name === "first-contentful-paint") {
if (performancePaintTiming.name === 'first-contentful-paint') {
firstContentfulPaintDuration = performancePaintTiming.startTime;

@@ -158,3 +179,6 @@ }

&& firstContentfulPaintDuration) {
this.perf.timeToInteractive(firstContentfulPaintDuration, this.timeToInteractiveCb.bind(this));
this.perf.timeToInteractive(firstContentfulPaintDuration).then(function (time) {
resolve(time);
_this.timeToInteractiveCb(time);
}).catch(reject);
}

@@ -168,17 +192,16 @@ };

if (this.timeToInteractiveDuration) {
this.log("Time to interactive", this.timeToInteractiveDuration);
this.log('Time to interactive', this.timeToInteractiveDuration);
}
if (this.config.timeToInteractiveCb) {
this.config.timeToInteractiveCb(this.timeToInteractiveDuration);
}
this.sendTiming("timeToInteractive", this.timeToInteractiveDuration);
this.sendTiming('timeToInteractive', this.timeToInteractiveDuration);
};
/**
* @param {number} duration
* @param {string} logText
* @param {string} metricName
*/
Perfume.prototype.logFCP = function (duration, logText, metricName) {
if (metricName === "firstPaint") {
if (metricName === 'firstPaint') {
this.firstPaintDuration = duration;
}
if (metricName === "firstContentfulPaint") {
if (metricName === 'firstContentfulPaint') {
this.firstContentfulPaintDuration = duration;

@@ -203,7 +226,7 @@ }

if (!window.ga) {
window.console.warn(this.config.logPrefix, "Google Analytics has not been loaded");
window.console.warn(this.config.logPrefix, 'Google Analytics has not been loaded');
return;
}
var durationInteger = Math.round(duration);
window.ga("send", "timing", metricName, this.config.googleAnalytics.timingVar, durationInteger);
window.ga('send', 'timing', metricName, this.config.googleAnalytics.timingVar, durationInteger);
};

@@ -210,0 +233,0 @@ return Perfume;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var EmulatedPerformance = /** @class */ (function () {
function EmulatedPerformance() {
function EmulatedPerformance(config) {
this.config = config;
}

@@ -10,3 +11,3 @@ /**

*
* @type {number}
* @return {number}
*/

@@ -25,3 +26,4 @@ EmulatedPerformance.prototype.now = function () {

* @param {string} metricName
* @param {object} metrics
* @param {Metrics} metrics
* @return {number}
*/

@@ -36,3 +38,3 @@ EmulatedPerformance.prototype.measure = function (metricName, metrics) {

*
* @param {any} cb
* @param {(entries: any[]) => void} cb
*/

@@ -50,3 +52,4 @@ EmulatedPerformance.prototype.firstContentfulPaint = function (cb) {

* @param {string} metricName
* @param {metrics} any
* @param {Metrics} metrics
* @return {number}
*/

@@ -61,3 +64,3 @@ EmulatedPerformance.prototype.getDurationByMetric = function (metricName, metrics) {

*
* @param {PerformancePaintTiming} performancePaintTiming
* @return {PerformancePaintTiming[]}
*/

@@ -68,4 +71,4 @@ EmulatedPerformance.prototype.getFirstPaint = function () {

duration: 0,
entryType: "paint",
name: "first-contentful-paint",
entryType: 'paint',
name: 'first-contentful-paint',
startTime: 0,

@@ -72,0 +75,0 @@ };

@@ -5,3 +5,4 @@ "use strict";

var Performance = /** @class */ (function () {
function Performance() {
function Performance(config) {
this.config = config;
this.timeToInteractiveDuration = 0;

@@ -18,3 +19,3 @@ this.ttiPolyfill = tti_polyfill_1.default;

*
* @type {boolean}
* @return {boolean}
*/

@@ -31,3 +32,3 @@ Performance.supported = function () {

*
* @type {boolean}
* @return {boolean}
*/

@@ -41,6 +42,6 @@ Performance.supportedPerformanceObserver = function () {

*
* @type {boolean}
* @return {boolean}
*/
Performance.supportedLongTask = function () {
return "PerformanceLongTaskTiming" in window;
return 'PerformanceLongTaskTiming' in window;
};

@@ -51,3 +52,3 @@ /**

* thousandths of a millisecond (5 microseconds).
* @type {number}
* @return {number}
*/

@@ -67,4 +68,4 @@ Performance.prototype.now = function () {

* @param {string} metricName
* @param {object} metrics
* @param {string} endMark
* @param {Metrics} metrics
* @return {number}
*/

@@ -84,9 +85,26 @@ Performance.prototype.measure = function (metricName, metrics) {

*
* @param {any} cb
* @param {(entries: any[]) => void} cb
*/
Performance.prototype.firstContentfulPaint = function (cb) {
this.perfObserver = new PerformanceObserver(this.performanceObserverCb.bind(this, cb));
this.perfObserver.observe({ entryTypes: ["paint"] });
this.perfObserver.observe({ entryTypes: ['paint'] });
};
/**
* The polyfill exposes a getFirstConsistentlyInteractive() method,
* which returns a promise that resolves with the TTI value.
*
* The getFirstConsistentlyInteractive() method accepts an optional
* startTime configuration option, allowing you to specify a lower bound
* for which you know your app cannot be interactive before.
* By default the polyfill uses DOMContentLoaded as the start time,
* but it's often more accurate to use something like the moment your hero elements
* are visible or the point when you know all your event listeners have been added.
*
* @param {number} minValue
* @return {Promise<number>}
*/
Performance.prototype.timeToInteractive = function (minValue) {
return this.ttiPolyfill.getFirstConsistentlyInteractive({ minValue: minValue });
};
/**
* Get the duration of the timing metric or -1 if there a measurement has

@@ -96,7 +114,8 @@ * not been made by the User Timing API

* @param {string} metricName
* @param {any} metrics
* @param {Metrics} metrics
* @return {number}
*/
Performance.prototype.getDurationByMetric = function (metricName, metrics) {
var entry = this.getMeasurementForGivenName(metricName);
if (entry && entry.entryType === "measure") {
if (entry && entry.entryType === 'measure') {
return entry.duration;

@@ -116,3 +135,3 @@ }

/**
* @param {any} cb
* @param {(entries: PerformanceEntry[]) => void} cb
* @param {PerformanceObserverEntryList} entryList

@@ -126,3 +145,3 @@ */

if (_this.config.firstContentfulPaint
&& performancePaintTiming.name === "first-contentful-paint") {
&& performancePaintTiming.name === 'first-contentful-paint') {
_this.perfObserver.disconnect();

@@ -132,19 +151,2 @@ }

};
/**
* The polyfill exposes a getFirstConsistentlyInteractive() method,
* which returns a promise that resolves with the TTI value.
*
* The getFirstConsistentlyInteractive() method accepts an optional
* startTime configuration option, allowing you to specify a lower bound
* for which you know your app cannot be interactive before.
* By default the polyfill uses DOMContentLoaded as the start time,
* but it's often more accurate to use something like the moment your hero elements
* are visible or the point when you know all your event listeners have been added.
*
* @param {number} minValue
* @param {any} cb
*/
Performance.prototype.timeToInteractive = function (minValue, cb) {
this.ttiPolyfill.getFirstConsistentlyInteractive({ minValue: minValue }).then(cb);
};
return Performance;

@@ -151,0 +153,0 @@ }());

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/*!
* Perfume.js v0.6.4 (http://zizzamia.github.io/perfume)
* Perfume.js v0.7.0 (http://zizzamia.github.io/perfume)
* Copyright 2018 The Perfume Authors (https://github.com/Zizzamia/perfume.js/graphs/contributors)

@@ -12,4 +12,9 @@ * Licensed under MIT (https://github.com/Zizzamia/perfume.js/blob/master/LICENSE)

var Perfume = /** @class */ (function () {
/**
* @constructor
* @param options
*/
function Perfume(options) {
if (options === void 0) { options = {}; }
var _this = this;
this.config = {

@@ -20,5 +25,5 @@ firstContentfulPaint: false,

enable: false,
timingVar: "name",
timingVar: 'name',
},
logPrefix: "⚡️ Perfume.js:",
logPrefix: '⚡️ Perfume.js:',
logging: true,

@@ -33,14 +38,25 @@ timeToInteractive: false,

// Init performance implementation
this.perf = performance_1.default.supported() ? new performance_1.default() : new emulated_performance_1.default();
this.perf.config = this.config;
// Init First Contentful Paint
if (performance_1.default.supportedPerformanceObserver()) {
this.perf.firstContentfulPaint(this.firstContentfulPaintCb.bind(this));
}
else {
this.perfEmulated = new emulated_performance_1.default();
this.perfEmulated.firstContentfulPaint(this.firstContentfulPaintCb.bind(this));
}
this.perf = performance_1.default.supported() ? new performance_1.default(this.config) : new emulated_performance_1.default(this.config);
this.timeToInteractivePromise = new Promise(function (resolve, reject) {
// Init First Contentful Paint
if (performance_1.default.supportedPerformanceObserver()) {
_this.perf.firstContentfulPaint(function (entries) {
_this.firstContentfulPaintCb(entries, resolve, reject);
});
}
else {
_this.perfEmulated = new emulated_performance_1.default(_this.config);
_this.perfEmulated.firstContentfulPaint(function (entries) {
_this.firstContentfulPaintCb(entries, resolve, reject);
});
}
});
}
/**
* @return {Promise<number>}
*/
Perfume.prototype.observeTimeToInteractive = function () {
return this.timeToInteractivePromise;
};
/**
* Start performance measurement

@@ -55,3 +71,3 @@ *

if (this.metrics[metricName]) {
window.console.warn(this.config.logPrefix, "Recording already started.");
window.console.warn(this.config.logPrefix, 'Recording already started.');
return;

@@ -63,3 +79,3 @@ }

};
this.perf.mark(metricName, "start");
this.perf.mark(metricName, 'start');
};

@@ -70,2 +86,3 @@ /**

* @param {string} metricName
* @return {void|number}
*/

@@ -77,7 +94,7 @@ Perfume.prototype.end = function (metricName) {

if (!this.metrics[metricName]) {
window.console.warn(this.config.logPrefix, "Recording already stopped.");
window.console.warn(this.config.logPrefix, 'Recording already stopped.');
return;
}
this.metrics[metricName].end = this.perf.now();
this.perf.mark(metricName, "end");
this.perf.mark(metricName, 'end');
var duration = this.perf.measure(metricName, this.metrics);

@@ -95,6 +112,7 @@ if (this.config.logging) {

* @param {string} metricName
* @return {Promise<number>}
*/
Perfume.prototype.endPaint = function (metricName) {
var _this = this;
return new Promise(function (resolve, reject) {
return new Promise(function (resolve) {
setTimeout(function () {

@@ -114,7 +132,7 @@ var duration = _this.end(metricName);

if (!metricName) {
window.console.warn(this.config.logPrefix, "Please provide a metric name");
window.console.warn(this.config.logPrefix, 'Please provide a metric name');
return;
}
var durationMs = duration.toFixed(2);
var style = "color: #ff6d00;font-size:12px;";
var style = 'color: #ff6d00;font-size:12px;';
var text = "%c " + this.config.logPrefix + " " + metricName + " " + durationMs + " ms";

@@ -125,2 +143,3 @@ window.console.log(text, style);

* @param {string} metricName
* @return {boolean}
*/

@@ -131,9 +150,11 @@ Perfume.prototype.checkMetricName = function (metricName) {

}
window.console.warn(this.config.logPrefix, "Please provide a metric name");
window.console.warn(this.config.logPrefix, 'Please provide a metric name');
return false;
};
/**
* @param {object} entry
* @param {Array<PerformancePaintTiming>} entries
* @param {(value: any) => void} resolve
* @param {(error: any) => void} reject
*/
Perfume.prototype.firstContentfulPaintCb = function (entries) {
Perfume.prototype.firstContentfulPaintCb = function (entries, resolve, reject) {
var _this = this;

@@ -143,10 +164,10 @@ var firstContentfulPaintDuration;

if (_this.config.firstPaint
&& performancePaintTiming.name === "first-paint") {
_this.logFCP(performancePaintTiming.startTime, "First Paint", "firstPaint");
&& performancePaintTiming.name === 'first-paint') {
_this.logFCP(performancePaintTiming.startTime, 'First Paint', 'firstPaint');
}
if (_this.config.firstContentfulPaint
&& performancePaintTiming.name === "first-contentful-paint") {
_this.logFCP(performancePaintTiming.startTime, "First Contentful Paint", "firstContentfulPaint");
&& performancePaintTiming.name === 'first-contentful-paint') {
_this.logFCP(performancePaintTiming.startTime, 'First Contentful Paint', 'firstContentfulPaint');
}
if (performancePaintTiming.name === "first-contentful-paint") {
if (performancePaintTiming.name === 'first-contentful-paint') {
firstContentfulPaintDuration = performancePaintTiming.startTime;

@@ -160,3 +181,6 @@ }

&& firstContentfulPaintDuration) {
this.perf.timeToInteractive(firstContentfulPaintDuration, this.timeToInteractiveCb.bind(this));
this.perf.timeToInteractive(firstContentfulPaintDuration).then(function (time) {
resolve(time);
_this.timeToInteractiveCb(time);
}).catch(reject);
}

@@ -170,17 +194,16 @@ };

if (this.timeToInteractiveDuration) {
this.log("Time to interactive", this.timeToInteractiveDuration);
this.log('Time to interactive', this.timeToInteractiveDuration);
}
if (this.config.timeToInteractiveCb) {
this.config.timeToInteractiveCb(this.timeToInteractiveDuration);
}
this.sendTiming("timeToInteractive", this.timeToInteractiveDuration);
this.sendTiming('timeToInteractive', this.timeToInteractiveDuration);
};
/**
* @param {number} duration
* @param {string} logText
* @param {string} metricName
*/
Perfume.prototype.logFCP = function (duration, logText, metricName) {
if (metricName === "firstPaint") {
if (metricName === 'firstPaint') {
this.firstPaintDuration = duration;
}
if (metricName === "firstContentfulPaint") {
if (metricName === 'firstContentfulPaint') {
this.firstContentfulPaintDuration = duration;

@@ -205,7 +228,7 @@ }

if (!window.ga) {
window.console.warn(this.config.logPrefix, "Google Analytics has not been loaded");
window.console.warn(this.config.logPrefix, 'Google Analytics has not been loaded');
return;
}
var durationInteger = Math.round(duration);
window.ga("send", "timing", metricName, this.config.googleAnalytics.timingVar, durationInteger);
window.ga('send', 'timing', metricName, this.config.googleAnalytics.timingVar, durationInteger);
};

@@ -212,0 +235,0 @@ return Perfume;

@@ -0,3 +1,6 @@

import ttiPolyfill from 'tti-polyfill';
var EmulatedPerformance = /** @class */ (function () {
function EmulatedPerformance() {
function EmulatedPerformance(config) {
this.config = config;
}

@@ -8,3 +11,3 @@ /**

*
* @type {number}
* @return {number}
*/

@@ -23,3 +26,4 @@ EmulatedPerformance.prototype.now = function () {

* @param {string} metricName
* @param {object} metrics
* @param {Metrics} metrics
* @return {number}
*/

@@ -34,3 +38,3 @@ EmulatedPerformance.prototype.measure = function (metricName, metrics) {

*
* @param {any} cb
* @param {(entries: any[]) => void} cb
*/

@@ -48,3 +52,4 @@ EmulatedPerformance.prototype.firstContentfulPaint = function (cb) {

* @param {string} metricName
* @param {metrics} any
* @param {Metrics} metrics
* @return {number}
*/

@@ -59,3 +64,3 @@ EmulatedPerformance.prototype.getDurationByMetric = function (metricName, metrics) {

*
* @param {PerformancePaintTiming} performancePaintTiming
* @return {PerformancePaintTiming[]}
*/

@@ -66,4 +71,4 @@ EmulatedPerformance.prototype.getFirstPaint = function () {

duration: 0,
entryType: "paint",
name: "first-contentful-paint",
entryType: 'paint',
name: 'first-contentful-paint',
startTime: 0,

@@ -79,27 +84,5 @@ };

var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
var ttiPolyfill = createCommonjsModule(function (module) {
(function(){var h="undefined"!=typeof window&&window===this?this:"undefined"!=typeof commonjsGlobal&&null!=commonjsGlobal?commonjsGlobal:this,k="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){a!=Array.prototype&&a!=Object.prototype&&(a[b]=c.value);};function l(){l=function(){};h.Symbol||(h.Symbol=m);}var n=0;function m(a){return"jscomp_symbol_"+(a||"")+n++}
function p(){l();var a=h.Symbol.iterator;a||(a=h.Symbol.iterator=h.Symbol("iterator"));"function"!=typeof Array.prototype[a]&&k(Array.prototype,a,{configurable:!0,writable:!0,value:function(){return q(this)}});p=function(){};}function q(a){var b=0;return r(function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}})}function r(a){p();a={next:a};a[h.Symbol.iterator]=function(){return this};return a}function t(a){p();var b=a[Symbol.iterator];return b?b.call(a):q(a)}
function u(a){if(!(a instanceof Array)){a=t(a);for(var b,c=[];!(b=a.next()).done;)c.push(b.value);a=c;}return a}var v=0;function w(a,b){var c=XMLHttpRequest.prototype.send,d=v++;XMLHttpRequest.prototype.send=function(f){for(var e=[],g=0;g<arguments.length;++g)e[g-0]=arguments[g];var E=this;a(d);this.addEventListener("readystatechange",function(){4===E.readyState&&b(d);});return c.apply(this,e)};}
function x(a,b){var c=fetch;fetch=function(d){for(var f=[],e=0;e<arguments.length;++e)f[e-0]=arguments[e];return new Promise(function(d,e){var g=v++;a(g);c.apply(null,[].concat(u(f))).then(function(a){b(g);d(a);},function(a){b(a);e(a);});})};}var y="img script iframe link audio video source".split(" ");function z(a,b){a=t(a);for(var c=a.next();!c.done;c=a.next())if(c=c.value, b.includes(c.nodeName.toLowerCase())||z(c.children,b))return!0;return!1}
function A(a){var b=new MutationObserver(function(c){c=t(c);for(var b=c.next();!b.done;b=c.next())b=b.value, "childList"==b.type&&z(b.addedNodes,y)?a(b):"attributes"==b.type&&y.includes(b.target.tagName.toLowerCase())&&a(b);});b.observe(document,{attributes:!0,childList:!0,subtree:!0,attributeFilter:["href","src"]});return b}
function B(a,b){if(2<a.length)return performance.now();var c=[];b=t(b);for(var d=b.next();!d.done;d=b.next())d=d.value, c.push({timestamp:d.start,type:"requestStart"}), c.push({timestamp:d.end,type:"requestEnd"});b=t(a);for(d=b.next();!d.done;d=b.next())c.push({timestamp:d.value,type:"requestStart"});c.sort(function(a,b){return a.timestamp-b.timestamp});a=a.length;for(b=c.length-1;0<=b;b--)switch(d=c[b], d.type){case "requestStart":a--;break;case "requestEnd":a++;if(2<a)return d.timestamp;break;default:throw Error("Internal Error: This should never happen");
}return 0}function C(a){a=a?a:{};this.w=!!a.useMutationObserver;this.u=a.minValue||null;a=window.__tti&&window.__tti.e;var b=window.__tti&&window.__tti.o;this.a=a?a.map(function(a){return{start:a.startTime,end:a.startTime+a.duration}}):[];b&&b.disconnect();this.b=[];this.f=new Map;this.j=null;this.v=-Infinity;this.i=!1;this.h=this.c=this.s=null;w(this.m.bind(this),this.l.bind(this));x(this.m.bind(this),this.l.bind(this));D(this);this.w&&(this.h=A(this.B.bind(this)));}
C.prototype.getFirstConsistentlyInteractive=function(){var a=this;return new Promise(function(b){a.s=b;"complete"==document.readyState?F(a):window.addEventListener("load",function(){F(a);});})};function F(a){a.i=!0;var b=0<a.a.length?a.a[a.a.length-1].end:0,c=B(a.g,a.b);G(a,Math.max(c+5E3,b));}
function G(a,b){!a.i||a.v>b||(clearTimeout(a.j), a.j=setTimeout(function(){var b=performance.timing.navigationStart,d=B(a.g,a.b),b=(window.a&&window.a.A?1E3*window.a.A().C-b:0)||performance.timing.domContentLoadedEventEnd-b;if(a.u)var f=a.u;else performance.timing.domContentLoadedEventEnd?(f=performance.timing, f=f.domContentLoadedEventEnd-f.navigationStart):f=null;var e=performance.now();null===f&&G(a,Math.max(d+5E3,e+1E3));var g=a.a;5E3>e-d?d=null:(d=g.length?g[g.length-1].end:b, d=5E3>e-d?null:Math.max(d,
f));d&&(a.s(d), clearTimeout(a.j), a.i=!1, a.c&&a.c.disconnect(), a.h&&a.h.disconnect());G(a,performance.now()+1E3);},b-performance.now()), a.v=b);}
function D(a){a.c=new PerformanceObserver(function(b){b=t(b.getEntries());for(var c=b.next();!c.done;c=b.next())if(c=c.value, "resource"===c.entryType&&(a.b.push({start:c.fetchStart,end:c.responseEnd}), G(a,B(a.g,a.b)+5E3)), "longtask"===c.entryType){var d=c.startTime+c.duration;a.a.push({start:c.startTime,end:d});G(a,d+5E3);}});a.c.observe({entryTypes:["longtask","resource"]});}C.prototype.m=function(a){this.f.set(a,performance.now());};C.prototype.l=function(a){this.f.delete(a);};
C.prototype.B=function(){G(this,performance.now()+5E3);};h.Object.defineProperties(C.prototype,{g:{configurable:!0,enumerable:!0,get:function(){return[].concat(u(this.f.values()))}}});var H={getFirstConsistentlyInteractive:function(a){a=a?a:{};return"PerformanceLongTaskTiming"in window?(new C(a)).getFirstConsistentlyInteractive():Promise.resolve(null)}};
"undefined"!='object'&&module.exports?module.exports=H:"function"===typeof undefined&&undefined.amd?undefined("ttiPolyfill",[],function(){return H}):window.ttiPolyfill=H;})();
});
var Performance = /** @class */ (function () {
function Performance() {
function Performance(config) {
this.config = config;
this.timeToInteractiveDuration = 0;

@@ -116,3 +99,3 @@ this.ttiPolyfill = ttiPolyfill;

*
* @type {boolean}
* @return {boolean}
*/

@@ -129,3 +112,3 @@ Performance.supported = function () {

*
* @type {boolean}
* @return {boolean}
*/

@@ -139,6 +122,6 @@ Performance.supportedPerformanceObserver = function () {

*
* @type {boolean}
* @return {boolean}
*/
Performance.supportedLongTask = function () {
return "PerformanceLongTaskTiming" in window;
return 'PerformanceLongTaskTiming' in window;
};

@@ -149,3 +132,3 @@ /**

* thousandths of a millisecond (5 microseconds).
* @type {number}
* @return {number}
*/

@@ -165,4 +148,4 @@ Performance.prototype.now = function () {

* @param {string} metricName
* @param {object} metrics
* @param {string} endMark
* @param {Metrics} metrics
* @return {number}
*/

@@ -182,9 +165,26 @@ Performance.prototype.measure = function (metricName, metrics) {

*
* @param {any} cb
* @param {(entries: any[]) => void} cb
*/
Performance.prototype.firstContentfulPaint = function (cb) {
this.perfObserver = new PerformanceObserver(this.performanceObserverCb.bind(this, cb));
this.perfObserver.observe({ entryTypes: ["paint"] });
this.perfObserver.observe({ entryTypes: ['paint'] });
};
/**
* The polyfill exposes a getFirstConsistentlyInteractive() method,
* which returns a promise that resolves with the TTI value.
*
* The getFirstConsistentlyInteractive() method accepts an optional
* startTime configuration option, allowing you to specify a lower bound
* for which you know your app cannot be interactive before.
* By default the polyfill uses DOMContentLoaded as the start time,
* but it's often more accurate to use something like the moment your hero elements
* are visible or the point when you know all your event listeners have been added.
*
* @param {number} minValue
* @return {Promise<number>}
*/
Performance.prototype.timeToInteractive = function (minValue) {
return this.ttiPolyfill.getFirstConsistentlyInteractive({ minValue: minValue });
};
/**
* Get the duration of the timing metric or -1 if there a measurement has

@@ -194,7 +194,8 @@ * not been made by the User Timing API

* @param {string} metricName
* @param {any} metrics
* @param {Metrics} metrics
* @return {number}
*/
Performance.prototype.getDurationByMetric = function (metricName, metrics) {
var entry = this.getMeasurementForGivenName(metricName);
if (entry && entry.entryType === "measure") {
if (entry && entry.entryType === 'measure') {
return entry.duration;

@@ -214,3 +215,3 @@ }

/**
* @param {any} cb
* @param {(entries: PerformanceEntry[]) => void} cb
* @param {PerformanceObserverEntryList} entryList

@@ -224,3 +225,3 @@ */

if (_this.config.firstContentfulPaint
&& performancePaintTiming.name === "first-contentful-paint") {
&& performancePaintTiming.name === 'first-contentful-paint') {
_this.perfObserver.disconnect();

@@ -230,19 +231,2 @@ }

};
/**
* The polyfill exposes a getFirstConsistentlyInteractive() method,
* which returns a promise that resolves with the TTI value.
*
* The getFirstConsistentlyInteractive() method accepts an optional
* startTime configuration option, allowing you to specify a lower bound
* for which you know your app cannot be interactive before.
* By default the polyfill uses DOMContentLoaded as the start time,
* but it's often more accurate to use something like the moment your hero elements
* are visible or the point when you know all your event listeners have been added.
*
* @param {number} minValue
* @param {any} cb
*/
Performance.prototype.timeToInteractive = function (minValue, cb) {
this.ttiPolyfill.getFirstConsistentlyInteractive({ minValue: minValue }).then(cb);
};
return Performance;

@@ -252,3 +236,3 @@ }());

/*!
* Perfume.js v0.6.4 (http://zizzamia.github.io/perfume)
* Perfume.js v0.7.0 (http://zizzamia.github.io/perfume)
* Copyright 2018 The Perfume Authors (https://github.com/Zizzamia/perfume.js/graphs/contributors)

@@ -259,4 +243,9 @@ * Licensed under MIT (https://github.com/Zizzamia/perfume.js/blob/master/LICENSE)

var Perfume = /** @class */ (function () {
/**
* @constructor
* @param options
*/
function Perfume(options) {
if (options === void 0) { options = {}; }
var _this = this;
this.config = {

@@ -267,5 +256,5 @@ firstContentfulPaint: false,

enable: false,
timingVar: "name",
timingVar: 'name',
},
logPrefix: "⚡️ Perfume.js:",
logPrefix: '⚡️ Perfume.js:',
logging: true,

@@ -280,14 +269,25 @@ timeToInteractive: false,

// Init performance implementation
this.perf = Performance.supported() ? new Performance() : new EmulatedPerformance();
this.perf.config = this.config;
// Init First Contentful Paint
if (Performance.supportedPerformanceObserver()) {
this.perf.firstContentfulPaint(this.firstContentfulPaintCb.bind(this));
}
else {
this.perfEmulated = new EmulatedPerformance();
this.perfEmulated.firstContentfulPaint(this.firstContentfulPaintCb.bind(this));
}
this.perf = Performance.supported() ? new Performance(this.config) : new EmulatedPerformance(this.config);
this.timeToInteractivePromise = new Promise(function (resolve, reject) {
// Init First Contentful Paint
if (Performance.supportedPerformanceObserver()) {
_this.perf.firstContentfulPaint(function (entries) {
_this.firstContentfulPaintCb(entries, resolve, reject);
});
}
else {
_this.perfEmulated = new EmulatedPerformance(_this.config);
_this.perfEmulated.firstContentfulPaint(function (entries) {
_this.firstContentfulPaintCb(entries, resolve, reject);
});
}
});
}
/**
* @return {Promise<number>}
*/
Perfume.prototype.observeTimeToInteractive = function () {
return this.timeToInteractivePromise;
};
/**
* Start performance measurement

@@ -302,3 +302,3 @@ *

if (this.metrics[metricName]) {
window.console.warn(this.config.logPrefix, "Recording already started.");
window.console.warn(this.config.logPrefix, 'Recording already started.');
return;

@@ -310,3 +310,3 @@ }

};
this.perf.mark(metricName, "start");
this.perf.mark(metricName, 'start');
};

@@ -317,2 +317,3 @@ /**

* @param {string} metricName
* @return {void|number}
*/

@@ -324,7 +325,7 @@ Perfume.prototype.end = function (metricName) {

if (!this.metrics[metricName]) {
window.console.warn(this.config.logPrefix, "Recording already stopped.");
window.console.warn(this.config.logPrefix, 'Recording already stopped.');
return;
}
this.metrics[metricName].end = this.perf.now();
this.perf.mark(metricName, "end");
this.perf.mark(metricName, 'end');
var duration = this.perf.measure(metricName, this.metrics);

@@ -342,6 +343,7 @@ if (this.config.logging) {

* @param {string} metricName
* @return {Promise<number>}
*/
Perfume.prototype.endPaint = function (metricName) {
var _this = this;
return new Promise(function (resolve, reject) {
return new Promise(function (resolve) {
setTimeout(function () {

@@ -361,7 +363,7 @@ var duration = _this.end(metricName);

if (!metricName) {
window.console.warn(this.config.logPrefix, "Please provide a metric name");
window.console.warn(this.config.logPrefix, 'Please provide a metric name');
return;
}
var durationMs = duration.toFixed(2);
var style = "color: #ff6d00;font-size:12px;";
var style = 'color: #ff6d00;font-size:12px;';
var text = "%c " + this.config.logPrefix + " " + metricName + " " + durationMs + " ms";

@@ -372,2 +374,3 @@ window.console.log(text, style);

* @param {string} metricName
* @return {boolean}
*/

@@ -378,9 +381,11 @@ Perfume.prototype.checkMetricName = function (metricName) {

}
window.console.warn(this.config.logPrefix, "Please provide a metric name");
window.console.warn(this.config.logPrefix, 'Please provide a metric name');
return false;
};
/**
* @param {object} entry
* @param {Array<PerformancePaintTiming>} entries
* @param {(value: any) => void} resolve
* @param {(error: any) => void} reject
*/
Perfume.prototype.firstContentfulPaintCb = function (entries) {
Perfume.prototype.firstContentfulPaintCb = function (entries, resolve, reject) {
var _this = this;

@@ -390,10 +395,10 @@ var firstContentfulPaintDuration;

if (_this.config.firstPaint
&& performancePaintTiming.name === "first-paint") {
_this.logFCP(performancePaintTiming.startTime, "First Paint", "firstPaint");
&& performancePaintTiming.name === 'first-paint') {
_this.logFCP(performancePaintTiming.startTime, 'First Paint', 'firstPaint');
}
if (_this.config.firstContentfulPaint
&& performancePaintTiming.name === "first-contentful-paint") {
_this.logFCP(performancePaintTiming.startTime, "First Contentful Paint", "firstContentfulPaint");
&& performancePaintTiming.name === 'first-contentful-paint') {
_this.logFCP(performancePaintTiming.startTime, 'First Contentful Paint', 'firstContentfulPaint');
}
if (performancePaintTiming.name === "first-contentful-paint") {
if (performancePaintTiming.name === 'first-contentful-paint') {
firstContentfulPaintDuration = performancePaintTiming.startTime;

@@ -407,3 +412,6 @@ }

&& firstContentfulPaintDuration) {
this.perf.timeToInteractive(firstContentfulPaintDuration, this.timeToInteractiveCb.bind(this));
this.perf.timeToInteractive(firstContentfulPaintDuration).then(function (time) {
resolve(time);
_this.timeToInteractiveCb(time);
}).catch(reject);
}

@@ -417,17 +425,16 @@ };

if (this.timeToInteractiveDuration) {
this.log("Time to interactive", this.timeToInteractiveDuration);
this.log('Time to interactive', this.timeToInteractiveDuration);
}
if (this.config.timeToInteractiveCb) {
this.config.timeToInteractiveCb(this.timeToInteractiveDuration);
}
this.sendTiming("timeToInteractive", this.timeToInteractiveDuration);
this.sendTiming('timeToInteractive', this.timeToInteractiveDuration);
};
/**
* @param {number} duration
* @param {string} logText
* @param {string} metricName
*/
Perfume.prototype.logFCP = function (duration, logText, metricName) {
if (metricName === "firstPaint") {
if (metricName === 'firstPaint') {
this.firstPaintDuration = duration;
}
if (metricName === "firstContentfulPaint") {
if (metricName === 'firstContentfulPaint') {
this.firstContentfulPaintDuration = duration;

@@ -452,7 +459,7 @@ }

if (!window.ga) {
window.console.warn(this.config.logPrefix, "Google Analytics has not been loaded");
window.console.warn(this.config.logPrefix, 'Google Analytics has not been loaded');
return;
}
var durationInteger = Math.round(duration);
window.ga("send", "timing", metricName, this.config.googleAnalytics.timingVar, durationInteger);
window.ga('send', 'timing', metricName, this.config.googleAnalytics.timingVar, durationInteger);
};

@@ -459,0 +466,0 @@ return Perfume;

@@ -5,3 +5,4 @@ var perfume = (function () {

var EmulatedPerformance = /** @class */ (function () {
function EmulatedPerformance() {
function EmulatedPerformance(config) {
this.config = config;
}

@@ -12,3 +13,3 @@ /**

*
* @type {number}
* @return {number}
*/

@@ -27,3 +28,4 @@ EmulatedPerformance.prototype.now = function () {

* @param {string} metricName
* @param {object} metrics
* @param {Metrics} metrics
* @return {number}
*/

@@ -38,3 +40,3 @@ EmulatedPerformance.prototype.measure = function (metricName, metrics) {

*
* @param {any} cb
* @param {(entries: any[]) => void} cb
*/

@@ -52,3 +54,4 @@ EmulatedPerformance.prototype.firstContentfulPaint = function (cb) {

* @param {string} metricName
* @param {metrics} any
* @param {Metrics} metrics
* @return {number}
*/

@@ -63,3 +66,3 @@ EmulatedPerformance.prototype.getDurationByMetric = function (metricName, metrics) {

*
* @param {PerformancePaintTiming} performancePaintTiming
* @return {PerformancePaintTiming[]}
*/

@@ -70,4 +73,4 @@ EmulatedPerformance.prototype.getFirstPaint = function () {

duration: 0,
entryType: "paint",
name: "first-contentful-paint",
entryType: 'paint',
name: 'first-contentful-paint',
startTime: 0,

@@ -107,3 +110,4 @@ };

var Performance = /** @class */ (function () {
function Performance() {
function Performance(config) {
this.config = config;
this.timeToInteractiveDuration = 0;

@@ -120,3 +124,3 @@ this.ttiPolyfill = ttiPolyfill;

*
* @type {boolean}
* @return {boolean}
*/

@@ -133,3 +137,3 @@ Performance.supported = function () {

*
* @type {boolean}
* @return {boolean}
*/

@@ -143,6 +147,6 @@ Performance.supportedPerformanceObserver = function () {

*
* @type {boolean}
* @return {boolean}
*/
Performance.supportedLongTask = function () {
return "PerformanceLongTaskTiming" in window;
return 'PerformanceLongTaskTiming' in window;
};

@@ -153,3 +157,3 @@ /**

* thousandths of a millisecond (5 microseconds).
* @type {number}
* @return {number}
*/

@@ -169,4 +173,4 @@ Performance.prototype.now = function () {

* @param {string} metricName
* @param {object} metrics
* @param {string} endMark
* @param {Metrics} metrics
* @return {number}
*/

@@ -186,9 +190,26 @@ Performance.prototype.measure = function (metricName, metrics) {

*
* @param {any} cb
* @param {(entries: any[]) => void} cb
*/
Performance.prototype.firstContentfulPaint = function (cb) {
this.perfObserver = new PerformanceObserver(this.performanceObserverCb.bind(this, cb));
this.perfObserver.observe({ entryTypes: ["paint"] });
this.perfObserver.observe({ entryTypes: ['paint'] });
};
/**
* The polyfill exposes a getFirstConsistentlyInteractive() method,
* which returns a promise that resolves with the TTI value.
*
* The getFirstConsistentlyInteractive() method accepts an optional
* startTime configuration option, allowing you to specify a lower bound
* for which you know your app cannot be interactive before.
* By default the polyfill uses DOMContentLoaded as the start time,
* but it's often more accurate to use something like the moment your hero elements
* are visible or the point when you know all your event listeners have been added.
*
* @param {number} minValue
* @return {Promise<number>}
*/
Performance.prototype.timeToInteractive = function (minValue) {
return this.ttiPolyfill.getFirstConsistentlyInteractive({ minValue: minValue });
};
/**
* Get the duration of the timing metric or -1 if there a measurement has

@@ -198,7 +219,8 @@ * not been made by the User Timing API

* @param {string} metricName
* @param {any} metrics
* @param {Metrics} metrics
* @return {number}
*/
Performance.prototype.getDurationByMetric = function (metricName, metrics) {
var entry = this.getMeasurementForGivenName(metricName);
if (entry && entry.entryType === "measure") {
if (entry && entry.entryType === 'measure') {
return entry.duration;

@@ -218,3 +240,3 @@ }

/**
* @param {any} cb
* @param {(entries: PerformanceEntry[]) => void} cb
* @param {PerformanceObserverEntryList} entryList

@@ -228,3 +250,3 @@ */

if (_this.config.firstContentfulPaint
&& performancePaintTiming.name === "first-contentful-paint") {
&& performancePaintTiming.name === 'first-contentful-paint') {
_this.perfObserver.disconnect();

@@ -234,19 +256,2 @@ }

};
/**
* The polyfill exposes a getFirstConsistentlyInteractive() method,
* which returns a promise that resolves with the TTI value.
*
* The getFirstConsistentlyInteractive() method accepts an optional
* startTime configuration option, allowing you to specify a lower bound
* for which you know your app cannot be interactive before.
* By default the polyfill uses DOMContentLoaded as the start time,
* but it's often more accurate to use something like the moment your hero elements
* are visible or the point when you know all your event listeners have been added.
*
* @param {number} minValue
* @param {any} cb
*/
Performance.prototype.timeToInteractive = function (minValue, cb) {
this.ttiPolyfill.getFirstConsistentlyInteractive({ minValue: minValue }).then(cb);
};
return Performance;

@@ -256,3 +261,3 @@ }());

/*!
* Perfume.js v0.6.4 (http://zizzamia.github.io/perfume)
* Perfume.js v0.7.0 (http://zizzamia.github.io/perfume)
* Copyright 2018 The Perfume Authors (https://github.com/Zizzamia/perfume.js/graphs/contributors)

@@ -263,4 +268,9 @@ * Licensed under MIT (https://github.com/Zizzamia/perfume.js/blob/master/LICENSE)

var Perfume = /** @class */ (function () {
/**
* @constructor
* @param options
*/
function Perfume(options) {
if (options === void 0) { options = {}; }
var _this = this;
this.config = {

@@ -271,5 +281,5 @@ firstContentfulPaint: false,

enable: false,
timingVar: "name",
timingVar: 'name',
},
logPrefix: "⚡️ Perfume.js:",
logPrefix: '⚡️ Perfume.js:',
logging: true,

@@ -284,14 +294,25 @@ timeToInteractive: false,

// Init performance implementation
this.perf = Performance.supported() ? new Performance() : new EmulatedPerformance();
this.perf.config = this.config;
// Init First Contentful Paint
if (Performance.supportedPerformanceObserver()) {
this.perf.firstContentfulPaint(this.firstContentfulPaintCb.bind(this));
}
else {
this.perfEmulated = new EmulatedPerformance();
this.perfEmulated.firstContentfulPaint(this.firstContentfulPaintCb.bind(this));
}
this.perf = Performance.supported() ? new Performance(this.config) : new EmulatedPerformance(this.config);
this.timeToInteractivePromise = new Promise(function (resolve, reject) {
// Init First Contentful Paint
if (Performance.supportedPerformanceObserver()) {
_this.perf.firstContentfulPaint(function (entries) {
_this.firstContentfulPaintCb(entries, resolve, reject);
});
}
else {
_this.perfEmulated = new EmulatedPerformance(_this.config);
_this.perfEmulated.firstContentfulPaint(function (entries) {
_this.firstContentfulPaintCb(entries, resolve, reject);
});
}
});
}
/**
* @return {Promise<number>}
*/
Perfume.prototype.observeTimeToInteractive = function () {
return this.timeToInteractivePromise;
};
/**
* Start performance measurement

@@ -306,3 +327,3 @@ *

if (this.metrics[metricName]) {
window.console.warn(this.config.logPrefix, "Recording already started.");
window.console.warn(this.config.logPrefix, 'Recording already started.');
return;

@@ -314,3 +335,3 @@ }

};
this.perf.mark(metricName, "start");
this.perf.mark(metricName, 'start');
};

@@ -321,2 +342,3 @@ /**

* @param {string} metricName
* @return {void|number}
*/

@@ -328,7 +350,7 @@ Perfume.prototype.end = function (metricName) {

if (!this.metrics[metricName]) {
window.console.warn(this.config.logPrefix, "Recording already stopped.");
window.console.warn(this.config.logPrefix, 'Recording already stopped.');
return;
}
this.metrics[metricName].end = this.perf.now();
this.perf.mark(metricName, "end");
this.perf.mark(metricName, 'end');
var duration = this.perf.measure(metricName, this.metrics);

@@ -346,6 +368,7 @@ if (this.config.logging) {

* @param {string} metricName
* @return {Promise<number>}
*/
Perfume.prototype.endPaint = function (metricName) {
var _this = this;
return new Promise(function (resolve, reject) {
return new Promise(function (resolve) {
setTimeout(function () {

@@ -365,7 +388,7 @@ var duration = _this.end(metricName);

if (!metricName) {
window.console.warn(this.config.logPrefix, "Please provide a metric name");
window.console.warn(this.config.logPrefix, 'Please provide a metric name');
return;
}
var durationMs = duration.toFixed(2);
var style = "color: #ff6d00;font-size:12px;";
var style = 'color: #ff6d00;font-size:12px;';
var text = "%c " + this.config.logPrefix + " " + metricName + " " + durationMs + " ms";

@@ -376,2 +399,3 @@ window.console.log(text, style);

* @param {string} metricName
* @return {boolean}
*/

@@ -382,9 +406,11 @@ Perfume.prototype.checkMetricName = function (metricName) {

}
window.console.warn(this.config.logPrefix, "Please provide a metric name");
window.console.warn(this.config.logPrefix, 'Please provide a metric name');
return false;
};
/**
* @param {object} entry
* @param {Array<PerformancePaintTiming>} entries
* @param {(value: any) => void} resolve
* @param {(error: any) => void} reject
*/
Perfume.prototype.firstContentfulPaintCb = function (entries) {
Perfume.prototype.firstContentfulPaintCb = function (entries, resolve, reject) {
var _this = this;

@@ -394,10 +420,10 @@ var firstContentfulPaintDuration;

if (_this.config.firstPaint
&& performancePaintTiming.name === "first-paint") {
_this.logFCP(performancePaintTiming.startTime, "First Paint", "firstPaint");
&& performancePaintTiming.name === 'first-paint') {
_this.logFCP(performancePaintTiming.startTime, 'First Paint', 'firstPaint');
}
if (_this.config.firstContentfulPaint
&& performancePaintTiming.name === "first-contentful-paint") {
_this.logFCP(performancePaintTiming.startTime, "First Contentful Paint", "firstContentfulPaint");
&& performancePaintTiming.name === 'first-contentful-paint') {
_this.logFCP(performancePaintTiming.startTime, 'First Contentful Paint', 'firstContentfulPaint');
}
if (performancePaintTiming.name === "first-contentful-paint") {
if (performancePaintTiming.name === 'first-contentful-paint') {
firstContentfulPaintDuration = performancePaintTiming.startTime;

@@ -411,3 +437,6 @@ }

&& firstContentfulPaintDuration) {
this.perf.timeToInteractive(firstContentfulPaintDuration, this.timeToInteractiveCb.bind(this));
this.perf.timeToInteractive(firstContentfulPaintDuration).then(function (time) {
resolve(time);
_this.timeToInteractiveCb(time);
}).catch(reject);
}

@@ -421,17 +450,16 @@ };

if (this.timeToInteractiveDuration) {
this.log("Time to interactive", this.timeToInteractiveDuration);
this.log('Time to interactive', this.timeToInteractiveDuration);
}
if (this.config.timeToInteractiveCb) {
this.config.timeToInteractiveCb(this.timeToInteractiveDuration);
}
this.sendTiming("timeToInteractive", this.timeToInteractiveDuration);
this.sendTiming('timeToInteractive', this.timeToInteractiveDuration);
};
/**
* @param {number} duration
* @param {string} logText
* @param {string} metricName
*/
Perfume.prototype.logFCP = function (duration, logText, metricName) {
if (metricName === "firstPaint") {
if (metricName === 'firstPaint') {
this.firstPaintDuration = duration;
}
if (metricName === "firstContentfulPaint") {
if (metricName === 'firstContentfulPaint') {
this.firstContentfulPaintDuration = duration;

@@ -456,7 +484,7 @@ }

if (!window.ga) {
window.console.warn(this.config.logPrefix, "Google Analytics has not been loaded");
window.console.warn(this.config.logPrefix, 'Google Analytics has not been loaded');
return;
}
var durationInteger = Math.round(duration);
window.ga("send", "timing", metricName, this.config.googleAnalytics.timingVar, durationInteger);
window.ga('send', 'timing', metricName, this.config.googleAnalytics.timingVar, durationInteger);
};

@@ -463,0 +491,0 @@ return Perfume;

@@ -8,3 +8,4 @@ (function (global, factory) {

var EmulatedPerformance = /** @class */ (function () {
function EmulatedPerformance() {
function EmulatedPerformance(config) {
this.config = config;
}

@@ -15,3 +16,3 @@ /**

*
* @type {number}
* @return {number}
*/

@@ -30,3 +31,4 @@ EmulatedPerformance.prototype.now = function () {

* @param {string} metricName
* @param {object} metrics
* @param {Metrics} metrics
* @return {number}
*/

@@ -41,3 +43,3 @@ EmulatedPerformance.prototype.measure = function (metricName, metrics) {

*
* @param {any} cb
* @param {(entries: any[]) => void} cb
*/

@@ -55,3 +57,4 @@ EmulatedPerformance.prototype.firstContentfulPaint = function (cb) {

* @param {string} metricName
* @param {metrics} any
* @param {Metrics} metrics
* @return {number}
*/

@@ -66,3 +69,3 @@ EmulatedPerformance.prototype.getDurationByMetric = function (metricName, metrics) {

*
* @param {PerformancePaintTiming} performancePaintTiming
* @return {PerformancePaintTiming[]}
*/

@@ -73,4 +76,4 @@ EmulatedPerformance.prototype.getFirstPaint = function () {

duration: 0,
entryType: "paint",
name: "first-contentful-paint",
entryType: 'paint',
name: 'first-contentful-paint',
startTime: 0,

@@ -110,3 +113,4 @@ };

var Performance = /** @class */ (function () {
function Performance() {
function Performance(config) {
this.config = config;
this.timeToInteractiveDuration = 0;

@@ -123,3 +127,3 @@ this.ttiPolyfill = ttiPolyfill;

*
* @type {boolean}
* @return {boolean}
*/

@@ -136,3 +140,3 @@ Performance.supported = function () {

*
* @type {boolean}
* @return {boolean}
*/

@@ -146,6 +150,6 @@ Performance.supportedPerformanceObserver = function () {

*
* @type {boolean}
* @return {boolean}
*/
Performance.supportedLongTask = function () {
return "PerformanceLongTaskTiming" in window;
return 'PerformanceLongTaskTiming' in window;
};

@@ -156,3 +160,3 @@ /**

* thousandths of a millisecond (5 microseconds).
* @type {number}
* @return {number}
*/

@@ -172,4 +176,4 @@ Performance.prototype.now = function () {

* @param {string} metricName
* @param {object} metrics
* @param {string} endMark
* @param {Metrics} metrics
* @return {number}
*/

@@ -189,9 +193,26 @@ Performance.prototype.measure = function (metricName, metrics) {

*
* @param {any} cb
* @param {(entries: any[]) => void} cb
*/
Performance.prototype.firstContentfulPaint = function (cb) {
this.perfObserver = new PerformanceObserver(this.performanceObserverCb.bind(this, cb));
this.perfObserver.observe({ entryTypes: ["paint"] });
this.perfObserver.observe({ entryTypes: ['paint'] });
};
/**
* The polyfill exposes a getFirstConsistentlyInteractive() method,
* which returns a promise that resolves with the TTI value.
*
* The getFirstConsistentlyInteractive() method accepts an optional
* startTime configuration option, allowing you to specify a lower bound
* for which you know your app cannot be interactive before.
* By default the polyfill uses DOMContentLoaded as the start time,
* but it's often more accurate to use something like the moment your hero elements
* are visible or the point when you know all your event listeners have been added.
*
* @param {number} minValue
* @return {Promise<number>}
*/
Performance.prototype.timeToInteractive = function (minValue) {
return this.ttiPolyfill.getFirstConsistentlyInteractive({ minValue: minValue });
};
/**
* Get the duration of the timing metric or -1 if there a measurement has

@@ -201,7 +222,8 @@ * not been made by the User Timing API

* @param {string} metricName
* @param {any} metrics
* @param {Metrics} metrics
* @return {number}
*/
Performance.prototype.getDurationByMetric = function (metricName, metrics) {
var entry = this.getMeasurementForGivenName(metricName);
if (entry && entry.entryType === "measure") {
if (entry && entry.entryType === 'measure') {
return entry.duration;

@@ -221,3 +243,3 @@ }

/**
* @param {any} cb
* @param {(entries: PerformanceEntry[]) => void} cb
* @param {PerformanceObserverEntryList} entryList

@@ -231,3 +253,3 @@ */

if (_this.config.firstContentfulPaint
&& performancePaintTiming.name === "first-contentful-paint") {
&& performancePaintTiming.name === 'first-contentful-paint') {
_this.perfObserver.disconnect();

@@ -237,19 +259,2 @@ }

};
/**
* The polyfill exposes a getFirstConsistentlyInteractive() method,
* which returns a promise that resolves with the TTI value.
*
* The getFirstConsistentlyInteractive() method accepts an optional
* startTime configuration option, allowing you to specify a lower bound
* for which you know your app cannot be interactive before.
* By default the polyfill uses DOMContentLoaded as the start time,
* but it's often more accurate to use something like the moment your hero elements
* are visible or the point when you know all your event listeners have been added.
*
* @param {number} minValue
* @param {any} cb
*/
Performance.prototype.timeToInteractive = function (minValue, cb) {
this.ttiPolyfill.getFirstConsistentlyInteractive({ minValue: minValue }).then(cb);
};
return Performance;

@@ -259,3 +264,3 @@ }());

/*!
* Perfume.js v0.6.4 (http://zizzamia.github.io/perfume)
* Perfume.js v0.7.0 (http://zizzamia.github.io/perfume)
* Copyright 2018 The Perfume Authors (https://github.com/Zizzamia/perfume.js/graphs/contributors)

@@ -266,4 +271,9 @@ * Licensed under MIT (https://github.com/Zizzamia/perfume.js/blob/master/LICENSE)

var Perfume = /** @class */ (function () {
/**
* @constructor
* @param options
*/
function Perfume(options) {
if (options === void 0) { options = {}; }
var _this = this;
this.config = {

@@ -274,5 +284,5 @@ firstContentfulPaint: false,

enable: false,
timingVar: "name",
timingVar: 'name',
},
logPrefix: "⚡️ Perfume.js:",
logPrefix: '⚡️ Perfume.js:',
logging: true,

@@ -287,14 +297,25 @@ timeToInteractive: false,

// Init performance implementation
this.perf = Performance.supported() ? new Performance() : new EmulatedPerformance();
this.perf.config = this.config;
// Init First Contentful Paint
if (Performance.supportedPerformanceObserver()) {
this.perf.firstContentfulPaint(this.firstContentfulPaintCb.bind(this));
}
else {
this.perfEmulated = new EmulatedPerformance();
this.perfEmulated.firstContentfulPaint(this.firstContentfulPaintCb.bind(this));
}
this.perf = Performance.supported() ? new Performance(this.config) : new EmulatedPerformance(this.config);
this.timeToInteractivePromise = new Promise(function (resolve, reject) {
// Init First Contentful Paint
if (Performance.supportedPerformanceObserver()) {
_this.perf.firstContentfulPaint(function (entries) {
_this.firstContentfulPaintCb(entries, resolve, reject);
});
}
else {
_this.perfEmulated = new EmulatedPerformance(_this.config);
_this.perfEmulated.firstContentfulPaint(function (entries) {
_this.firstContentfulPaintCb(entries, resolve, reject);
});
}
});
}
/**
* @return {Promise<number>}
*/
Perfume.prototype.observeTimeToInteractive = function () {
return this.timeToInteractivePromise;
};
/**
* Start performance measurement

@@ -309,3 +330,3 @@ *

if (this.metrics[metricName]) {
window.console.warn(this.config.logPrefix, "Recording already started.");
window.console.warn(this.config.logPrefix, 'Recording already started.');
return;

@@ -317,3 +338,3 @@ }

};
this.perf.mark(metricName, "start");
this.perf.mark(metricName, 'start');
};

@@ -324,2 +345,3 @@ /**

* @param {string} metricName
* @return {void|number}
*/

@@ -331,7 +353,7 @@ Perfume.prototype.end = function (metricName) {

if (!this.metrics[metricName]) {
window.console.warn(this.config.logPrefix, "Recording already stopped.");
window.console.warn(this.config.logPrefix, 'Recording already stopped.');
return;
}
this.metrics[metricName].end = this.perf.now();
this.perf.mark(metricName, "end");
this.perf.mark(metricName, 'end');
var duration = this.perf.measure(metricName, this.metrics);

@@ -349,6 +371,7 @@ if (this.config.logging) {

* @param {string} metricName
* @return {Promise<number>}
*/
Perfume.prototype.endPaint = function (metricName) {
var _this = this;
return new Promise(function (resolve, reject) {
return new Promise(function (resolve) {
setTimeout(function () {

@@ -368,7 +391,7 @@ var duration = _this.end(metricName);

if (!metricName) {
window.console.warn(this.config.logPrefix, "Please provide a metric name");
window.console.warn(this.config.logPrefix, 'Please provide a metric name');
return;
}
var durationMs = duration.toFixed(2);
var style = "color: #ff6d00;font-size:12px;";
var style = 'color: #ff6d00;font-size:12px;';
var text = "%c " + this.config.logPrefix + " " + metricName + " " + durationMs + " ms";

@@ -379,2 +402,3 @@ window.console.log(text, style);

* @param {string} metricName
* @return {boolean}
*/

@@ -385,9 +409,11 @@ Perfume.prototype.checkMetricName = function (metricName) {

}
window.console.warn(this.config.logPrefix, "Please provide a metric name");
window.console.warn(this.config.logPrefix, 'Please provide a metric name');
return false;
};
/**
* @param {object} entry
* @param {Array<PerformancePaintTiming>} entries
* @param {(value: any) => void} resolve
* @param {(error: any) => void} reject
*/
Perfume.prototype.firstContentfulPaintCb = function (entries) {
Perfume.prototype.firstContentfulPaintCb = function (entries, resolve, reject) {
var _this = this;

@@ -397,10 +423,10 @@ var firstContentfulPaintDuration;

if (_this.config.firstPaint
&& performancePaintTiming.name === "first-paint") {
_this.logFCP(performancePaintTiming.startTime, "First Paint", "firstPaint");
&& performancePaintTiming.name === 'first-paint') {
_this.logFCP(performancePaintTiming.startTime, 'First Paint', 'firstPaint');
}
if (_this.config.firstContentfulPaint
&& performancePaintTiming.name === "first-contentful-paint") {
_this.logFCP(performancePaintTiming.startTime, "First Contentful Paint", "firstContentfulPaint");
&& performancePaintTiming.name === 'first-contentful-paint') {
_this.logFCP(performancePaintTiming.startTime, 'First Contentful Paint', 'firstContentfulPaint');
}
if (performancePaintTiming.name === "first-contentful-paint") {
if (performancePaintTiming.name === 'first-contentful-paint') {
firstContentfulPaintDuration = performancePaintTiming.startTime;

@@ -414,3 +440,6 @@ }

&& firstContentfulPaintDuration) {
this.perf.timeToInteractive(firstContentfulPaintDuration, this.timeToInteractiveCb.bind(this));
this.perf.timeToInteractive(firstContentfulPaintDuration).then(function (time) {
resolve(time);
_this.timeToInteractiveCb(time);
}).catch(reject);
}

@@ -424,17 +453,16 @@ };

if (this.timeToInteractiveDuration) {
this.log("Time to interactive", this.timeToInteractiveDuration);
this.log('Time to interactive', this.timeToInteractiveDuration);
}
if (this.config.timeToInteractiveCb) {
this.config.timeToInteractiveCb(this.timeToInteractiveDuration);
}
this.sendTiming("timeToInteractive", this.timeToInteractiveDuration);
this.sendTiming('timeToInteractive', this.timeToInteractiveDuration);
};
/**
* @param {number} duration
* @param {string} logText
* @param {string} metricName
*/
Perfume.prototype.logFCP = function (duration, logText, metricName) {
if (metricName === "firstPaint") {
if (metricName === 'firstPaint') {
this.firstPaintDuration = duration;
}
if (metricName === "firstContentfulPaint") {
if (metricName === 'firstContentfulPaint') {
this.firstContentfulPaintDuration = duration;

@@ -459,7 +487,7 @@ }

if (!window.ga) {
window.console.warn(this.config.logPrefix, "Google Analytics has not been loaded");
window.console.warn(this.config.logPrefix, 'Google Analytics has not been loaded');
return;
}
var durationInteger = Math.round(duration);
window.ga("send", "timing", metricName, this.config.googleAnalytics.timingVar, durationInteger);
window.ga('send', 'timing', metricName, this.config.googleAnalytics.timingVar, durationInteger);
};

@@ -466,0 +494,0 @@ return Perfume;

@@ -1,6 +0,6 @@

import PerformImpl from "./performance-impl";
declare global {
}
import PerformImpl from './performance-impl';
import { Metrics, PerfumeConfig } from './perfume';
export default class EmulatedPerformance implements PerformImpl {
config: any;
config: PerfumeConfig;
constructor(config: PerfumeConfig);
/**

@@ -10,3 +10,3 @@ * When performance API is not available

*
* @type {number}
* @return {number}
*/

@@ -21,5 +21,6 @@ now(): number;

* @param {string} metricName
* @param {object} metrics
* @param {Metrics} metrics
* @return {number}
*/
measure(metricName: string, metrics: object): number;
measure(metricName: string, metrics: Metrics): number;
/**

@@ -30,5 +31,5 @@ * First Paint is essentially the paint after which

*
* @param {any} cb
* @param {(entries: any[]) => void} cb
*/
firstContentfulPaint(cb: any): void;
firstContentfulPaint(cb: (entries: any[]) => void): void;
/**

@@ -39,3 +40,4 @@ * Get the duration of the timing metric or -1 if there a measurement has

* @param {string} metricName
* @param {metrics} any
* @param {Metrics} metrics
* @return {number}
*/

@@ -47,5 +49,5 @@ private getDurationByMetric(metricName, metrics);

*
* @param {PerformancePaintTiming} performancePaintTiming
* @return {PerformancePaintTiming[]}
*/
private getFirstPaint();
}

@@ -0,7 +1,8 @@

import { Metrics, PerfumeConfig } from './perfume';
export default interface PerformImpl {
config: any;
config: PerfumeConfig;
now(): number;
mark(metricName: string, type: string): any;
measure(metricName: string, metrics: object): number;
measure(metricName: string, metrics: Metrics): number;
firstContentfulPaint(cb: any): any;
}

@@ -1,8 +0,5 @@

import PerformImpl from "./performance-impl";
declare global {
interface Window {
chrome: any;
}
}
import PerformImpl from './performance-impl';
import { Metrics, PerfumeConfig } from './perfume';
export default class Performance implements PerformImpl {
config: PerfumeConfig;
/**

@@ -16,3 +13,3 @@ * True if the browser supports the Navigation Timing API,

*
* @type {boolean}
* @return {boolean}
*/

@@ -25,3 +22,3 @@ static supported(): boolean;

*
* @type {boolean}
* @return {boolean}
*/

@@ -33,10 +30,9 @@ static supportedPerformanceObserver(): boolean;

*
* @type {boolean}
* @return {boolean}
*/
static supportedLongTask(): boolean;
timeToInteractiveDuration: number;
config: any;
private ttiPolyfill;
private perfObserver;
constructor();
constructor(config: PerfumeConfig);
/**

@@ -46,3 +42,3 @@ * When performance API available

* thousandths of a millisecond (5 microseconds).
* @type {number}
* @return {number}
*/

@@ -57,6 +53,6 @@ now(): number;

* @param {string} metricName
* @param {object} metrics
* @param {string} endMark
* @param {Metrics} metrics
* @return {number}
*/
measure(metricName: string, metrics: object): any;
measure(metricName: string, metrics: Metrics): number;
/**

@@ -69,6 +65,21 @@ * First Paint is essentially the paint after which

*
* @param {any} cb
* @param {(entries: any[]) => void} cb
*/
firstContentfulPaint(cb: any): any;
firstContentfulPaint(cb: (entries: any[]) => void): void;
/**
* The polyfill exposes a getFirstConsistentlyInteractive() method,
* which returns a promise that resolves with the TTI value.
*
* The getFirstConsistentlyInteractive() method accepts an optional
* startTime configuration option, allowing you to specify a lower bound
* for which you know your app cannot be interactive before.
* By default the polyfill uses DOMContentLoaded as the start time,
* but it's often more accurate to use something like the moment your hero elements
* are visible or the point when you know all your event listeners have been added.
*
* @param {number} minValue
* @return {Promise<number>}
*/
timeToInteractive(minValue: number): Promise<number>;
/**
* Get the duration of the timing metric or -1 if there a measurement has

@@ -78,3 +89,4 @@ * not been made by the User Timing API

* @param {string} metricName
* @param {any} metrics
* @param {Metrics} metrics
* @return {number}
*/

@@ -89,21 +101,6 @@ private getDurationByMetric(metricName, metrics);

/**
* @param {any} cb
* @param {(entries: PerformanceEntry[]) => void} cb
* @param {PerformanceObserverEntryList} entryList
*/
private performanceObserverCb(cb, entryList);
/**
* The polyfill exposes a getFirstConsistentlyInteractive() method,
* which returns a promise that resolves with the TTI value.
*
* The getFirstConsistentlyInteractive() method accepts an optional
* startTime configuration option, allowing you to specify a lower bound
* for which you know your app cannot be interactive before.
* By default the polyfill uses DOMContentLoaded as the start time,
* but it's often more accurate to use something like the moment your hero elements
* are visible or the point when you know all your event listeners have been added.
*
* @param {number} minValue
* @param {any} cb
*/
private timeToInteractive(minValue, cb);
}

@@ -0,1 +1,18 @@

export interface PerfumeConfig {
firstContentfulPaint: boolean;
firstPaint: boolean;
googleAnalytics: {
enable: boolean;
timingVar: string;
};
logPrefix: string;
logging: boolean;
timeToInteractive: boolean;
}
export interface Metrics {
[key: string]: {
start: number;
end: number;
};
}
declare global {

@@ -7,14 +24,3 @@ interface Window {

export default class Perfume {
config: {
firstContentfulPaint: boolean;
firstPaint: boolean;
googleAnalytics: {
enable: boolean;
timingVar: string;
};
logPrefix: string;
logging: boolean;
timeToInteractive: boolean;
timeToInteractiveCb?: any;
};
config: PerfumeConfig;
firstPaintDuration: number;

@@ -25,5 +31,14 @@ firstContentfulPaintDuration: number;

private perf;
private perfEmulated;
private perfEmulated?;
private readonly timeToInteractivePromise;
/**
* @constructor
* @param options
*/
constructor(options?: any);
/**
* @return {Promise<number>}
*/
observeTimeToInteractive(): Promise<number>;
/**
* Start performance measurement

@@ -38,4 +53,5 @@ *

* @param {string} metricName
* @return {void|number}
*/
end(metricName: string): any;
end(metricName: string): void | number;
/**

@@ -45,4 +61,5 @@ * End performance measurement after first paint from the beging of it

* @param {string} metricName
* @return {Promise<number>}
*/
endPaint(metricName: string): Promise<{}>;
endPaint(metricName: string): Promise<void | number>;
/**

@@ -57,8 +74,11 @@ * Coloring Text in Browser Console

* @param {string} metricName
* @return {boolean}
*/
private checkMetricName(metricName);
/**
* @param {object} entry
* @param {Array<PerformancePaintTiming>} entries
* @param {(value: any) => void} resolve
* @param {(error: any) => void} reject
*/
private firstContentfulPaintCb(entries);
private firstContentfulPaintCb(entries, resolve, reject);
/**

@@ -70,2 +90,4 @@ * @param {number} timeToInteractive

* @param {number} duration
* @param {string} logText
* @param {string} metricName
*/

@@ -84,2 +106,1 @@ private logFCP(duration, logText, metricName);

}
export {};
{
"name": "perfume.js",
"version": "0.6.6",
"version": "0.7.0",
"description": "JavaScript library for measuring Short and Long Script, First Contentful Paint (FCP), Time to Interactive (TTI), Component First Paint (CFM), annotating them to the DevTools timeline and reporting the results to Google Analytics.",

@@ -24,4 +24,5 @@ "keywords": [

"iife": "dist/perfume.iife.js",
"main": "dist/perfume.umd.js",
"main": "dist/perfume.js",
"module": "dist/perfume.es5.js",
"unpkg": "dist/perfume.umd.min.js",
"typings": "dist/types/perfume.d.ts",

@@ -52,3 +53,3 @@ "files": [

"precommit": "lint-staged",
"prepush": "npm run test:prod && npm run build"
"prepush": "npm run test:prod"
},

@@ -93,6 +94,6 @@ "lint-staged": {

"global": {
"branches": 92,
"functions": 92,
"lines": 96,
"statements": 96
"branches": 96,
"functions": 95,
"lines": 99,
"statements": 99
}

@@ -122,4 +123,4 @@ },

"ts-node": "^4.0.1",
"tslint": "^5.4.3",
"typescript": "^2.3.4",
"tslint": "^5.9.1",
"typescript": "^2.8.3",
"validate-commit-msg": "^2.12.2"

@@ -126,0 +127,0 @@ },

@@ -1,7 +0,7 @@

<a href="http://zizzamia.github.io/perfume/"><img src="https://github.com/Zizzamia/perfume.js/blob/master/docs/src/assets/perfume-logo-v0-6-5.png" align="left" width="262" /></a>
<a href="http://zizzamia.github.io/perfume/"><img src="https://github.com/Zizzamia/perfume.js/blob/master/docs/src/assets/perfume-logo-v0-7-0.png" align="left" width="262" /></a>
# [Perfume.js v0.6.6](http://zizzamia.github.io/perfume/)
[![NPM version](https://badge.fury.io/js/perfume.js.svg)](https://www.npmjs.org/package/perfume.js) [![Build Status](https://travis-ci.org/Zizzamia/perfume.js.svg?branch=master)](https://travis-ci.org/Zizzamia/perfume.js) [![NPM Downloads](http://img.shields.io/npm/dm/perfume.js.svg)](https://www.npmjs.org/package/perfume.js) [![Test Coverage](https://api.codeclimate.com/v1/badges/f813d2f45b274d93b8c5/test_coverage)](https://codeclimate.com/github/Zizzamia/perfume.js/test_coverage) [![JS gzip size](http://img.badgesize.io/Zizzamia/perfume.js/master/dist/perfume.umd.js?compression=gzip&label=JS+gzip+size)](https://github.com/Zizzamia/perfume.js/blob/master/dist/perfume.umd.js)
# [Perfume.js v0.7.0](http://zizzamia.github.io/perfume/)
[![NPM version](https://badge.fury.io/js/perfume.js.svg)](https://www.npmjs.org/package/perfume.js) [![Build Status](https://travis-ci.org/Zizzamia/perfume.js.svg?branch=master)](https://travis-ci.org/Zizzamia/perfume.js) [![NPM Downloads](http://img.shields.io/npm/dm/perfume.js.svg)](https://www.npmjs.org/package/perfume.js) [![Test Coverage](https://api.codeclimate.com/v1/badges/f813d2f45b274d93b8c5/test_coverage)](https://codeclimate.com/github/Zizzamia/perfume.js/test_coverage) [![JS gzip size](https://img.badgesize.io/https://unpkg.com/perfume.js?compression=gzip&label=JS+gzip+size)](https://unpkg.com/perfume.js)
> Perfume is a JavaScript library for measuring Short and Long Script, First (Contentful) Paint ([FP/FCP](https://developers.google.com/web/updates/2017/06/user-centric-performance-metrics#first_paint_and_first_contentful_paint)), Time to Interactive ([TTI](https://developers.google.com/web/tools/lighthouse/audits/time-to-interactive)), Component First Paint (CFM), annotating them to the DevTools timeline and reporting the results to Google Analytics.
> Perfume is a JavaScript library for measuring Short and Long Script, First (Contentful) Paint ([FP/FCP](https://medium.com/@zizzamia/first-contentful-paint-with-a-touch-of-perfume-js-cd11dfd2e18f)), Time to Interactive ([TTI](https://medium.com/@zizzamia/time-to-interactive-with-rum-862ba874392c)), Component First Paint (CFM), annotating them to the DevTools timeline and reporting the results to Google Analytics.

@@ -12,3 +12,2 @@ <br />

<br />
<br />

@@ -37,3 +36,3 @@ ## User-centric performance metrics

npm install perfume.js --save
npm install perfume.js --save-dev

@@ -64,3 +63,3 @@

### First Contentful Paint (FCP)
### First Contentful Paint ([FCP](https://medium.com/@zizzamia/first-contentful-paint-with-a-touch-of-perfume-js-cd11dfd2e18f))
This metric mark the point, immediately after navigation, when the browser renders pixels to the screen. This is important to the user because it answers the question: is it happening?

@@ -78,7 +77,7 @@

### Time to Interactive (TTI)
### Time to Interactive ([TTI](https://medium.com/@zizzamia/time-to-interactive-with-rum-862ba874392c))
The metric marks the point at which your application is both visually rendered and capable of reliably responding to user input. An application could be unable to respond to user input for a couple of reasons:
- The JavaScript needed to make the components on the page work hasn't yet loaded;
- There are long tasks blocking the main thread.
The **TTI** metric identifies the point at which the page's initial JavaScript is loaded and the main thread is idle (free of long tasks). See the [metric definition](https://docs.google.com/document/d/1GGiI9-7KeY3TPqS3YT271upUVimo-XiL5mwWorDUD4c/preview#) for in-depth implementation details.
The **TTI** metric identifies the point at which the page's initial JavaScript is loaded and the main thread is idle (free of long tasks).

@@ -85,0 +84,0 @@ ```javascript

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc