refactor(ganalytics, gtag): move options out of themeConfig (#5832)

* refactor(ganalytics, gtag): move options out of themeConfig

* Forbid themeConfig options

* Add PR link

* Add key names to error message

* Fix?

* Doc updates

Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com>
This commit is contained in:
Joshua Chen 2021-11-10 19:04:43 +08:00 committed by GitHub
parent f5732e7589
commit ac88d979f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 274 additions and 106 deletions

View file

@ -22,7 +22,7 @@ declare module '@generated/site-metadata' {
import type {DocusaurusSiteMetadata} from '@docusaurus/types'; import type {DocusaurusSiteMetadata} from '@docusaurus/types';
const siteMetadata: DocusaurusSiteMetadata; const siteMetadata: DocusaurusSiteMetadata;
export default siteMetadata; export = siteMetadata;
} }
declare module '@generated/registry' { declare module '@generated/registry' {
@ -48,13 +48,13 @@ declare module '@generated/routes' {
declare module '@generated/routesChunkNames' { declare module '@generated/routesChunkNames' {
const routesChunkNames: Record<string, Record<string, string>>; const routesChunkNames: Record<string, Record<string, string>>;
export default routesChunkNames; export = routesChunkNames;
} }
declare module '@generated/globalData' { declare module '@generated/globalData' {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const globalData: Record<string, any>; const globalData: Record<string, any>;
export default globalData; export = globalData;
} }
declare module '@generated/i18n' { declare module '@generated/i18n' {
@ -64,12 +64,12 @@ declare module '@generated/i18n' {
currentLocale: string; currentLocale: string;
localeConfigs: Record<string, {label: string; direction: string}>; localeConfigs: Record<string, {label: string; direction: string}>;
}; };
export default i18n; export = i18n;
} }
declare module '@generated/codeTranslations' { declare module '@generated/codeTranslations' {
const codeTranslations: Record<string, string>; const codeTranslations: Record<string, string>;
export default codeTranslations; export = codeTranslations;
} }
declare module '@theme-original/*'; declare module '@theme-original/*';

View file

@ -18,7 +18,8 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-beta.9" "@docusaurus/core": "2.0.0-beta.9",
"@docusaurus/utils-validation": "2.0.0-beta.9"
}, },
"devDependencies": { "devDependencies": {
"@docusaurus/types": "2.0.0-beta.9" "@docusaurus/types": "2.0.0-beta.9"

View file

@ -6,30 +6,23 @@
*/ */
import path from 'path'; import path from 'path';
import type {LoadContext, Plugin, HtmlTags} from '@docusaurus/types'; import {Joi} from '@docusaurus/utils-validation';
import type {ThemeConfig} from '@docusaurus/plugin-google-analytics'; import type {
LoadContext,
export default function pluginGoogleAnalytics(context: LoadContext): Plugin { Plugin,
const { HtmlTags,
siteConfig: {themeConfig}, OptionValidationContext,
} = context; ValidationResult,
const {googleAnalytics} = themeConfig as ThemeConfig; ThemeConfig,
ThemeConfigValidationContext,
if (!googleAnalytics) { } from '@docusaurus/types';
throw new Error( import type {PluginOptions} from '@docusaurus/plugin-google-analytics';
`You need to specify "googleAnalytics" object in "themeConfig" with "trackingId" field in it to use docusaurus-plugin-google-analytics.`,
);
}
const {trackingID, anonymizeIP} = googleAnalytics;
if (!trackingID) {
throw new Error(
'You specified the "googleAnalytics" object in "themeConfig" but the "trackingID" field was missing. ' +
'Please ensure this is not a mistake.',
);
}
export default function pluginGoogleAnalytics(
context: LoadContext,
options: PluginOptions,
): Plugin {
const {trackingID, anonymizeIP} = options;
const isProd = process.env.NODE_ENV === 'production'; const isProd = process.env.NODE_ENV === 'production';
return { return {
@ -74,3 +67,26 @@ export default function pluginGoogleAnalytics(context: LoadContext): Plugin {
}, },
}; };
} }
const pluginOptionsSchema = Joi.object<PluginOptions>({
trackingID: Joi.string().required(),
anonymizeIP: Joi.boolean().default(false),
});
export function validateOptions({
validate,
options,
}: OptionValidationContext<PluginOptions>): ValidationResult<PluginOptions> {
return validate(pluginOptionsSchema, options);
}
export function validateThemeConfig({
themeConfig,
}: ThemeConfigValidationContext<ThemeConfig>): ValidationResult<ThemeConfig> {
if (themeConfig.googleAnalytics) {
throw new Error(
'The "googleAnalytics" field in themeConfig should now be specified as option for plugin-google-analytics. More information at https://github.com/facebook/docusaurus/pull/5832.',
);
}
return themeConfig;
}

View file

@ -5,9 +5,9 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
export interface ThemeConfig { export type PluginOptions = {
googleAnalytics?: { trackingID: string;
trackingID: string; anonymizeIP: boolean;
anonymizeIP?: boolean; };
};
} export type Options = Partial<PluginOptions>;

View file

@ -18,7 +18,8 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-beta.9" "@docusaurus/core": "2.0.0-beta.9",
"@docusaurus/utils-validation": "2.0.0-beta.9"
}, },
"devDependencies": { "devDependencies": {
"@docusaurus/types": "2.0.0-beta.9" "@docusaurus/types": "2.0.0-beta.9"

View file

@ -6,17 +6,16 @@
*/ */
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
import siteConfig from '@generated/docusaurus.config'; import globalData from '@generated/globalData';
import type {ThemeConfig} from '@docusaurus/plugin-google-gtag'; import type {PluginOptions} from '@docusaurus/plugin-google-gtag';
export default (function () { export default (function () {
if (!ExecutionEnvironment.canUseDOM) { if (!ExecutionEnvironment.canUseDOM) {
return null; return null;
} }
const {themeConfig} = siteConfig; const {trackingID} = globalData['docusaurus-plugin-google-gtag']
const {gtag} = themeConfig as ThemeConfig; .default as PluginOptions;
const {trackingID} = gtag!;
return { return {
onRouteUpdate({location}: {location: Location}) { onRouteUpdate({location}: {location: Location}) {

View file

@ -6,35 +6,32 @@
*/ */
import path from 'path'; import path from 'path';
import type {LoadContext, Plugin, HtmlTags} from '@docusaurus/types'; import {Joi} from '@docusaurus/utils-validation';
import type {ThemeConfig} from '@docusaurus/plugin-google-gtag'; import type {
LoadContext,
export default function pluginGoogleGtag(context: LoadContext): Plugin { Plugin,
const { HtmlTags,
siteConfig: {themeConfig}, OptionValidationContext,
} = context; ValidationResult,
const {gtag} = themeConfig as ThemeConfig; ThemeConfig,
ThemeConfigValidationContext,
if (!gtag) { } from '@docusaurus/types';
throw new Error( import type {PluginOptions} from '@docusaurus/plugin-google-gtag';
`You need to specify "gtag" object in "themeConfig" with "trackingId" field in it to use docusaurus-plugin-google-gtag.`,
);
}
const {anonymizeIP, trackingID} = gtag;
if (!trackingID) {
throw new Error(
'You specified the "gtag" object in "themeConfig" but the "trackingID" field was missing. ' +
'Please ensure this is not a mistake.',
);
}
export default function pluginGoogleGtag(
context: LoadContext,
options: PluginOptions,
): Plugin {
const {anonymizeIP, trackingID} = options;
const isProd = process.env.NODE_ENV === 'production'; const isProd = process.env.NODE_ENV === 'production';
return { return {
name: 'docusaurus-plugin-google-gtag', name: 'docusaurus-plugin-google-gtag',
async contentLoaded({actions}) {
actions.setGlobalData(options);
},
getClientModules() { getClientModules() {
return isProd ? [path.resolve(__dirname, './gtag')] : []; return isProd ? [path.resolve(__dirname, './gtag')] : [];
}, },
@ -83,3 +80,26 @@ export default function pluginGoogleGtag(context: LoadContext): Plugin {
}, },
}; };
} }
const pluginOptionsSchema = Joi.object<PluginOptions>({
trackingID: Joi.string().required(),
anonymizeIP: Joi.boolean().default(false),
});
export function validateOptions({
validate,
options,
}: OptionValidationContext<PluginOptions>): ValidationResult<PluginOptions> {
return validate(pluginOptionsSchema, options);
}
export function validateThemeConfig({
themeConfig,
}: ThemeConfigValidationContext<ThemeConfig>): ValidationResult<ThemeConfig> {
if (themeConfig.gtag) {
throw new Error(
'The "gtag" field in themeConfig should now be specified as option for plugin-google-gtag. More information at https://github.com/facebook/docusaurus/pull/5832.',
);
}
return themeConfig;
}

View file

@ -5,9 +5,9 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
export interface ThemeConfig { export type PluginOptions = {
gtag?: { trackingID: string;
trackingID: string; anonymizeIP: boolean;
anonymizeIP?: boolean; };
};
} export type Options = Partial<PluginOptions>;

View file

@ -29,9 +29,19 @@ export default function preset(
): Preset { ): Preset {
const {siteConfig} = context; const {siteConfig} = context;
const {themeConfig} = siteConfig; const {themeConfig} = siteConfig;
const {algolia, googleAnalytics, gtag} = themeConfig as Partial<ThemeConfig>; const {algolia} = themeConfig as Partial<ThemeConfig>;
const isProd = process.env.NODE_ENV === 'production'; const isProd = process.env.NODE_ENV === 'production';
const {debug, docs, blog, pages, sitemap, theme, ...rest} = opts; const {
debug,
docs,
blog,
pages,
sitemap,
theme,
googleAnalytics,
gtag,
...rest
} = opts;
const themes: PluginConfig[] = []; const themes: PluginConfig[] = [];
themes.push(makePluginConfig('@docusaurus/theme-classic', theme)); themes.push(makePluginConfig('@docusaurus/theme-classic', theme));
@ -50,13 +60,15 @@ export default function preset(
plugins.push(makePluginConfig('@docusaurus/plugin-content-pages', pages)); plugins.push(makePluginConfig('@docusaurus/plugin-content-pages', pages));
} }
if (isProd && googleAnalytics) { if (isProd && googleAnalytics) {
plugins.push(require.resolve('@docusaurus/plugin-google-analytics')); plugins.push(
makePluginConfig('@docusaurus/plugin-google-analytics', googleAnalytics),
);
} }
if (debug || (debug === undefined && !isProd)) { if (debug || (debug === undefined && !isProd)) {
plugins.push(require.resolve('@docusaurus/plugin-debug')); plugins.push(require.resolve('@docusaurus/plugin-debug'));
} }
if (isProd && gtag) { if (isProd && gtag) {
plugins.push(require.resolve('@docusaurus/plugin-google-gtag')); plugins.push(makePluginConfig('@docusaurus/plugin-google-gtag', gtag));
} }
if (isProd && sitemap !== false) { if (isProd && sitemap !== false) {
plugins.push(makePluginConfig('@docusaurus/plugin-sitemap', sitemap)); plugins.push(makePluginConfig('@docusaurus/plugin-sitemap', sitemap));
@ -65,7 +77,7 @@ export default function preset(
throw new Error( throw new Error(
`Unrecognized keys ${Object.keys(rest).join( `Unrecognized keys ${Object.keys(rest).join(
', ', ', ',
)} found in preset-classic configuration. The allowed keys are debug, docs, blog, pages, sitemap, theme. Check the documentation: https://docusaurus.io/docs/presets#docusauruspreset-classic for more information on how to configure individual plugins.`, )} found in preset-classic configuration. The allowed keys are debug, docs, blog, pages, sitemap, theme, googleAnalytics, gtag. Check the documentation: https://docusaurus.io/docs/presets#docusauruspreset-classic for more information on how to configure individual plugins.`,
); );
} }

View file

@ -12,13 +12,11 @@ export type Options = {
pages?: false | import('@docusaurus/plugin-content-pages').Options; pages?: false | import('@docusaurus/plugin-content-pages').Options;
sitemap?: false | import('@docusaurus/plugin-sitemap').Options; sitemap?: false | import('@docusaurus/plugin-sitemap').Options;
theme?: import('@docusaurus/theme-classic').Options; theme?: import('@docusaurus/theme-classic').Options;
googleAnalytics?: import('@docusaurus/plugin-google-analytics').Options;
gtag?: import('@docusaurus/plugin-google-gtag').Options;
}; };
export type ThemeConfig = import('@docusaurus/types').ThemeConfig & export type ThemeConfig = import('@docusaurus/types').ThemeConfig &
import('@docusaurus/theme-common').UserThemeConfig & import('@docusaurus/theme-common').UserThemeConfig & {
// Those plugins themeConfigs should rather be moved to preset/plugin options
// Plugin data can be made available to browser thank to the globalData api
import('@docusaurus/plugin-google-analytics').ThemeConfig &
import('@docusaurus/plugin-google-gtag').ThemeConfig & {
algolia?: unknown; // TODO type plugin algolia?: unknown; // TODO type plugin
}; };

View file

@ -21,15 +21,74 @@ If you have installed `@docusaurus/preset-classic`, you don't need to install it
## Configuration {#configuration} ## Configuration {#configuration}
```js title="docusaurus.config.js" Accepted fields:
module.exports = {
plugins: ['@docusaurus/plugin-google-analytics'], <small>
themeConfig: {
googleAnalytics: { | Name | Type | Default | Description |
trackingID: 'UA-141789564-1', | --- | --- | --- | --- |
// Optional fields. | `trackingID` | `string` | **Required** | The tracking ID of your analytics service. |
anonymizeIP: true, // Should IPs be anonymized? | `anonymizeIP` | `boolean` | `false` | Whether the IP should be anonymized when sending requests. |
},
}, </small>
## Example configuration {#ex-config}
Here's an example configuration object.
You can provide it as [preset options](#ex-config-preset) or [plugin options](#ex-config-plugin).
:::tip
Most Docusaurus users configure this plugin through the [preset options](#ex-config-preset).
:::
```js
const config = {
trackingID: 'UA-141789564-1',
anonymizeIP: true,
};
```
### Preset options {#ex-config-preset}
If you use a preset, configure this plugin through the [preset options](presets.md#docusauruspreset-classic):
```js title="docusaurus.config.js"
module.exports = {
presets: [
[
'@docusaurus/preset-classic',
{
// highlight-start
googleAnalytics: {
trackingID: 'UA-141789564-1',
anonymizeIP: true,
},
// highlight-end
},
],
],
};
```
### Plugin options {#ex-config-plugin}
If you are using a standalone plugin, provide options directly to the plugin:
```js title="docusaurus.config.js"
module.exports = {
plugins: [
[
'@docusaurus/plugin-google-analytics',
// highlight-start
{
trackingID: 'UA-141789564-1',
anonymizeIP: true,
},
// highlight-end
],
],
}; };
``` ```

View file

@ -27,16 +27,74 @@ If you have installed `@docusaurus/preset-classic`, you don't need to install it
## Configuration {#configuration} ## Configuration {#configuration}
```js title="docusaurus.config.js" Accepted fields:
module.exports = {
plugins: ['@docusaurus/plugin-google-gtag'], <small>
themeConfig: {
gtag: { | Name | Type | Default | Description |
// You can also use your "G-" Measurement ID here. | --- | --- | --- | --- |
trackingID: 'UA-141789564-1', | `trackingID` | `string` | **Required** | The tracking ID of your gtag service. |
// Optional fields. | `anonymizeIP` | `boolean` | `false` | Whether the IP should be anonymized when sending requests. |
anonymizeIP: true, // Should IPs be anonymized?
}, </small>
},
## Example configuration {#ex-config}
Here's an example configuration object.
You can provide it as [preset options](#ex-config-preset) or [plugin options](#ex-config-plugin).
:::tip
Most Docusaurus users configure this plugin through the [preset options](#ex-config-preset).
:::
```js
const config = {
trackingID: 'UA-141789564-1',
anonymizeIP: true,
};
```
### Preset options {#ex-config-preset}
If you use a preset, configure this plugin through the [preset options](presets.md#docusauruspreset-classic):
```js title="docusaurus.config.js"
module.exports = {
presets: [
[
'@docusaurus/preset-classic',
{
// highlight-start
gtag: {
trackingID: 'UA-141789564-1',
anonymizeIP: true,
},
// highlight-end
},
],
],
};
```
### Plugin options {#ex-config-plugin}
If you are using a standalone plugin, provide options directly to the plugin:
```js title="docusaurus.config.js"
module.exports = {
plugins: [
[
'@docusaurus/plugin-google-gtag',
// highlight-start
{
trackingID: 'UA-141789564-1',
anonymizeIP: true,
},
// highlight-end
],
],
}; };
``` ```

View file

@ -106,6 +106,10 @@ module.exports = {
pages: {}, pages: {},
// Will be passed to @docusaurus/plugin-content-sitemap (false to disable) // Will be passed to @docusaurus/plugin-content-sitemap (false to disable)
sitemap: {}, sitemap: {},
// Will be passed to @docusaurus/plugin-google-gtag (only enabled when explicitly specified)
gtag: {},
// Will be passed to @docusaurus/plugin-google-analytics (only enabled when explicitly specified)
googleAnalytics: {},
}, },
], ],
], ],

View file

@ -301,6 +301,11 @@ const config = {
theme: { theme: {
customCss: [require.resolve('./src/css/custom.css')], customCss: [require.resolve('./src/css/custom.css')],
}, },
gtag: !isDeployPreview
? {
trackingID: 'UA-141789564-1',
}
: undefined,
}), }),
], ],
], ],
@ -328,11 +333,6 @@ const config = {
}, },
image: 'img/docusaurus-soc.png', image: 'img/docusaurus-soc.png',
// metadata: [{name: 'twitter:card', content: 'summary'}], // metadata: [{name: 'twitter:card', content: 'summary'}],
gtag: !isDeployPreview
? {
trackingID: 'UA-141789564-1',
}
: undefined,
algolia: { algolia: {
appId: 'X1Z85QJPUV', appId: 'X1Z85QJPUV',
apiKey: 'bf7211c161e8205da2f933a02534105a', apiKey: 'bf7211c161e8205da2f933a02534105a',