Skip to content

Commit 2b2187c

Browse files
committed
Create performance navigation timing plugin (close #1171)
1 parent d170327 commit 2b2187c

File tree

16 files changed

+618
-1
lines changed

16 files changed

+618
-1
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@snowplow/browser-plugin-performance-navigation-timing",
5+
"comment": "Introduce Performance Navigation Timing plugin",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@snowplow/browser-plugin-performance-navigation-timing"
10+
}

common/config/rush/pnpm-lock.yaml

Lines changed: 49 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

common/config/rush/repo-state.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush.
22
{
3-
"pnpmShrinkwrapHash": "acc89ec01200ab3281ee1b0320ec90dfd66db4fa",
3+
"pnpmShrinkwrapHash": "1b4af3f37be662be92115c24013c6b260e74acc8",
44
"preferredVersionsHash": "bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f"
55
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
BSD 3-Clause License
2+
3+
Copyright (c) 2023 Snowplow Analytics Ltd
4+
All rights reserved.
5+
6+
Redistribution and use in source and binary forms, with or without
7+
modification, are permitted provided that the following conditions are met:
8+
9+
1. Redistributions of source code must retain the above copyright notice, this
10+
list of conditions and the following disclaimer.
11+
12+
2. Redistributions in binary form must reproduce the above copyright notice,
13+
this list of conditions and the following disclaimer in the documentation
14+
and/or other materials provided with the distribution.
15+
16+
3. Neither the name of the copyright holder nor the names of its
17+
contributors may be used to endorse or promote products derived from
18+
this software without specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Snowplow Performance Navigation Timing Tracking
2+
3+
[![npm version][npm-image]][npm-url]
4+
[![License][license-image]](LICENSE)
5+
6+
Browser Plugin to be used with `@snowplow/browser-tracker`.
7+
8+
Adds Performance Navigation Timing contexts to your Snowplow tracking. To learn more about the properties tracked, you can visit the [specification](https://www.w3.org/TR/navigation-timing-2/) or MDN [documentation site](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming).
9+
10+
The following diagram shows the ResourceTiming and PerformanceNavigationTiming properties and how they connect to the navigation of the page main document.
11+
12+
<figure>
13+
<img src="./docs/performance_navigation_timeline.svg" alt="performance navigation timeline"/>
14+
<figcaption>Performance navigation timeline from the <a href="https://www.w3.org/TR/navigation-timing-2/">W3C specification.</a></figcaption>
15+
</figure>
16+
17+
## Maintainer quick start
18+
19+
Part of the Snowplow JavaScript Tracker monorepo.
20+
Build with [Node.js](https://nodejs.org/en/) (14 or 16) and [Rush](https://rushjs.io/).
21+
22+
### Setup repository
23+
24+
```bash
25+
npm install -g @microsoft/rush
26+
git clone https://github.com/snowplow/snowplow-javascript-tracker.git
27+
rush update
28+
```
29+
30+
## Package Installation
31+
32+
With npm:
33+
34+
```bash
35+
npm install @snowplow/browser-plugin-performance-navigation-timing
36+
```
37+
38+
## Usage
39+
40+
Initialize your tracker with the PerformanceNavigationTimingPlugin:
41+
42+
```js
43+
import { newTracker } from '@snowplow/browser-tracker';
44+
import { PerformanceNavigationTimingPlugin } from '@snowplow/browser-plugin-performance-navigation-timing';
45+
46+
newTracker('sp1', '{{collector}}', { plugins: [ PerformanceNavigationTimingPlugin() ] });
47+
```
48+
49+
## Copyright and license
50+
51+
Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]).
52+
53+
Copyright (c) 2023 Snowplow Analytics Ltd.
54+
55+
All rights reserved.
56+
57+
[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-performance-navigation-timing
58+
[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-performance-navigation-timing
59+
[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/
60+
[osi]: https://opensource.org/licenses/BSD-3-Clause
61+
[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-performance-navigation-timing

plugins/browser-plugin-performance-navigation-timing/docs/performance_navigation_timeline.svg

Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
preset: 'ts-jest',
3+
reporters: ['jest-standard-reporter'],
4+
testEnvironment: 'jest-environment-jsdom-global',
5+
};
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"name": "@snowplow/browser-plugin-performance-navigation-timing",
3+
"version": "3.9.0",
4+
"description": "Attaches Performance Navigation Timing data to Snowplow events",
5+
"homepage": "https://docs.snowplow.io/",
6+
"bugs": "https://github.com/snowplow/snowplow-javascript-tracker/issues",
7+
"repository": {
8+
"type": "git",
9+
"url": "https://github.com/snowplow/snowplow-javascript-tracker.git"
10+
},
11+
"license": "BSD-3-Clause",
12+
"author": "Peter Perlepes",
13+
"sideEffects": false,
14+
"main": "./dist/index.umd.js",
15+
"module": "./dist/index.module.js",
16+
"types": "./dist/index.module.d.ts",
17+
"files": [
18+
"dist"
19+
],
20+
"scripts": {
21+
"build": "rollup -c --silent --failAfterWarnings",
22+
"test": "jest"
23+
},
24+
"dependencies": {
25+
"@snowplow/browser-tracker-core": "workspace:*",
26+
"@snowplow/tracker-core": "workspace:*",
27+
"tslib": "^2.3.1"
28+
},
29+
"devDependencies": {
30+
"@ampproject/rollup-plugin-closure-compiler": "~0.27.0",
31+
"@rollup/plugin-commonjs": "~21.0.2",
32+
"@rollup/plugin-node-resolve": "~13.1.3",
33+
"@types/jest": "~27.4.1",
34+
"@types/jsdom": "~16.2.14",
35+
"@typescript-eslint/eslint-plugin": "~5.15.0",
36+
"@typescript-eslint/parser": "~5.15.0",
37+
"eslint": "~8.11.0",
38+
"jest": "~27.5.1",
39+
"jest-environment-jsdom": "~27.5.1",
40+
"jest-environment-jsdom-global": "~3.0.0",
41+
"jest-standard-reporter": "~2.0.0",
42+
"rollup": "~2.70.1",
43+
"rollup-plugin-cleanup": "~3.2.1",
44+
"rollup-plugin-license": "~2.6.1",
45+
"rollup-plugin-terser": "~7.0.2",
46+
"rollup-plugin-ts": "~2.0.5",
47+
"ts-jest": "~27.1.3",
48+
"typescript": "~4.6.2"
49+
},
50+
"peerDependencies": {
51+
"@snowplow/browser-tracker": "~3.9.0"
52+
}
53+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { nodeResolve } from '@rollup/plugin-node-resolve';
2+
import commonjs from '@rollup/plugin-commonjs';
3+
import ts from 'rollup-plugin-ts'; // Preferred over @rollup/plugin-typescript as it bundles .d.ts files
4+
import { banner } from '../../banner';
5+
import compiler from '@ampproject/rollup-plugin-closure-compiler';
6+
import { terser } from 'rollup-plugin-terser';
7+
import cleanup from 'rollup-plugin-cleanup';
8+
import pkg from './package.json';
9+
import { builtinModules } from 'module';
10+
11+
const umdPlugins = [nodeResolve({ browser: true }), commonjs(), ts()];
12+
const umdName = 'snowplowPerformanceNavigationTiming';
13+
14+
export default [
15+
// CommonJS (for Node) and ES module (for bundlers) build.
16+
{
17+
input: './src/index.ts',
18+
plugins: [...umdPlugins, banner()],
19+
treeshake: { moduleSideEffects: ['sha1'] },
20+
output: [{ file: pkg.main, format: 'umd', sourcemap: true, name: umdName }],
21+
},
22+
{
23+
input: './src/index.ts',
24+
plugins: [...umdPlugins, compiler(), terser(), cleanup({ comments: 'none' }), banner()],
25+
treeshake: { moduleSideEffects: ['sha1'] },
26+
output: [{ file: pkg.main.replace('.js', '.min.js'), format: 'umd', sourcemap: true, name: umdName }],
27+
},
28+
{
29+
input: './src/index.ts',
30+
external: [...builtinModules, ...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)],
31+
plugins: [
32+
ts(), // so Rollup can convert TypeScript to JavaScript
33+
banner(),
34+
],
35+
output: [{ file: pkg.module, format: 'es', sourcemap: true }],
36+
},
37+
];
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { PERFORMANCE_NAVIGATION_TIMING_SCHEMA } from './schemata';
2+
3+
declare global {
4+
interface Window {
5+
mozPerformance: any;
6+
msPerformance: any;
7+
webkitPerformance: any;
8+
}
9+
}
10+
11+
type PerformanceNavigationTimingContext = PerformanceNavigationTiming & {
12+
activationStart?: number;
13+
deliveryType?: string;
14+
};
15+
16+
/**
17+
* Creates a context from the PerformanceNavigationTiming object
18+
*
19+
* @returns object PerformanceNavigationTiming context
20+
*/
21+
export function getPerformanceNavigationTimingContext() {
22+
const performanceAlias =
23+
window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance || {};
24+
25+
if (performanceAlias.getEntriesByType) {
26+
const [performanceNavigationTiming] = performanceAlias.getEntriesByType('navigation') as [
27+
PerformanceNavigationTiming
28+
];
29+
30+
if (!performanceNavigationTiming) {
31+
return [];
32+
}
33+
34+
return constructNavigationTimingContext(performanceNavigationTiming);
35+
}
36+
37+
return [];
38+
}
39+
40+
export function constructNavigationTimingContext(
41+
performanceNavigationTimingInstance: PerformanceNavigationTimingContext
42+
) {
43+
const performanceNavigationKeys = [
44+
'entryType',
45+
'startTime',
46+
'duration',
47+
'nextHopProtocol',
48+
'workerStart',
49+
'redirectStart',
50+
'redirectEnd',
51+
'fetchStart',
52+
'domainLookupStart',
53+
'domainLookupEnd',
54+
'connectStart',
55+
'secureConnectionStart',
56+
'connectEnd',
57+
'requestStart',
58+
'responseStart',
59+
'responseEnd',
60+
'transferSize',
61+
'encodedBodySize',
62+
'decodedBodySize',
63+
'serverTiming',
64+
'unloadEventStart',
65+
'unloadEventEnd',
66+
'domInteractive',
67+
'domContentLoadedEventStart',
68+
'domContentLoadedEventEnd',
69+
'domComplete',
70+
'loadEventStart',
71+
'loadEventEnd',
72+
'type',
73+
'redirectCount',
74+
'activationStart',
75+
'deliveryType',
76+
] as const;
77+
78+
const performanceContextData = performanceNavigationKeys.reduce((accum, key) => {
79+
const performanceValue = performanceNavigationTimingInstance[key];
80+
if (key === 'serverTiming' && Array.isArray(performanceValue) && performanceValue.length) {
81+
accum[key] = performanceValue.map(({ description, duration, name }: PerformanceServerTiming) => ({
82+
description,
83+
duration,
84+
name,
85+
}));
86+
} else if (performanceValue) {
87+
accum[key] = performanceValue;
88+
}
89+
90+
return accum;
91+
}, {} as Record<typeof performanceNavigationKeys[number], unknown>);
92+
93+
return [
94+
{
95+
schema: PERFORMANCE_NAVIGATION_TIMING_SCHEMA,
96+
data: performanceContextData,
97+
},
98+
];
99+
}

0 commit comments

Comments
 (0)