Skip to content

Commit f5f7511

Browse files
authored
Add a window var for CWV Tech Report to look for (#11222)
1 parent add6f8a commit f5f7511

File tree

6 files changed

+156
-16
lines changed

6 files changed

+156
-16
lines changed

.changeset/cwv-report-id.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"react-router-dom-v5-compat": minor
3+
"react-router-dom": minor
4+
---
5+
6+
Include a window tag for CWV Report detection

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,10 @@
125125
"none": "17.1 kB"
126126
},
127127
"packages/react-router-dom/dist/react-router-dom.production.min.js": {
128-
"none": "16.9 kB"
128+
"none": "17.0 kB"
129129
},
130130
"packages/react-router-dom/dist/umd/react-router-dom.production.min.js": {
131-
"none": "23.1 kB"
131+
"none": "23.2 kB"
132132
}
133133
}
134134
}

packages/react-router-dom-v5-compat/rollup.config.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ const replace = require("@rollup/plugin-replace");
77
const { terser } = require("rollup-plugin-terser");
88
const typescript = require("@rollup/plugin-typescript");
99
const {
10+
babelPluginReplaceVersionPlaceholder,
1011
createBanner,
1112
getBuildDirectories,
13+
validateReplacedVersion,
1214
PRETTY,
1315
} = require("../../rollup.utils");
1416
const { name, version } = require("./package.json");
@@ -57,7 +59,10 @@ module.exports = function rollup() {
5759
"@babel/preset-react",
5860
"@babel/preset-typescript",
5961
],
60-
plugins: ["babel-plugin-dev-expression"],
62+
plugins: [
63+
"babel-plugin-dev-expression",
64+
babelPluginReplaceVersionPlaceholder(),
65+
],
6166
extensions: [".ts", ".tsx"],
6267
}),
6368
typescript({
@@ -71,6 +76,7 @@ module.exports = function rollup() {
7176
],
7277
verbose: true,
7378
}),
79+
validateReplacedVersion(),
7480
].concat(PRETTY ? prettier({ parser: "babel" }) : []),
7581
},
7682
];
@@ -110,13 +116,17 @@ module.exports = function rollup() {
110116
"@babel/preset-react",
111117
"@babel/preset-typescript",
112118
],
113-
plugins: ["babel-plugin-dev-expression"],
119+
plugins: [
120+
"babel-plugin-dev-expression",
121+
babelPluginReplaceVersionPlaceholder(),
122+
],
114123
extensions: [".ts", ".tsx"],
115124
}),
116125
replace({
117126
preventAssignment: true,
118127
values: { "process.env.NODE_ENV": JSON.stringify("development") },
119128
}),
129+
validateReplacedVersion(),
120130
].concat(PRETTY ? prettier({ parser: "babel" }) : []),
121131
},
122132
{
@@ -152,14 +162,18 @@ module.exports = function rollup() {
152162
"@babel/preset-react",
153163
"@babel/preset-typescript",
154164
],
155-
plugins: ["babel-plugin-dev-expression"],
165+
plugins: [
166+
"babel-plugin-dev-expression",
167+
babelPluginReplaceVersionPlaceholder(),
168+
],
156169
extensions: [".ts", ".tsx"],
157170
}),
158171
replace({
159172
preventAssignment: true,
160173
values: { "process.env.NODE_ENV": JSON.stringify("production") },
161174
}),
162175
terser(),
176+
validateReplacedVersion(),
163177
].concat(PRETTY ? prettier({ parser: "babel" }) : []),
164178
},
165179
];

