Skip to content

Commit ad05939

Browse files
committed
Add RUM's react plugin injection
1 parent 5f3ea86 commit ad05939

File tree

14 files changed

+201
-6
lines changed

14 files changed

+201
-6
lines changed
Binary file not shown.

LICENSES-3rdparty.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ Component,Origin,Licence,Copyright
118118
@datadog/browser-core,npm,Apache-2.0,(https://www.npmjs.com/package/@datadog/browser-core)
119119
@datadog/browser-rum,virtual,Apache-2.0,(https://www.npmjs.com/package/@datadog/browser-rum)
120120
@datadog/browser-rum-core,npm,Apache-2.0,(https://www.npmjs.com/package/@datadog/browser-rum-core)
121+
@datadog/browser-rum-react,virtual,Apache-2.0,(https://www.npmjs.com/package/@datadog/browser-rum-react)
121122
@esbuild/darwin-arm64,npm,MIT,(https://www.npmjs.com/package/@esbuild/darwin-arm64)
122123
@esbuild/linux-x64,npm,MIT,(https://www.npmjs.com/package/@esbuild/linux-x64)
123124
@eslint-community/eslint-utils,virtual,MIT,Toru Nagashima (https://github.com/eslint-community/eslint-utils#readme)

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ Follow the specific documentation for each bundler:
104104
};
105105
rum?: {
106106
disabled?: boolean;
107+
react?: {
108+
router?: boolean;
109+
};
107110
sdk?: {
108111
actionNameAttribute?: string;
109112
allowedTracingUrls?: string[];
@@ -327,6 +330,9 @@ datadogWebpackPlugin({
327330
datadogWebpackPlugin({
328331
rum?: {
329332
disabled?: boolean,
333+
react?: {
334+
router?: boolean,
335+
},
330336
sdk?: {
331337
actionNameAttribute?: string,
332338
allowedTracingUrls?: string[],

packages/plugins/rum/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Interact with Real User Monitoring (RUM) directly from your build system.
1010

1111
<!-- #toc -->
1212
- [Configuration](#configuration)
13+
- [React instrumentation](#react-instrumentation)
14+
- [rum.react.router (alpha)](#rumreactrouter-alpha)
1315
- [Browser SDK Injection](#browser-sdk-injection)
1416
- [rum.sdk.applicationId](#rumsdkapplicationid)
1517
- [rum.sdk.clientToken](#rumsdkclienttoken)
@@ -48,6 +50,9 @@ Interact with Real User Monitoring (RUM) directly from your build system.
4850
```ts
4951
rum?: {
5052
disabled?: boolean;
53+
react?: {
54+
router?: boolean;
55+
};
5156
sdk?: {
5257
actionNameAttribute?: string;
5358
allowedTracingUrls?: string[];
@@ -92,6 +97,25 @@ rum: {
9297
}
9398
```
9499

100+
## React instrumentation
101+
102+
Automatically inject and instrument [RUM's React and React Router integrations](https://github.com/DataDog/browser-sdk/tree/main/packages/rum-react#react-router-integration).
103+
104+
### rum.react.router (alpha)
105+
106+
> default: false
107+
108+
It will:
109+
110+
1. inject `@datadog/browser-rum-react` into your bundle.
111+
2. enable the plugin in the RUM SDK.
112+
3. automatically instrument your React Router routes.
113+
a. For now, it only instruments `createBrowserRouter`.
114+
115+
> [!IMPORTANT]
116+
> - You need to have `react`, `react-dom` and `react-router-dom` into your dependencies.
117+
> - This feature is in alpha and may not work as expected in all cases.
118+
95119
## Browser SDK Injection
96120

97121
Automatically inject the RUM SDK into your application.

packages/plugins/rum/package.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414
"toBuild": {
1515
"rum-browser-sdk": {
1616
"entry": "./src/built/rum-browser-sdk.ts"
17+
},
18+
"rum-react-plugin": {
19+
"entry": "./src/built/rum-react-plugin.ts",
20+
"external": [
21+
"react",
22+
"react-router-dom"
23+
]
1724
}
1825
},
1926
"exports": {
@@ -28,6 +35,7 @@
2835
"chalk": "2.3.1"
2936
},
3037
"devDependencies": {
31-
"@datadog/browser-rum": "6.0.0"
38+
"@datadog/browser-rum": "6.0.0",
39+
"@datadog/browser-rum-react": "6.0.0"
3240
}
3341
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Unless explicitly stated otherwise all files in this repository are licensed under the MIT License.
2+
// This product includes software developed at Datadog (https://www.datadoghq.com/).
3+
// Copyright 2019-Present Datadog, Inc.
4+
5+
import { createBrowserRouter } from '@datadog/browser-rum-react/react-router-v6';
6+
import { reactPlugin } from '@datadog/browser-rum-react';
7+
8+
// To please TypeScript.
9+
const globalAny: any = global;
10+
11+
// Have them globally available.
12+
globalAny.reactPlugin = reactPlugin;
13+
globalAny.createBrowserRouter = createBrowserRouter;
14+
15+
// Also them to the global DD_RUM object.
16+
globalAny.DD_RUM = globalAny.DD_RUM || {};
17+
globalAny.DD_RUM.reactPlugin = reactPlugin;
18+
globalAny.DD_RUM.createBrowserRouter = createBrowserRouter;

packages/plugins/rum/src/index.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { InjectPosition } from '@dd/core/types';
77
import path from 'path';
88

99
import { CONFIG_KEY, PLUGIN_NAME } from './constants';
10+
import { getReactPlugin } from './react';
1011
import { getInjectionValue } from './sdk';
1112
import type { OptionsWithRum, RumOptions, RumOptionsWithSdk } from './types';
1213
import { validateOptions } from './validate';
@@ -37,12 +38,26 @@ export const getPlugins: GetPlugins<OptionsWithRum> = (
3738
// Inject the SDK from the CDN.
3839
context.inject({
3940
type: 'file',
40-
// Using MIDDLE otherwise it's not executed in context.
41+
// Using MIDDLE otherwise it's not executed before the rum react plugin injection.
4142
position: InjectPosition.MIDDLE,
4243
// This file is being built alongside the bundler plugin.
4344
value: path.join(__dirname, './rum-browser-sdk.js'),
4445
});
4546

47+
if (options.react?.router) {
48+
// Inject the rum-react-plugin.
49+
context.inject({
50+
type: 'file',
51+
// It's MIDDLE in order to be able to import "react", "react-dom" and "react-router-dom".
52+
// If put in BEFORE, it would not have access to the dependencies of the user's project.
53+
position: InjectPosition.MIDDLE,
54+
// This file is being built alongside the bundler plugin.
55+
value: path.join(__dirname, './rum-react-plugin.js'),
56+
});
57+
58+
plugins.push(getReactPlugin());
59+
}
60+
4661
// Inject the SDK Initialization.
4762
context.inject({
4863
type: 'code',

packages/plugins/rum/src/react.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Unless explicitly stated otherwise all files in this repository are licensed under the MIT License.
2+
// This product includes software developed at Datadog (https://www.datadoghq.com/).
3+
// Copyright 2019-Present Datadog, Inc.
4+
5+
import type { PluginOptions } from '@dd/core/types';
6+
7+
export const getReactPlugin = (): PluginOptions => {
8+
return {
9+
name: 'datadog-rum-react-plugin',
10+
transform(code) {
11+
let updatedCode = code;
12+
const createBrowserRouterImportRegExp = new RegExp(
13+
/(import \{.*)createBrowserRouter[,]?(.*\} from "react-router-dom")/g,
14+
);
15+
const hasCreateBrowserRouterImport =
16+
code.match(createBrowserRouterImportRegExp) !== null;
17+
18+
if (hasCreateBrowserRouterImport) {
19+
// Remove the import of createBrowserRouter
20+
updatedCode = updatedCode.replace(createBrowserRouterImportRegExp, (_, p1, p2) => {
21+
return `${p1}${p2}`;
22+
});
23+
24+
// replace all occurences of `createBrowserRouter` with `DD_RUM.createBrowserRouter`
25+
updatedCode = updatedCode.replace(
26+
new RegExp(/createBrowserRouter/g),
27+
'DD_RUM.createBrowserRouter',
28+
);
29+
}
30+
31+
return updatedCode;
32+
},
33+
transformInclude(id) {
34+
return id.match(new RegExp(/.*\.(js|jsx|ts|tsx)$/)) !== null;
35+
},
36+
};
37+
};

packages/plugins/rum/src/sdk.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ type RumAppResponse = {
1616
};
1717

1818
const getContent = (opts: RumOptionsWithDefaults) => {
19-
return `global.DD_RUM.init({${JSON.stringify(opts.sdk).replace(/(^{|}$)/g, '')}});
19+
const pluginContent = opts.react?.router ? ',plugins:[reactPlugin({router:true})]' : '';
20+
return `global.DD_RUM.init({${JSON.stringify(opts.sdk).replace(/(^{|}$)/g, '')}${pluginContent}});
2021
`;
2122
};
2223

packages/plugins/rum/src/types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type { CONFIG_KEY } from './constants';
99
export type RumOptions = {
1010
disabled?: boolean;
1111
sdk?: SDKOptions;
12+
react?: ReactOptions;
1213
};
1314

1415
export type SDKOptions = {
@@ -59,12 +60,23 @@ export type SDKOptionsWithDefaults = Assign<
5960
}
6061
>;
6162

63+
export type ReactOptions = {
64+
router?: boolean;
65+
};
66+
67+
export type ReactOptionsWithDefaults = Required<ReactOptions>;
68+
6269
export type RumOptionsWithDefaults = {
6370
disabled?: boolean;
6471
sdk?: SDKOptionsWithDefaults;
72+
react?: ReactOptionsWithDefaults;
6573
};
6674

6775
export type RumOptionsWithSdk = Assign<RumOptionsWithDefaults, { sdk: SDKOptionsWithDefaults }>;
76+
export type RumOptionsWithReact = Assign<
77+
RumOptionsWithDefaults,
78+
{ react: ReactOptionsWithDefaults }
79+
>;
6880

6981
export interface OptionsWithRum extends GetPluginsOptions {
7082
[CONFIG_KEY]: RumOptions;

0 commit comments

Comments
 (0)