@samitouri / QOS-React / commits / 6de7733e73

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"