Skip to content

Commit

Permalink
Merge pull request #25 from xwp/feature/web-vitals
Browse files Browse the repository at this point in the history
Track web-vitals
  • Loading branch information
mehigh authored May 3, 2021
2 parents 261ca3b + eb73f22 commit cd36631
Show file tree
Hide file tree
Showing 11 changed files with 558 additions and 2 deletions.
4 changes: 4 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
**/*.min.js
**/node_modules/**
**/vendor/**
**/js/dist/**/*.js
48 changes: 48 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"extends": [
"plugin:@wordpress/eslint-plugin/recommended",
"prettier"
],
"rules": {
"@wordpress/i18n-text-domain": [
"error",
{
"allowedTextDomain": [ "xcurrent" ]
}
],
"prettier/prettier": [
"error",
{
"singleQuote": true,
"parenSpacing": true,
"trailingComma": "es5",
"jsxBracketSameLine": false,
"arrowParens": "avoid"
}
]
},
"overrides": [
{
"files":[
"**/__tests__/**/*.js",
"**/test/*.js",
"**/?(*.)test.js",
"tests/js/**/*.js"
],
"extends": [
"plugin:jest/all"
],
"rules": {
"jest/lowercase-name": [
"error",
{
"ignore": [ "describe" ]
}
],
"jest/no-hooks": "off",
"jest/prefer-expect-assertions": "off",
"jest/prefer-inline-snapshots": "off"
}
}
]
}
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,42 @@ Filter the [entry types](https://developer.mozilla.org/en-US/docs/Web/API/Perfor
apply_filters( 'site_performance_tracker_event_types', array $entry_types = [ 'paint', 'navigation', 'mark' ] );
```

##### Enable web vitals tracking

To send web vitals to Google Analytics in a format compatible with the [Web Vitals Report](https://web-vitals-report.web.app/), enable the following theme support and passing in the ID, both UA- and G- ID formats are supported:

Analytics is suppored, requires passing the ID using `ga_id`:
```php
add_theme_support( 'site_performance_tracker_vitals', array(
'ga_id' => 'UA-XXXXXXXX-Y',
) );
```
Gtag is suppored, requires passing the ID using `gtag_id`:
```php
add_theme_support( 'site_performance_tracker_vitals', array(
'gtag_id' => 'UA-XXXXXXXX-Y',
) );
```

If you need to override the Google Analytics dimensions (defaults to dimensions1 through 6) to store these under, pass them along on the add theme support initialisation:
```php
add_theme_support( 'site_performance_tracker_vitals', array(
'gtag_id' => 'UA-XXXXXXXX-Y',
'measurementVersion' => 'dimension7',
'clientId' => 'dimension8',
'segments' => 'dimension9',
'config' => 'dimension10',
'eventMeta' => 'dimension11',
'eventDebug' => 'dimension12',
) );
```

## Changelog

#### 0.5 - April 13, 2021

* Feature: Add support for sending data in the web vitals report format.

#### 0.3.1 - March 11, 2020

* Feature: Add support to Analytics added through Google Tag Managere.
Expand Down
1 change: 1 addition & 0 deletions js/dist/module/web-vitals-analytics.asset.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return array('dependencies' => array('wp-polyfill'), 'version' => '545643e091ef707f7501413bf114f4ab');
1 change: 1 addition & 0 deletions js/dist/module/web-vitals-analytics.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

222 changes: 222 additions & 0 deletions js/src/web-vitals-analytics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* global ga, gtag, location, requestIdleCallback */

import { getCLS, getFCP, getFID, getLCP } from 'web-vitals';

const vitalThresholds = {
CLS: [ 0.1, 0.25 ],
FCP: [ 1800, 3000 ],
FID: [ 100, 300 ],
LCP: [ 2500, 4000 ],
};

const uaDimMeasurementVersion = window.webVitalsAnalyticsData.measurementVersion
? window.webVitalsAnalyticsData.measurementVersion
: 'dimension1';
const uaDimclientId = window.webVitalsAnalyticsData.clientId
? window.webVitalsAnalyticsData.cliegantId
: 'dimension2';
const uaDimSegments = window.webVitalsAnalyticsData.segments
? window.webVitalsAnalyticsData.segments
: 'dimension3';
const uaDimConfig = window.webVitalsAnalyticsData.config
? window.webVitalsAnalyticsData.config
: 'dimension4';
const uaDimEventMeta = window.webVitalsAnalyticsData.eventMeta
? window.webVitalsAnalyticsData.eventMeta
: 'dimension5';
const uaDimEventDebug = window.webVitalsAnalyticsData.eventDebug
? window.webVitalsAnalyticsData.eventDebug
: 'dimension6';

const getConfig = id => {
const config = {
page_path: location.pathname,
};

if ( 'gtag' === window.webVitalsAnalyticsData.delivery ) {
Object.assign( config, {
transport_type: 'beacon',
measurement_version: '6',
} );
}

if ( id.startsWith( 'UA-' ) ) {
// Only gtag suports custom maps.
if ( 'gtag' === window.webVitalsAnalyticsData.delivery ) {
Object.assign( config, {
custom_map: {
[ uaDimMeasurementVersion ]: 'measurement_version',
[ uaDimclientId ]: 'client_id',
[ uaDimSegments ]: 'segments',
[ uaDimConfig ]: 'config',
[ uaDimEventMeta ]: 'event_meta',
[ uaDimEventDebug ]: 'event_debug',
metric1: 'report_size',
},
} );
}

if ( 'ga' === window.webVitalsAnalyticsData.delivery ) {
Object.assign( config, {
[ uaDimMeasurementVersion ]: '6',
} );
}
}

return [ 'config', id, config ];
};

function getRating( value, thresholds ) {
if ( value > thresholds[ 1 ] ) {
return 'poor';
}
if ( value > thresholds[ 0 ] ) {
return 'ni';
}
return 'good';
}

function getNodePath( node ) {
try {
let name = node.nodeName.toLowerCase();
if ( name === 'body' ) {
return 'html>body';
}
if ( node.id ) {
return `${ name }#${ node.id }`;
}
if ( node.className && node.className.length ) {
name += `.${ [ ...node.classList.values() ].join( '.' ) }`;
}
return `${ getNodePath( node.parentElement ) }>${ name }`;
} catch ( error ) {
return '(error)';
}
}

