feat[devtools]: ship source maps for content scripts and ignore list installHook script (#28730)
## Summary 1. RDT browser extension's content scripts will now ship source maps (without source in prod, to save some bundle size). 2. `installHook` content script will be ignore listed via `ignoreList` field in the corresponding source map. 3. Previously, source map for backend file used `x_google_ignoreList` naming, now `ignoreList`. ## How did you test this change? 1. `ignoreList-test.js` 2. Tested manually that I don't see `installHook` in stack traces when `console.error` is called.
Ruslan Lesiutin committed
Apr 8, 2024 at 18:10 UTC
6de7733e73152ecb9a0cb8bcf73dcc1c96ca7dde
6 files changed
+111
-33
packages/react-devtools-extensions/package.json
-1
@@ -39,7 +39,6 @@
39
"chrome-launch": "^1.1.4",
40
"crx": "^5.0.0",
41
"css-loader": "^1.0.1",
42
- "devtools-ignore-webpack-plugin": "^0.1.1",
42
"file-loader": "^6.1.0",
43
"filesize": "^6.0.1",
44
"find": "^0.3.0",
packages/react-devtools-extensions/src/__tests__/ignoreList-test.js
renamed
+6
-16
@@ -12,7 +12,7 @@ import {readFileSync} from 'fs';
12
import path from 'path';
13
import {rimrafSync} from 'rimraf';
14
15
-describe('x_google_ignoreList source map extension', () => {
15
+describe('ignoreList source map extension', () => {
16
jest.setTimeout(60 * 1000);
17
18
const pathToExtensionsPackage = path.resolve(__dirname, '..', '..');
@@ -30,7 +30,7 @@ describe('x_google_ignoreList source map extension', () => {
30
});
31
32
describe('for dev builds', () => {
33
- it('should include only sources with /node_modules/ and /webpack/ in path', async () => {
33
+ it('should not ignore list anything', async () => {
34
await exec('yarn build:chrome:local', {
35
cwd: pathToExtensionsPackage,
36
});
@@ -38,18 +38,8 @@ describe('x_google_ignoreList source map extension', () => {
38
const sourceMapJSON = readFileSync(pathToSourceMap);
39
const sourceMap = JSON.parse(sourceMapJSON);
40
41
- const {sources, x_google_ignoreList} = sourceMap;
42
-
43
- const expectedIgnoreList = [];
44
- for (let sourceIndex = 0; sourceIndex < sources.length; ++sourceIndex) {
45
- const source = sources[sourceIndex];
46
-
47
- if (source.includes('/node_modules/') || source.includes('/webpack/')) {
48
- expectedIgnoreList.push(sourceIndex);
49
- }
50
- }
51
-
52
- expect(x_google_ignoreList).toEqual(expectedIgnoreList);
41
+ const {ignoreList} = sourceMap;
42
+ expect(ignoreList).toEqual([]);
43
});
44
});
45
@@ -60,9 +50,9 @@ describe('x_google_ignoreList source map extension', () => {
50
const sourceMapJSON = readFileSync(pathToSourceMap);
51
const sourceMap = JSON.parse(sourceMapJSON);
52
63
- const {sources, x_google_ignoreList} = sourceMap;
53
+ const {sources, ignoreList} = sourceMap;
54
65
- expect(sources.length).toBe(x_google_ignoreList.length);
55
+ expect(sources.length).toBe(ignoreList.length);
56
});
57
});
58
});
packages/react-devtools-extensions/webpack.backend.js
+9
-10
@@ -2,9 +2,10 @@
2
3
const {resolve} = require('path');
4
const Webpack = require('webpack');
5
-const DevToolsIgnorePlugin = require('devtools-ignore-webpack-plugin');
5
6
const {resolveFeatureFlags} = require('react-devtools-shared/buildUtils');
7
+const SourceMapIgnoreListPlugin = require('react-devtools-shared/SourceMapIgnoreListPlugin');
8
+
9
const {
10
DARK_MODE_DIMMED_WARNING_COLOR,
11
DARK_MODE_DIMMED_ERROR_COLOR,
@@ -42,7 +43,7 @@ const featureFlagTarget = process.env.FEATURE_FLAG_TARGET || 'extension-oss';
43
44
module.exports = {
45
mode: __DEV__ ? 'development' : 'production',
45
- devtool: __DEV__ ? 'cheap-module-source-map' : 'nosources-cheap-source-map',
46
+ devtool: false,
47
entry: {
48
backend: './src/backend.js',
49
},
@@ -87,14 +88,12 @@ module.exports = {
88
'process.env.IS_FIREFOX': IS_FIREFOX,
89
'process.env.IS_EDGE': IS_EDGE,
90
}),
90
- new DevToolsIgnorePlugin({
91
- shouldIgnorePath: function (path) {
92
- if (!__DEV__) {
93
- return true;
94
- }
95
-
96
- return path.includes('/node_modules/') || path.includes('/webpack/');
97
- },
91
+ new Webpack.SourceMapDevToolPlugin({
92
+ filename: '[file].map',
93
+ noSources: !__DEV__,
94
+ }),
95
+ new SourceMapIgnoreListPlugin({
96
+ shouldIgnoreSource: () => !__DEV__,
97
}),
98
],
99
module: {
packages/react-devtools-extensions/webpack.config.js
+23
-1
@@ -14,6 +14,7 @@ const {
14
getVersionString,
15
} = require('./utils');
16
const {resolveFeatureFlags} = require('react-devtools-shared/buildUtils');
17
+const SourceMapIgnoreListPlugin = require('react-devtools-shared/SourceMapIgnoreListPlugin');
18
19
const NODE_ENV = process.env.NODE_ENV;
20
if (!NODE_ENV) {
@@ -54,7 +55,7 @@ const babelOptions = {
55
56
module.exports = {
57
mode: __DEV__ ? 'development' : 'production',
57
- devtool: __DEV__ ? 'cheap-module-source-map' : false,
58
+ devtool: false,
59
entry: {
60
background: './src/background/index.js',
61
backendManager: './src/contentScripts/backendManager.js',
@@ -134,6 +135,27 @@ module.exports = {
135
'process.env.LIGHT_MODE_DIMMED_ERROR_COLOR': `"${LIGHT_MODE_DIMMED_ERROR_COLOR}"`,
136
'process.env.LIGHT_MODE_DIMMED_LOG_COLOR': `"${LIGHT_MODE_DIMMED_LOG_COLOR}"`,
137
}),
138
+ new Webpack.SourceMapDevToolPlugin({
139
+ filename: '[file].map',
140
+ noSources: !__DEV__,
141
+ }),
142
+ new SourceMapIgnoreListPlugin({
143
+ shouldIgnoreSource: (assetName, _source) => {
144
+ if (__DEV__) {
145
+ // Don't ignore list anything in DEV build for debugging purposes
146
+ return false;
147
+ }
148
+
149
+ const contentScriptNamesToIgnoreList = [
150
+ // This is where we override console
151
+ 'installHook',
152
+ ];
153
+
154
+ return contentScriptNamesToIgnoreList.some(ignoreListName =>
155
+ assetName.startsWith(ignoreListName),
156
+ );
157
+ },
158
+ }),
159
],
160
module: {
161
defaultRules: [
packages/react-devtools-shared/SourceMapIgnoreListPlugin.js
new
+73
@@ -0,0 +1,73 @@
1
+/**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+/**
9
+ * The implementation of this plugin is based on similar webpack plugin in Angular CLI
10
+ * https://github.com/angular/angular-cli/blob/16d8c552e99bfe65ded9e843e917dbb95eb8ec01/packages/angular_devkit/build_angular/src/tools/webpack/plugins/devtools-ignore-plugin.ts
11
+ * and devtools-ignore-webpack-plugin
12
+ * https://github.com/mondaychen/devtools-ignore-webpack-plugin/blob/d15274e4d2fdb74f73aa644f14773a5523823999/src/index.ts
13
+ * which both are licensed under MIT
14
+ */
15
+
16
+const {Compilation} = require('webpack');
17
+
18
+const IGNORE_LIST = 'ignoreList';
19
+const PLUGIN_NAME = 'source-map-ignore-list-plugin';
20
+
21
+class SourceMapIgnoreListPlugin {
22
+ constructor({shouldIgnoreSource}) {
23
+ this.shouldIgnoreSource = shouldIgnoreSource;
24
+ }
25
+
26
+ apply(compiler) {
27
+ const {RawSource} = compiler.webpack.sources;
28
+
29
+ compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
30
+ compilation.hooks.processAssets.tap(
31
+ {
32
+ name: PLUGIN_NAME,
33
+ stage: Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING,
34
+ additionalAssets: true,
35
+ },
36
+ assets => {
37
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
38
+ for (const [name, asset] of Object.entries(assets)) {
39
+ if (!name.endsWith('.map')) {
40
+ continue;
41
+ }
42
+
43
+ const mapContent = asset.source().toString();
44
+ if (!mapContent) {
45
+ continue;
46
+ }
47
+
48
+ const map = JSON.parse(mapContent);
49
+ const ignoreList = [];
50
+
51
+ const sourcesCount = map.sources.length;
52
+ for (
53
+ let potentialSourceIndex = 0;
54
+ potentialSourceIndex < sourcesCount;
55
+ ++potentialSourceIndex
56
+ ) {
57
+ const source = map.sources[potentialSourceIndex];
58
+
59
+ if (this.shouldIgnoreSource(name, source)) {
60
+ ignoreList.push(potentialSourceIndex);
61
+ }
62
+ }
63
+
64
+ map[IGNORE_LIST] = ignoreList;
65
+ compilation.updateAsset(name, new RawSource(JSON.stringify(map)));
66
+ }
67
+ },
68
+ );
69
+ });
70
+ }
71
+}
72
+
73
+module.exports = SourceMapIgnoreListPlugin;
yarn.lock
-5
@@ -6417,11 +6417,6 @@ detect-node@^2.0.4:
6417
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
6418
integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
6419
6420
-devtools-ignore-webpack-plugin@^0.1.1:
6421
- version "0.1.1"
6422
- resolved "https://registry.yarnpkg.com/devtools-ignore-webpack-plugin/-/devtools-ignore-webpack-plugin-0.1.1.tgz#8f4fcf83019bc361e8a3cf7b7d466a33693de14e"
6423
- integrity sha512-pJ/NGZTQxK1VDoyy8fLm0UV3ugOanostztLKUmzqYnUIKqyUm2ZkIpon6No0gWlpOSMoSpBWTnzrx1cdsbpuyw==
6424
-
6420
diff-sequences@^27.0.6:
6421
version "27.0.6"
6422
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.0.6.tgz#3305cb2e55a033924054695cc66019fd7f8e5723"