packages/react-router-dom/index.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,11 +218,28 @@ export {
218218

219219
declare global {
220220
var __staticRouterHydrationData: HydrationState | undefined;
221+
var __reactRouterVersion: string;
221222
interface Document {
222223
startViewTransition(cb: () => Promise<void> | void): ViewTransition;
223224
}
224225
}
225226

227+
// HEY YOU! DON'T TOUCH THIS VARIABLE!
228+
//
229+
// It is replaced with the proper version at build time via a babel plugin in
230+
// the rollup config.
231+
//
232+
// Export a global property onto the window for React Router detection by the
233+
// Core Web Vitals Technology Report. This way they can configure the `wappalyzer`
234+
// to detect and properly classify live websites as being built with React Router:
235+
// https://github.com/HTTPArchive/wappalyzer/blob/main/src/technologies/r.json
236+
const REACT_ROUTER_VERSION = "0";
237+
try {
238+
window.__reactRouterVersion = REACT_ROUTER_VERSION;
239+
} catch (e) {
240+
// no-op
241+
}
242+
226243
////////////////////////////////////////////////////////////////////////////////
227244
//#region Routers
228245
////////////////////////////////////////////////////////////////////////////////

packages/react-router-dom/rollup.config.js

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ const replace = require("@rollup/plugin-replace");
77
const { terser } = require("rollup-plugin-terser");
88
const typescript = require("@rollup/plugin-typescript");
99
const {
10+
babelPluginReplaceVersionPlaceholder,
1011
createBanner,
1112
getBuildDirectories,
13+
validateReplacedVersion,
1214
PRETTY,
1315
} = require("../../rollup.utils");
1416
const { name, version } = require("./package.json");
@@ -37,7 +39,10 @@ module.exports = function rollup() {
3739
"@babel/preset-react",
3840
"@babel/preset-typescript",
3941
],
40-
plugins: ["babel-plugin-dev-expression"],
42+
plugins: [
43+
"babel-plugin-dev-expression",
44+
babelPluginReplaceVersionPlaceholder(),
45+
],
4146
extensions: [".ts", ".tsx"],
4247
}),
4348
typescript({
@@ -51,6 +56,7 @@ module.exports = function rollup() {
5156
],
5257
verbose: true,
5358
}),
59+
validateReplacedVersion(),
5460
].concat(PRETTY ? prettier({ parser: "babel" }) : []),
5561
},
5662
];
@@ -78,13 +84,17 @@ module.exports = function rollup() {
7884
"@babel/preset-react",
7985
"@babel/preset-typescript",
8086
],
81-
plugins: ["babel-plugin-dev-expression"],
87+
plugins: [
88+
"babel-plugin-dev-expression",
89+
babelPluginReplaceVersionPlaceholder(),
90+
],
8291
extensions: [".ts", ".tsx"],
8392
}),
8493
replace({
8594
preventAssignment: true,
8695
values: { "process.env.NODE_ENV": JSON.stringify("development") },
8796
}),
97+
validateReplacedVersion(),
8898
].concat(PRETTY ? prettier({ parser: "babel" }) : []),
8999
},
90100
{
@@ -118,14 +128,17 @@ module.exports = function rollup() {
118128
],
119129
"@babel/preset-typescript",
120130
],
121-
plugins: ["babel-plugin-dev-expression"],
131+
plugins: [
132+
"babel-plugin-dev-expression",
133+
babelPluginReplaceVersionPlaceholder(),
134+
],
122135
extensions: [".ts", ".tsx"],
123136
}),
124137
replace({
125138
preventAssignment: true,
126139
values: { "process.env.NODE_ENV": JSON.stringify("production") },
127140
}),
128-
// compiler(),
141+
validateReplacedVersion(),
129142
terser({ ecma: 8, safari10: true }),
130143
].concat(PRETTY ? prettier({ parser: "babel" }) : []),
131144
},
@@ -158,13 +171,17 @@ module.exports = function rollup() {
158171
"@babel/preset-react",
159172
"@babel/preset-typescript",
160173
],
161-
plugins: ["babel-plugin-dev-expression"],
174+
plugins: [
175+
"babel-plugin-dev-expression",
176+
babelPluginReplaceVersionPlaceholder(),
177+
],
162178
extensions: [".ts", ".tsx"],
163179
}),
164180
replace({
165181
preventAssignment: true,
166182
values: { "process.env.NODE_ENV": JSON.stringify("development") },
167183
}),
184+
validateReplacedVersion(),
168185
].concat(PRETTY ? prettier({ parser: "babel" }) : []),
169186
},
170187
{
@@ -192,15 +209,18 @@ module.exports = function rollup() {
192209
"@babel/preset-react",
193210
"@babel/preset-typescript",
194211
],
195-
plugins: ["babel-plugin-dev-expression"],
212+
plugins: [
213+
"babel-plugin-dev-expression",
214+
babelPluginReplaceVersionPlaceholder(),
215+
],
196216
extensions: [".ts", ".tsx"],
197217
}),
198218
replace({
199219
preventAssignment: true,
200220
values: { "process.env.NODE_ENV": JSON.stringify("production") },
201221
}),
202-
// compiler(),
203222
terser(),
223+
validateReplacedVersion(),
204224
].concat(PRETTY ? prettier({ parser: "babel" }) : []),
205225
},
206226
];
@@ -247,7 +267,10 @@ module.exports = function rollup() {
247267
"@babel/preset-react",
248268
"@babel/preset-typescript",
249269
],
250-
plugins: ["babel-plugin-dev-expression"],
270+
plugins: [
271+
"babel-plugin-dev-expression",
272+
babelPluginReplaceVersionPlaceholder(),
273+
],
251274
extensions: [".ts", ".tsx"],
252275
}),
253276
typescript({
@@ -256,7 +279,7 @@ module.exports = function rollup() {
256279
exclude: ["__tests__"],
257280
noEmitOnError: true,
258281
}),
259-
// compiler()
282+
validateReplacedVersion(),
260283
].concat(PRETTY ? prettier({ parser: "babel" }) : []),
261284
},
262285
{
@@ -296,10 +319,13 @@ module.exports = function rollup() {
296319
"@babel/preset-react",
297320
"@babel/preset-typescript",
298321
],
299-
plugins: ["babel-plugin-dev-expression"],
322+
plugins: [
323+
"babel-plugin-dev-expression",
324+
babelPluginReplaceVersionPlaceholder(),
325+
],
300326
extensions: [".ts", ".tsx"],
301327
}),
302-
// compiler()
328+
validateReplacedVersion(),
303329
].concat(PRETTY ? prettier({ parser: "babel" }) : []),
304330
},
305331
];

