Skip to content

Commit 7d6a8f8

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

File tree

16 files changed

+499
-1
lines changed

16 files changed

+499
-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: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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+
![performance navigation timeline](./docs/performance_navigation_timeline.svg)
13+
14+
## Maintainer quick start
15+
16+
Part of the Snowplow JavaScript Tracker monorepo.
17+
Build with [Node.js](https://nodejs.org/en/) (14 or 16) and [Rush](https://rushjs.io/).
18+
19+
### Setup repository
20+
21+
```bash
22+
npm install -g @microsoft/rush
23+
git clone https://github.com/snowplow/snowplow-javascript-tracker.git
24+
rush update
25+
```
26+
27+
## Package Installation
28+
29+
With npm:
30+
31+
```bash
32+
npm install @snowplow/browser-plugin-performance-navigation-timing
33+
```
34+
35+
## Usage
36+
37+
Initialize your tracker with the PerformanceNavigationTimingPlugin:
38+
39+
```js
40+
import { newTracker } from '@snowplow/browser-tracker';
41+
import { PerformanceNavigationTimingPlugin } from '@snowplow/browser-plugin-performance-navigation-timing';
42+
43+
newTracker('sp1', '{{collector}}', { plugins: [ PerformanceNavigationTimingPlugin() ] });
44+
```
45+
46+
## Copyright and license
47+
48+
Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]).
49+
50+
Copyright (c) 2023 Snowplow Analytics Ltd.
51+
52+
All rights reserved.
53+
54+
[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-performance-navigation-timing
55+
[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-performance-navigation-timing
56+
[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/
57+
[osi]: https://opensource.org/licenses/BSD-3-Clause
58+
[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: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
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+
/**
12+
* Creates a context from the PerformanceNavigationTiming object
13+
*
14+
* @returns object PerformanceNavigationTiming context
15+
*/
16+
export function getPerformanceNavigationTimingContext() {
17+
const performanceAlias =
18+
window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance || {};
19+
20+
if (performanceAlias.getEntriesByType) {
21+
const [performanceNavigationTiming] = performanceAlias.getEntriesByType('navigation') as [
22+
PerformanceNavigationTiming
23+
];
24+
25+
if (!performanceNavigationTiming) {
26+
return [];
27+
}
28+
29+
return constructNavigationTimingContext(performanceNavigationTiming);
30+
}
31+
32+
return [];
33+
}
34+
35+
export function constructNavigationTimingContext(performanceNavigationTimingInstance: PerformanceNavigationTiming) {
36+
const serverTimingData =
37+
performanceNavigationTimingInstance.serverTiming &&
38+
performanceNavigationTimingInstance.serverTiming.map(({ description, duration, name }) => ({
39+
description,
40+
duration,
41+
name,
42+
}));
43+
44+
return [
45+
{
46+
schema: PERFORMANCE_NAVIGATION_TIMING_SCHEMA,
47+
data: {
48+
entryType: performanceNavigationTimingInstance.entryType,
49+
startTime: performanceNavigationTimingInstance.startTime,
50+
duration: performanceNavigationTimingInstance.duration,
51+
nextHopProtocol: performanceNavigationTimingInstance.nextHopProtocol,
52+
workerStart: performanceNavigationTimingInstance.workerStart,
53+
redirectStart: performanceNavigationTimingInstance.redirectStart,
54+
redirectEnd: performanceNavigationTimingInstance.redirectEnd,
55+
fetchStart: performanceNavigationTimingInstance.fetchStart,
56+
domainLookupStart: performanceNavigationTimingInstance.domainLookupStart,
57+
domainLookupEnd: performanceNavigationTimingInstance.domainLookupEnd,
58+
connectStart: performanceNavigationTimingInstance.connectStart,
59+
secureConnectionStart: performanceNavigationTimingInstance.secureConnectionStart,
60+
connectEnd: performanceNavigationTimingInstance.connectEnd,
61+
requestStart: performanceNavigationTimingInstance.requestStart,
62+
responseStart: performanceNavigationTimingInstance.responseStart,
63+
responseEnd: performanceNavigationTimingInstance.responseEnd,
64+
transferSize: performanceNavigationTimingInstance.transferSize,
65+
encodedBodySize: performanceNavigationTimingInstance.encodedBodySize,
66+
decodedBodySize: performanceNavigationTimingInstance.decodedBodySize,
67+
serverTiming: serverTimingData,
68+
unloadEventStart: performanceNavigationTimingInstance.unloadEventStart,
69+
unloadEventEnd: performanceNavigationTimingInstance.unloadEventEnd,
70+
domInteractive: performanceNavigationTimingInstance.domInteractive,
71+
domContentLoadedEventStart: performanceNavigationTimingInstance.domContentLoadedEventStart,
72+
domContentLoadedEventEnd: performanceNavigationTimingInstance.domContentLoadedEventEnd,
73+
domComplete: performanceNavigationTimingInstance.domComplete,
74+
loadEventStart: performanceNavigationTimingInstance.loadEventStart,
75+
loadEventEnd: performanceNavigationTimingInstance.loadEventEnd,
76+
type: performanceNavigationTimingInstance.type,
77+
redirectCount: performanceNavigationTimingInstance.redirectCount,
78+
activationStart: (<any>performanceNavigationTimingInstance).activationStart,
79+
deliveryType: (<any>performanceNavigationTimingInstance).deliveryType,
80+
},
81+
},
82+
];
83+
}

0 commit comments

Comments
 (0)