From ebc076feecc6397d70d70bf30b67e109c5b8878d Mon Sep 17 00:00:00 2001 From: LekoArts Date: Mon, 17 Apr 2023 15:39:33 +0200 Subject: [PATCH 1/6] add plugin options --- .../gatsby-plugin-google-gtag/package.json | 3 +- .../src/__tests__/gatsby-node.js | 58 +++++++++++++++++++ .../src/gatsby-node.js | 50 ++++++++++++++++ 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 packages/gatsby-plugin-google-gtag/src/__tests__/gatsby-node.js create mode 100644 packages/gatsby-plugin-google-gtag/src/gatsby-node.js diff --git a/packages/gatsby-plugin-google-gtag/package.json b/packages/gatsby-plugin-google-gtag/package.json index 6bf0d884abbf0..c3cd81f82c0a3 100644 --- a/packages/gatsby-plugin-google-gtag/package.json +++ b/packages/gatsby-plugin-google-gtag/package.json @@ -14,7 +14,8 @@ "@babel/cli": "^7.20.7", "@babel/core": "^7.20.12", "babel-preset-gatsby-package": "^3.9.0-next.0", - "cross-env": "^7.0.3" + "cross-env": "^7.0.3", + "gatsby-plugin-utils": "^4.9.0-next.1" }, "homepage": "https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-plugin-google-gtag#readme", "keywords": [ diff --git a/packages/gatsby-plugin-google-gtag/src/__tests__/gatsby-node.js b/packages/gatsby-plugin-google-gtag/src/__tests__/gatsby-node.js new file mode 100644 index 0000000000000..0917a4f1b569a --- /dev/null +++ b/packages/gatsby-plugin-google-gtag/src/__tests__/gatsby-node.js @@ -0,0 +1,58 @@ +import { testPluginOptionsSchema } from "gatsby-plugin-utils" +import { pluginOptionsSchema } from "../gatsby-node" + +describe(`pluginOptionsSchema`, () => { + it(`should invalidate incorrect options`, async () => { + const options = { + trackingIds: undefined, // Is required + gtagConfig: `test`, + pluginConfig: { + head: `test`, + respectDNT: `test`, + exclude: `test`, + origin: 1, + delayOnRouteUpdate: `test`, + }, + } + const expectedErrors = [ + `"trackingIds" is required`, + `"gtagConfig" must be of type object`, + `"pluginConfig.head" must be a boolean`, + `"pluginConfig.respectDNT" must be a boolean`, + `"pluginConfig.exclude" must be an array`, + `"pluginConfig.origin" must be a string`, + `"pluginConfig.delayOnRouteUpdate" must be a number`, + ] + + const { isValid, errors } = await testPluginOptionsSchema( + pluginOptionsSchema, + options + ) + + expect(isValid).toBe(false) + expect(errors).toEqual(expectedErrors) + }) + + it(`should validate correct options`, async () => { + const options = { + trackingIds: [`test`], + gtagConfig: { + anonymize_ip: true, + }, + pluginConfig: { + head: true, + respectDNT: true, + exclude: [`test`], + origin: `test`, + delayOnRouteUpdate: 1, + }, + } + const { isValid, errors } = await testPluginOptionsSchema( + pluginOptionsSchema, + options + ) + + expect(isValid).toBe(true) + expect(errors).toEqual([]) + }) +}) diff --git a/packages/gatsby-plugin-google-gtag/src/gatsby-node.js b/packages/gatsby-plugin-google-gtag/src/gatsby-node.js new file mode 100644 index 0000000000000..56924182ab25b --- /dev/null +++ b/packages/gatsby-plugin-google-gtag/src/gatsby-node.js @@ -0,0 +1,50 @@ +// @ts-check + +/** + * @type {import('gatsby').GatsbyNode["pluginOptionsSchema"]} + */ +exports.pluginOptionsSchema = ({ Joi }) => + Joi.object({ + trackingIds: Joi.array() + .items(Joi.string()) + .description( + `The tracking IDs; the tracking code won't be generated without them.` + ) + .required(), + gtagConfig: Joi.object({ + optimize_id: Joi.string().description( + `Enable if you need to use Google Optimize.` + ), + anonymize_ip: Joi.boolean() + .description(`Enable if you need to use the "anonymizeIP" function.`) + .default(false), + }) + .unknown(true) + .description( + `This object gets passed directly to the gtag config command.` + ) + .default({}), + pluginConfig: Joi.object({ + head: Joi.boolean() + .description(`Puts tracking script in the instead of the `) + .default(false), + respectDNT: Joi.boolean() + .description( + `If you enable this optional option, Google Global Site Tag will not be loaded at all for visitors that have "Do Not Track" enabled.` + ) + .default(false), + exclude: Joi.array() + .items(Joi.string()) + .description( + `If you need to exclude any path from the tracking system, you can add it (one or more) to this optional array as glob expressions.` + ), + origin: Joi.string() + .description(`Your optional self hosted origin for the script.`) + .default(`https://www.googletagmanager.com`), + delayOnRouteUpdate: Joi.number() + .description(`Delay processing pageview events on route update`) + .default(0), + }) + .description(`Configure the plugin behavior.`) + .default({}), + }) From c3b16360266f982fc064c23e393bc28a8826fbd8 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Mon, 17 Apr 2023 15:46:24 +0200 Subject: [PATCH 2/6] change object syntax --- .../src/gatsby-node.js | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/packages/gatsby-plugin-google-gtag/src/gatsby-node.js b/packages/gatsby-plugin-google-gtag/src/gatsby-node.js index 56924182ab25b..02467ee091471 100644 --- a/packages/gatsby-plugin-google-gtag/src/gatsby-node.js +++ b/packages/gatsby-plugin-google-gtag/src/gatsby-node.js @@ -11,40 +11,44 @@ exports.pluginOptionsSchema = ({ Joi }) => `The tracking IDs; the tracking code won't be generated without them.` ) .required(), - gtagConfig: Joi.object({ - optimize_id: Joi.string().description( - `Enable if you need to use Google Optimize.` - ), - anonymize_ip: Joi.boolean() - .description(`Enable if you need to use the "anonymizeIP" function.`) - .default(false), - }) + gtagConfig: Joi.object() + .keys({ + optimize_id: Joi.string().description( + `Enable if you need to use Google Optimize.` + ), + anonymize_ip: Joi.boolean() + .description(`Enable if you need to use the "anonymizeIP" function.`) + .default(false), + }) .unknown(true) .description( `This object gets passed directly to the gtag config command.` ) .default({}), - pluginConfig: Joi.object({ - head: Joi.boolean() - .description(`Puts tracking script in the instead of the `) - .default(false), - respectDNT: Joi.boolean() - .description( - `If you enable this optional option, Google Global Site Tag will not be loaded at all for visitors that have "Do Not Track" enabled.` - ) - .default(false), - exclude: Joi.array() - .items(Joi.string()) - .description( - `If you need to exclude any path from the tracking system, you can add it (one or more) to this optional array as glob expressions.` - ), - origin: Joi.string() - .description(`Your optional self hosted origin for the script.`) - .default(`https://www.googletagmanager.com`), - delayOnRouteUpdate: Joi.number() - .description(`Delay processing pageview events on route update`) - .default(0), - }) - .description(`Configure the plugin behavior.`) - .default({}), + pluginConfig: Joi.object() + .keys({ + head: Joi.boolean() + .description( + `Puts tracking script in the instead of the ` + ) + .default(false), + respectDNT: Joi.boolean() + .description( + `If you enable this optional option, Google Global Site Tag will not be loaded at all for visitors that have "Do Not Track" enabled.` + ) + .default(false), + exclude: Joi.array() + .items(Joi.string()) + .description( + `If you need to exclude any path from the tracking system, you can add it (one or more) to this optional array as glob expressions.` + ) + .default([]), + origin: Joi.string() + .description(`Your optional self hosted origin for the script.`) + .default(`https://www.googletagmanager.com`), + delayOnRouteUpdate: Joi.number() + .description(`Delay processing pageview events on route update`) + .default(0), + }) + .description(`Configure the plugin's behavior.`), }) From 63b04e88d228255278f827a076292e0a2aa189be Mon Sep 17 00:00:00 2001 From: LekoArts Date: Mon, 17 Apr 2023 15:53:46 +0200 Subject: [PATCH 3/6] update source code --- .../src/gatsby-browser.js | 9 ++-- .../src/gatsby-ssr.js | 44 +++++++++++-------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/packages/gatsby-plugin-google-gtag/src/gatsby-browser.js b/packages/gatsby-plugin-google-gtag/src/gatsby-browser.js index 1424b51f20a5a..b3855d22ade78 100644 --- a/packages/gatsby-plugin-google-gtag/src/gatsby-browser.js +++ b/packages/gatsby-plugin-google-gtag/src/gatsby-browser.js @@ -1,9 +1,12 @@ -exports.onRouteUpdate = ({ location }, pluginOptions = {}) => { +/** + * @type {import('gatsby').GatsbyBrowser["onRouteUpdate"]} + */ +exports.onRouteUpdate = ({ location }, { pluginConfig }) => { if (process.env.NODE_ENV !== `production` || typeof gtag !== `function`) { return null } - const pluginConfig = pluginOptions.pluginConfig || {} + const { delayOnRouteUpdate } = pluginConfig const pathIsExcluded = location && @@ -20,8 +23,6 @@ exports.onRouteUpdate = ({ location }, pluginOptions = {}) => { window.gtag(`event`, `page_view`, { page_path: pagePath }) } - const { delayOnRouteUpdate = 0 } = pluginConfig - if (`requestAnimationFrame` in window) { requestAnimationFrame(() => { requestAnimationFrame(() => setTimeout(sendPageView, delayOnRouteUpdate)) diff --git a/packages/gatsby-plugin-google-gtag/src/gatsby-ssr.js b/packages/gatsby-plugin-google-gtag/src/gatsby-ssr.js index 17d096706a28a..d68c0eabf10e8 100644 --- a/packages/gatsby-plugin-google-gtag/src/gatsby-ssr.js +++ b/packages/gatsby-plugin-google-gtag/src/gatsby-ssr.js @@ -1,22 +1,34 @@ +// @ts-check + import React from "react" import { Minimatch } from "minimatch" +/** + * @type {import('gatsby').GatsbySSR["onRenderBody"]} + */ exports.onRenderBody = ( { setHeadComponents, setPostBodyComponents }, - pluginOptions + { trackingIds, gtagConfig, pluginConfig } ) => { - if (process.env.NODE_ENV !== `production` && process.env.NODE_ENV !== `test`) + if ( + process.env.NODE_ENV !== `production` && + process.env.NODE_ENV !== `test` + ) { return null - - const gtagConfig = pluginOptions.gtagConfig || {} - const pluginConfig = pluginOptions.pluginConfig || {} - - const origin = pluginConfig.origin || `https://www.googletagmanager.com` + } // Lighthouse recommends pre-connecting to google tag manager setHeadComponents([ - , - , + , + , ]) // Prevent duplicate or excluded pageview events being emitted on initial load of page by the `config` command @@ -24,13 +36,10 @@ exports.onRenderBody = ( gtagConfig.send_page_view = false - const firstTrackingId = - pluginOptions.trackingIds && pluginOptions.trackingIds.length - ? pluginOptions.trackingIds[0] - : `` + const firstTrackingId = trackingIds[0] const excludeGtagPaths = [] - if (typeof pluginConfig.exclude !== `undefined`) { + if (pluginConfig.exclude.length > 0) { pluginConfig.exclude.map(exclude => { const mm = new Minimatch(exclude) excludeGtagPaths.push(mm.makeRe()) @@ -48,13 +57,12 @@ exports.onRenderBody = ( : `` } ${ - typeof gtagConfig.anonymize_ip !== `undefined` && gtagConfig.anonymize_ip === true ? `function gaOptout(){document.cookie=disableStr+'=true; expires=Thu, 31 Dec 2099 23:59:59 UTC;path=/',window[disableStr]=!0}var gaProperty='${firstTrackingId}',disableStr='ga-disable-'+gaProperty;document.cookie.indexOf(disableStr+'=true')>-1&&(window[disableStr]=!0);` : `` } if(${ - pluginConfig.respectDNT + pluginConfig.respectDNT === true ? `!(navigator.doNotTrack == "1" || window.doNotTrack == "1")` : `true` }) { @@ -62,7 +70,7 @@ exports.onRenderBody = ( function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); - ${pluginOptions.trackingIds + ${trackingIds .map( trackingId => `gtag('config', '${trackingId}', ${JSON.stringify(gtagConfig)});` @@ -75,7 +83,7 @@ exports.onRenderBody = (