rollup.utils.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
const path = require("path");
22
const fse = require("fs-extra");
3+
const { version } = require("./packages/react-router/package.json");
4+
const majorVersion = version.split(".").shift();
35

46
const PRETTY = !!process.env.PRETTY;
57

@@ -62,8 +64,83 @@ function createBanner(packageName, version) {
6264
*/`;
6365
}
6466

67+
// Babel plugin to replace `const REACT_ROUTER_VERSION = "0.0.0";` with the
68+
// current version at build time, so we can set it on `window.__reactRouterVersion`
69+
// for consumption by the Core Web Vitals Technology Report
70+
function babelPluginReplaceVersionPlaceholder() {
71+
return function (babel) {
72+
var t = babel.types;
73+
74+
const KIND = "const";
75+
const NAME = "REACT_ROUTER_VERSION";
76+
const PLACEHOLDER = "0";
77+
78+
return {
79+
visitor: {
80+
VariableDeclaration: {
81+
enter: function (path) {
82+
// Only operate on top-level variables
83+
if (!path.parentPath.isProgram()) {
84+
return;
85+
}
86+
87+
let { kind, declarations } = path.node;
88+
if (
89+
kind === KIND &&
90+
declarations.length === 1 &&
91+
declarations[0].id.name === NAME &&
92+
declarations[0].init?.value === PLACEHOLDER
93+
) {
94+
path.replaceWith(
95+
t.variableDeclaration(KIND, [
96+
t.variableDeclarator(
97+
t.identifier(NAME),
98+
t.stringLiteral(majorVersion)
99+
),
100+
])
101+
);
102+
}
103+
},
104+
},
105+
},
106+
};
107+
};
108+
}
109+
110+
// Post-build plugin to validate that the version placeholder was replaced
111+
function validateReplacedVersion() {
112+
return {
113+
name: "validate-replaced-version",
114+
writeBundle(_, bundle) {
115+
Object.entries(bundle).forEach(([filename, contents]) => {
116+
if (!filename.endsWith(".js") || filename === "server.js") {
117+
return;
118+
}
119+
120+
let requiredStrs = filename.endsWith(".min.js")
121+
? [`{window.__reactRouterVersion="${majorVersion}"}`]
122+
: [
123+
`const REACT_ROUTER_VERSION = "${majorVersion}";`,
124+
`window.__reactRouterVersion = REACT_ROUTER_VERSION;`,
125+
];
126+
127+
requiredStrs.forEach((str) => {
128+
if (!contents.code.includes(str)) {
129+
throw new Error(
130+
`Expected ${filename} to include \`${str}\` but it did not`
131+
);
132+
}
133+
});
134+
});
135+
},
136+
};
137+
}
138+
139+
// rollup.config.js
65140
module.exports = {
66141
getBuildDirectories,
67142
createBanner,
143+
babelPluginReplaceVersionPlaceholder,
144+
validateReplacedVersion,
68145
PRETTY,
69146
};

0 commit comments

Comments
 (0)