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.
This commit is contained in:
Ruslan Lesiutin
2024-04-08 18:10:09 +01:00
committed by GitHub
parent 4c12339ce3
commit 6de7733e73
6 changed files with 111 additions and 33 deletions

View File

@@ -39,7 +39,6 @@
"chrome-launch": "^1.1.4",
"crx": "^5.0.0",
"css-loader": "^1.0.1",
"devtools-ignore-webpack-plugin": "^0.1.1",
"file-loader": "^6.1.0",
"filesize": "^6.0.1",
"find": "^0.3.0",

View File

@@ -12,7 +12,7 @@ import {readFileSync} from 'fs';
import path from 'path';
import {rimrafSync} from 'rimraf';
describe('x_google_ignoreList source map extension', () => {
describe('ignoreList source map extension', () => {
jest.setTimeout(60 * 1000);
const pathToExtensionsPackage = path.resolve(__dirname, '..', '..');
@@ -30,7 +30,7 @@ describe('x_google_ignoreList source map extension', () => {
});
describe('for dev builds', () => {
it('should include only sources with /node_modules/ and /webpack/ in path', async () => {
it('should not ignore list anything', async () => {
await exec('yarn build:chrome:local', {
cwd: pathToExtensionsPackage,
});
@@ -38,18 +38,8 @@ describe('x_google_ignoreList source map extension', () => {
const sourceMapJSON = readFileSync(pathToSourceMap);
const sourceMap = JSON.parse(sourceMapJSON);
const {sources, x_google_ignoreList} = sourceMap;
const expectedIgnoreList = [];
for (let sourceIndex = 0; sourceIndex < sources.length; ++sourceIndex) {
const source = sources[sourceIndex];
if (source.includes('/node_modules/') || source.includes('/webpack/')) {
expectedIgnoreList.push(sourceIndex);
}
}
expect(x_google_ignoreList).toEqual(expectedIgnoreList);
const {ignoreList} = sourceMap;
expect(ignoreList).toEqual([]);
});
});
@@ -60,9 +50,9 @@ describe('x_google_ignoreList source map extension', () => {
const sourceMapJSON = readFileSync(pathToSourceMap);
const sourceMap = JSON.parse(sourceMapJSON);
const {sources, x_google_ignoreList} = sourceMap;
const {sources, ignoreList} = sourceMap;
expect(sources.length).toBe(x_google_ignoreList.length);
expect(sources.length).toBe(ignoreList.length);
});
});
});

View File

@@ -2,9 +2,10 @@
const {resolve} = require('path');
const Webpack = require('webpack');
const DevToolsIgnorePlugin = require('devtools-ignore-webpack-plugin');
const {resolveFeatureFlags} = require('react-devtools-shared/buildUtils');
const SourceMapIgnoreListPlugin = require('react-devtools-shared/SourceMapIgnoreListPlugin');
const {
DARK_MODE_DIMMED_WARNING_COLOR,
DARK_MODE_DIMMED_ERROR_COLOR,
@@ -42,7 +43,7 @@ const featureFlagTarget = process.env.FEATURE_FLAG_TARGET || 'extension-oss';
module.exports = {
mode: __DEV__ ? 'development' : 'production',
devtool: __DEV__ ? 'cheap-module-source-map' : 'nosources-cheap-source-map',
devtool: false,
entry: {
backend: './src/backend.js',
},
@@ -87,14 +88,12 @@ module.exports = {
'process.env.IS_FIREFOX': IS_FIREFOX,
'process.env.IS_EDGE': IS_EDGE,
}),
new DevToolsIgnorePlugin({
shouldIgnorePath: function (path) {
if (!__DEV__) {
return true;
}
return path.includes('/node_modules/') || path.includes('/webpack/');
},
new Webpack.SourceMapDevToolPlugin({
filename: '[file].map',
noSources: !__DEV__,
}),
new SourceMapIgnoreListPlugin({
shouldIgnoreSource: () => !__DEV__,
}),
],
module: {

View File

@@ -14,6 +14,7 @@ const {
getVersionString,
} = require('./utils');
const {resolveFeatureFlags} = require('react-devtools-shared/buildUtils');
const SourceMapIgnoreListPlugin = require('react-devtools-shared/SourceMapIgnoreListPlugin');
const NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV) {
@@ -54,7 +55,7 @@ const babelOptions = {
module.exports = {
mode: __DEV__ ? 'development' : 'production',
devtool: __DEV__ ? 'cheap-module-source-map' : false,
devtool: false,
entry: {
background: './src/background/index.js',
backendManager: './src/contentScripts/backendManager.js',
@@ -134,6 +135,27 @@ module.exports = {
'process.env.LIGHT_MODE_DIMMED_ERROR_COLOR': `"${LIGHT_MODE_DIMMED_ERROR_COLOR}"`,
'process.env.LIGHT_MODE_DIMMED_LOG_COLOR': `"${LIGHT_MODE_DIMMED_LOG_COLOR}"`,
}),
new Webpack.SourceMapDevToolPlugin({
filename: '[file].map',
noSources: !__DEV__,
}),
new SourceMapIgnoreListPlugin({
shouldIgnoreSource: (assetName, _source) => {
if (__DEV__) {
// Don't ignore list anything in DEV build for debugging purposes
return false;
}
const contentScriptNamesToIgnoreList = [
// This is where we override console
'installHook',
];
return contentScriptNamesToIgnoreList.some(ignoreListName =>
assetName.startsWith(ignoreListName),
);
},
}),
],
module: {
defaultRules: [

View File

@@ -0,0 +1,73 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* The implementation of this plugin is based on similar webpack plugin in Angular CLI
* https://github.com/angular/angular-cli/blob/16d8c552e99bfe65ded9e843e917dbb95eb8ec01/packages/angular_devkit/build_angular/src/tools/webpack/plugins/devtools-ignore-plugin.ts
* and devtools-ignore-webpack-plugin
* https://github.com/mondaychen/devtools-ignore-webpack-plugin/blob/d15274e4d2fdb74f73aa644f14773a5523823999/src/index.ts
* which both are licensed under MIT
*/
const {Compilation} = require('webpack');
const IGNORE_LIST = 'ignoreList';
const PLUGIN_NAME = 'source-map-ignore-list-plugin';
class SourceMapIgnoreListPlugin {
constructor({shouldIgnoreSource}) {
this.shouldIgnoreSource = shouldIgnoreSource;
}
apply(compiler) {
const {RawSource} = compiler.webpack.sources;
compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
compilation.hooks.processAssets.tap(
{
name: PLUGIN_NAME,
stage: Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING,
additionalAssets: true,
},
assets => {
// eslint-disable-next-line no-for-of-loops/no-for-of-loops
for (const [name, asset] of Object.entries(assets)) {
if (!name.endsWith('.map')) {
continue;
}
const mapContent = asset.source().toString();
if (!mapContent) {
continue;
}
const map = JSON.parse(mapContent);
const ignoreList = [];
const sourcesCount = map.sources.length;
for (
let potentialSourceIndex = 0;
potentialSourceIndex < sourcesCount;
++potentialSourceIndex
) {
const source = map.sources[potentialSourceIndex];
if (this.shouldIgnoreSource(name, source)) {
ignoreList.push(potentialSourceIndex);
}
}
map[IGNORE_LIST] = ignoreList;
compilation.updateAsset(name, new RawSource(JSON.stringify(map)));
}
},
);
});
}
}
module.exports = SourceMapIgnoreListPlugin;

View File

@@ -6417,11 +6417,6 @@ detect-node@^2.0.4:
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
devtools-ignore-webpack-plugin@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/devtools-ignore-webpack-plugin/-/devtools-ignore-webpack-plugin-0.1.1.tgz#8f4fcf83019bc361e8a3cf7b7d466a33693de14e"
integrity sha512-pJ/NGZTQxK1VDoyy8fLm0UV3ugOanostztLKUmzqYnUIKqyUm2ZkIpon6No0gWlpOSMoSpBWTnzrx1cdsbpuyw==
diff-sequences@^27.0.6:
version "27.0.6"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.0.6.tgz#3305cb2e55a033924054695cc66019fd7f8e5723"