function getDebugInfo( metricName, entries = [] ) {
const firstEntry = entries[ 0 ];
const lastEntry = entries[ entries.length - 1 ];

switch ( metricName ) {
case 'LCP':
if ( lastEntry ) {
return getNodePath( lastEntry.element );
}
break;
case 'FID':
if ( firstEntry ) {
const { name } = firstEntry;
return `${ name }(${ getNodePath( firstEntry.target ) })`;
}
break;
case 'CLS':
if ( entries.length ) {
const largestShift = entries.reduce( ( a, b ) => {
return a && a.value > b.value ? a : b;
} );
if ( largestShift && largestShift.sources ) {
const largestSource = largestShift.sources.reduce( ( a, b ) => {
return a.node &&
a.previousRect.width * a.previousRect.height >
b.previousRect.width * b.previousRect.height
? a
: b;
} );
if ( largestSource ) {
return getNodePath( largestSource.node );
}
}
}
break;
default:
return '(not set)';
}
}

function sendToGoogleAnalytics( { name, value, delta, id, entries } ) {
if ( 'undefined' !== typeof window.webVitalsAnalyticsData.gtag_id ) {
gtag( 'event', name, {
event_category: 'Web Vitals',
event_label: id,
value: Math.round( name === 'CLS' ? delta * 1000 : delta ),
non_interaction: true,
event_meta: getRating( value, vitalThresholds[ name ] ),
metric_rating: getRating( value, vitalThresholds[ name ] ),
event_debug: getDebugInfo( name, entries ),
} );
}
if ( 'undefined' !== typeof window.webVitalsAnalyticsData.ga_id ) {
ga( 'send', 'event', {
eventCategory: 'Web Vitals',
eventAction: name,
eventLabel: id,
eventValue: Math.round( name === 'CLS' ? delta * 1000 : delta ),
nonInteraction: true,
transport: 'beacon',
[ uaDimEventMeta ]: getRating( value, vitalThresholds[ name ] ),
[ uaDimEventDebug ]: getDebugInfo( name, entries ),
} );
}
}

export function measureWebVitals() {
getCLS( sendToGoogleAnalytics );
getFCP( sendToGoogleAnalytics );
getFID( sendToGoogleAnalytics );
getLCP( sendToGoogleAnalytics );
}

export function initAnalytics() {
if ( 'undefined' === typeof window.webVitalsAnalyticsData ) {
return false;
// Do nothing without a config.
}
if ( 'undefined' !== typeof window.webVitalsAnalyticsData.gtag_id ) {
window.webVitalsAnalyticsData.delivery = 'gtag';
} else if ( 'undefined' !== typeof window.webVitalsAnalyticsData.ga_id ) {
window.webVitalsAnalyticsData.delivery = 'ga';
}

if ( 'gtag' === window.webVitalsAnalyticsData.delivery ) {
window.webVitalsAnalyticsData.type = 'gtag';
if ( 'undefined' === typeof window.gtag ) {
// eslint-disable-next-line no-console
window.gtag = console.log;
}
gtag( 'js', new Date() );
gtag( ...getConfig( window.webVitalsAnalyticsData.gtag_id ) );
}

if ( 'ga' === window.webVitalsAnalyticsData.delivery ) {
if ( 'undefined' === typeof window.ga ) {
// eslint-disable-next-line no-console
window.ga = console.log;
} else {
ga( 'js', new Date() );
ga( ...getConfig( window.webVitalsAnalyticsData.ga_id ) );
}
}

measureWebVitals();
}

( function () {
requestIdleCallback( initAnalytics );
} )();
51 changes: 51 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"name": "site-performance-tracker",
"version": "1.0.0",
"description": "Site Performance Tracker",
"author": "XWP",
"license": "GPL-2.0-or-later",
"keywords": [
"WordPress",
"Plugin"
],
"engines": {
"node": ">=14.0.0"
},
"homepage": "https://github.com/xwp/site-performance-tracker#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/xwp/site-performance-tracker.git"
},
"bugs": {
"url": "https://github.com/xwp/site-performance-tracker/issues"
},
"browserslist": [
"last 2 Chrome versions",
"last 2 Firefox versions",
"last 2 Safari versions",
"last 2 Edge versions",
"last 2 iOS versions",
"last 1 Android version",
"last 1 ChromeAndroid version",
"> 2%"
],
"devDependencies": {
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@wordpress/scripts": "^13.0.3",
"del": "^6.0.0",
"dir-archiver": "^1.1.1",
"gulp": "^4.0.2",
"gulp-rename": "^2.0.0",
"npm-run-all": "^4.1.5",
"webpackbar": "^5.0.0-3"
},
"scripts": {
"dev:js": "wp-scripts start",
"build:js": "wp-scripts build",
"lint:js": "wp-scripts lint-js",
"format:js": "npm run lint:js -- --fix"
},
"dependencies": {
"web-vitals": "^1.1.1"
}
}
Loading

0 comments on commit cd36631

Please sign in to comment.