This repository has been archived by the owner on Aug 10, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
372 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
const {resolve} = require('path'); | ||
|
||
module.exports = { | ||
mode: 'production', | ||
entry: './src/index.js', | ||
output: { | ||
path: resolve(__dirname, 'dist'), | ||
filename: 'main.js', | ||
library: 'MyLibrary', | ||
libraryTarget: 'umd2', | ||
}, | ||
module: { | ||
rules: [ | ||
{ | ||
test: /\.js$/, | ||
loader: 'babel-loader', | ||
include: resolve('../src'), | ||
sideEffects: false, | ||
}, | ||
], | ||
}, | ||
target: 'web', | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,38 @@ | ||
export default () => null; | ||
import { performanceMetrics } from './performance-metrics'; | ||
import { measure } from './measure'; | ||
import { supported } from './supported'; | ||
|
||
const DEFAULT_REDUCER = (accumulator, [key, value]) => [...accumulator, [key, value]]; | ||
const DEFAULT_ACCUMULATOR = []; | ||
|
||
/** | ||
* An opinionated reducer on performance.timing object | ||
* @param {String[]} [options.metrics] Requested metrics | ||
* @param {Function} [options.reducer] Reducer function | ||
* @param {Any} [options.accumulator] Reducer accumulator | ||
* @return {Any} | ||
*/ | ||
export const pageTiming = ({metrics = performanceMetrics, reducer = DEFAULT_REDUCER, accumulator = DEFAULT_ACCUMULATOR} = {}) => | ||
supported() ? | ||
metrics | ||
.reduce( | ||
(results, metric, index, metrics) => { | ||
|
||
// Ignore invalid performance metrics | ||
if (!performanceMetrics.includes(metric)) { | ||
return results; | ||
} | ||
const value = measure(metric); | ||
|
||
// Ignore empty entries | ||
if (value <= 0) { | ||
return results; | ||
} | ||
|
||
return reducer(results, [metric, value], index, metrics); | ||
}, | ||
accumulator | ||
) | ||
: | ||
accumulator | ||
; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
const timeOrigin = 1; | ||
|
||
const mock = { | ||
unloadEventStart: 0, | ||
unloadEventEnd: 0, | ||
secureConnectionStart: 0, | ||
redirectStart: 0, | ||
redirectEnd: 0, | ||
navigationStart: 1, | ||
connectStart: 110, | ||
connectEnd: 120, | ||
domainLookupEnd: 130, | ||
domainLookupStart: 140, | ||
fetchStart: 150, | ||
requestStart: 170, | ||
responseStart: 180, | ||
domLoading: 190, | ||
responseEnd: 200, | ||
domInteractive: 210, | ||
domContentLoadedEventStart: 220, | ||
domContentLoadedEventEnd: 230, | ||
loadEventStart: 240, | ||
domComplete: 250, | ||
loadEventEnd: 260, | ||
}; | ||
|
||
const results = Object.entries(mock).reduce( | ||
(results, [key, value]) => | ||
value > timeOrigin | ||
? | ||
Object.assign(results, {[key]: value - timeOrigin}) | ||
: | ||
results, | ||
{} | ||
); | ||
|
||
describe('Integration', async() => { | ||
delete require.cache[require.resolve('../')]; | ||
delete require.cache[require.resolve('../start')]; | ||
delete require.cache[require.resolve('../measure')]; | ||
require('../supported').supported(); // cached result | ||
|
||
const performance = Object.getOwnPropertyDescriptor(window, 'performance'); | ||
|
||
beforeEach(() => { | ||
window.performance = { | ||
timeOrigin, | ||
timing: mock, | ||
}; | ||
}); | ||
afterEach(() => { | ||
Object.defineProperty(window, 'performance', performance); | ||
}); | ||
|
||
it('Should extract all performance metrics to a structured object, and skip 0 values', async() => { | ||
await onload(); | ||
await sleep(400); | ||
|
||
const pageTiming = require('../').pageTiming; | ||
|
||
const obj = {key: 'value', metrics: {}}; | ||
const reducer = (accumulator, [key, value]) => Object.assign( | ||
accumulator, | ||
{[key]: parseInt(value, 10)} | ||
); | ||
|
||
pageTiming({ | ||
reducer, | ||
accumulator: obj.metrics, | ||
}); | ||
|
||
expect(obj).to.deep.equal({ | ||
key: 'value', | ||
metrics: results, | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { start } from '../start'; | ||
|
||
/** | ||
* Get the measurement diff from start | ||
* @param {String} measurement | ||
* @return {Number} | ||
*/ | ||
export const measure = (measurement) => Math.max(window.performance.timing[measurement] - start(), 0); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
const { measure } = require('.'); | ||
|
||
describe('measure', () => { | ||
const performance = Object.getOwnPropertyDescriptor(window, 'performance'); | ||
|
||
afterEach(() => | ||
Object.defineProperty(window, 'performance', performance) | ||
); | ||
|
||
it('Should return the diff between timing metric to start point', () => { | ||
window.performance = { | ||
timeOrigin: 100, | ||
timing: { | ||
something: 250, | ||
}, | ||
}; | ||
expect(measure('something')).to.equal(150); | ||
}); | ||
|
||
it('Should return 0 if the time unit it lower than start (e.g. 0)', () => { | ||
window.performance = { | ||
timeOrigin: 100, | ||
timing: { | ||
something: 50, | ||
}, | ||
}; | ||
expect(measure('something')).to.equal(0); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const mem = new WeakMap(); | ||
|
||
/** | ||
* Memoises value by reference | ||
* @param {Object} key | ||
* @param {Function} fn | ||
* @return {Any} | ||
*/ | ||
export const memoise = (key, fn) => mem.has(key) ? mem.get(key) : mem.set(key, fn()).get(key); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
describe('memoise', () => { | ||
let memoise; | ||
const key = {}; | ||
|
||
beforeEach(() => { | ||
delete require.cache[require.resolve('.')]; | ||
memoise = require('.').memoise; | ||
}); | ||
|
||
it('Should uses the getter to retrieve the value', () => { | ||
memoise(key, () => 'Thang'); | ||
expect(memoise(key)).to.equal('Thang'); | ||
}); | ||
|
||
it('Should return the value', () => | ||
expect(memoise(key, () => 'Thang')).to.equal('Thang') | ||
); | ||
|
||
it('Should memoise the result', () => { | ||
memoise(key, () => 'Thing'); | ||
memoise(key, () => 'Thang'); | ||
expect(memoise(key)).to.equal('Thing'); | ||
}); | ||
|
||
it('Should throw error when trying to memoise primitives', () => | ||
[ | ||
'', | ||
Symbol(), | ||
4, | ||
].forEach((key) => expect(() => memoise(key, () => 'Thing')).to.throw()) | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
export const performanceMetrics = [ | ||
'connectEnd', | ||
'connectStart', | ||
'domComplete', | ||
'domContentLoadedEventEnd', | ||
'domContentLoadedEventStart', | ||
'domInteractive', | ||
'domLoading', | ||
'domainLookupEnd', | ||
'domainLookupStart', | ||
'fetchStart', | ||
'loadEventEnd', | ||
'loadEventStart', | ||
'navigationStart', | ||
'redirectEnd', | ||
'redirectStart', | ||
'requestStart', | ||
'responseEnd', | ||
'responseStart', | ||
'secureConnectionStart', | ||
'unloadEventEnd', | ||
'unloadEventStart', | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
const { performanceMetrics } = require('.'); | ||
const IGNORE = [ | ||
'toJSON', | ||
]; | ||
|
||
describe('performance-metrics', () => { | ||
it('Should include all performance metrics', () => { | ||
const windowMetrics = Object.keys(window.performance.timing.constructor.prototype) | ||
.filter((item) => !IGNORE.includes(item)); | ||
|
||
expect(performanceMetrics).to.have.members(windowMetrics); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,51 @@ | ||
import { pageTiming } from '.'; | ||
|
||
const SLEEP_FOR = 400; | ||
|
||
describe('page-timing', async() => { | ||
it('wip', () => { | ||
assert(true); | ||
it('Should return result by default', async() => { | ||
await onload(); | ||
await sleep(SLEEP_FOR); | ||
const measurements = pageTiming(); | ||
expect(measurements).to.have.lengthOf.at.least(5); | ||
}); | ||
|
||
it('Should collect metrics as arrays of [key, value]', async() => { | ||
await onload(); | ||
await sleep(SLEEP_FOR); | ||
const measurements = pageTiming({ | ||
metrics: ['domInteractive', 'loadEventEnd'], | ||
}); | ||
expect(measurements).to.have.lengthOf(2); | ||
measurements.forEach( | ||
([key, value]) => { | ||
expect(key).to.be.a('string'); | ||
expect(value).to.be.a('number'); | ||
} | ||
); | ||
}); | ||
|
||
it('Should ignore metrics that are not valid', async() => { | ||
await onload(); | ||
await sleep(SLEEP_FOR); | ||
const measurements = pageTiming({ | ||
metrics: ['domInteractive', 'loadEventEnd', 'another'], | ||
}); | ||
expect(measurements).to.have.lengthOf(2); | ||
}); | ||
|
||
it('Should format metrics', async() => { | ||
await onload(); | ||
await sleep(SLEEP_FOR); | ||
const [interactive, load] = pageTiming({ | ||
metrics: ['domInteractive', 'loadEventEnd'], | ||
reducer: (accumulator, [key, value]) => [ | ||
...accumulator, | ||
['prefix', key, Math.round(value)].join(':'), | ||
], | ||
}); | ||
|
||
expect(interactive).to.match(/prefix:domInteractive:(\d{2,4})/); | ||
expect(load).to.match(/prefix:loadEventEnd:(\d{2,4})/); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { memoise } from '../memoise'; | ||
const key = {}; | ||
|
||
export const start = () => memoise(key, () => window.performance.timeOrigin || window.performance.timing.navigationStart); |
Oops, something went wrong.