Skip to content

Extract errors from Error() and new Error() instead of invariant() #22514

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion scripts/error-codes/codes.json
Original file line number Diff line number Diff line change
Expand Up @@ -401,5 +401,25 @@
"413": "Expected finished root and lanes to be set. This is a bug in React.",
"414": "Did not expect this call in production. This is a bug in React. Please file an issue.",
"415": "Error parsing the data. It's probably an error code or network corruption.",
"416": "This environment don't support binary chunks."
"416": "This environment don't support binary chunks.",
"417": "%s: %s type `%s` is invalid; it must be a function, usually from the `prop-types` package, but received `%s`.This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`.",
"418": "Expected resolveFamily to be set during hot reload.",
"419": "Did not expect findHostInstancesForRefresh to be called in production.",
"420": "Expected to reach root first.",
"421": "Simulated error coming from DevTools",
"422": "Cannot swap the root fiber.",
"423": "Expected parent to have a child.",
"424": "Expected to find the previous sibling.",
"425": "Error message",
"426": "An error was thrown inside one of your components, but React doesn't know what it was. This is likely due to browser flakiness. React does its best to preserve the \"Pause on exceptions\" behavior of the DevTools, which requires some DEV-mode only tricks. It's possible that these don't work in your browser. Try triggering the error in production mode, or switching to a modern browser. If you suspect that this is actually an issue with React, please file an issue.",
"427": "A cross-origin error was thrown. React doesn't have access to the actual error object in development. See https://reactjs.org/link/crossorigin-error for more information.",
"428": "%s",
"429": "Should never be called",
"430": "failed to set property",
"431": "\"%s\" is read-only",
"432": "Class \"%s\" cannot be referenced in computed property keys.",
"433": "Decorating class property failed. Please ensure that proposal-class-properties is enabled and runs after the decorators transform.",
"434": "You must require a mode before requiring anything else.",
"435": "Dynamic requires are not currently supported by rollup-plugin-commonjs",
"436": "Bad input"
}
37 changes: 23 additions & 14 deletions scripts/error-codes/extract-errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const parser = require('@babel/parser');
const fs = require('fs');
const path = require('path');
const traverse = require('@babel/traverse').default;
const {evalStringConcat} = require('../shared/evalToString');
const {evalStringAndTemplateConcat} = require('../shared/evalToString');
const invertObject = require('./invertObject');

const babylonOptions = {
Expand Down Expand Up @@ -67,29 +67,38 @@ module.exports = function(opts) {
function transform(source) {
const ast = parser.parse(source, babylonOptions);

function ErrorCallExpression(node) {
const errorMessageNode = node.arguments[0];
if (errorMessageNode === undefined) {
return;
}
const errorMsgLiteral = evalStringAndTemplateConcat(errorMessageNode, []);
if (existingErrorMap.hasOwnProperty(errorMsgLiteral)) {
return;
}
existingErrorMap[errorMsgLiteral] = '' + currentID++;
}

traverse(ast, {
CallExpression: {
exit(astPath) {
if (astPath.get('callee').isIdentifier({name: 'invariant'})) {
if (astPath.get('callee').isIdentifier({name: 'Error'})) {
const node = astPath.node;

// error messages can be concatenated (`+`) at runtime, so here's a
// trivial partial evaluator that interprets the literal value
const errorMsgLiteral = evalStringConcat(node.arguments[1]);
addToErrorMap(errorMsgLiteral);
ErrorCallExpression(node);
}
},
},
NewExpression: {
exit(astPath) {
if (astPath.get('callee').isIdentifier({name: 'Error'})) {
const node = astPath.node;
ErrorCallExpression(node);
}
},
},
});
}

function addToErrorMap(errorMsgLiteral) {
if (existingErrorMap.hasOwnProperty(errorMsgLiteral)) {
return;
}
existingErrorMap[errorMsgLiteral] = '' + currentID++;
}

function flush(cb) {
fs.writeFileSync(
errorMapFilePath,
Expand Down
11 changes: 6 additions & 5 deletions scripts/rollup/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,12 +361,13 @@ function getPlugins(
const shouldStayReadable = isFBWWWBundle || isRNBundle || forcePrettyOutput;
return [
// Extract error codes from invariant() messages into a file.
shouldExtractErrors && {
transform(source) {
findAndRecordErrorCodes(source);
return source;
shouldExtractErrors &&
bundle.minifyWithProdErrorCodes !== false && {
transform(source) {
findAndRecordErrorCodes(source);
return source;
},
},
},
// Shim any modules that need forking in this environment.
useForks(forks),
// Ensure we don't try to bundle any fbjs modules.
Expand Down
12 changes: 6 additions & 6 deletions scripts/rollup/bundles.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ const bundles = [
moduleType: ISOMORPHIC,
entry: 'react-fetch/index.browser',
global: 'ReactFetch',
minifyWithProdErrorCodes: true,
minifyWithProdErrorCodes: false,
externals: ['react'],
},

Expand All @@ -157,7 +157,7 @@ const bundles = [
moduleType: ISOMORPHIC,
entry: 'react-fs/index.browser.server',
global: 'ReactFilesystem',
minifyWithProdErrorCodes: true,
minifyWithProdErrorCodes: false,
externals: [],
},

Expand All @@ -177,7 +177,7 @@ const bundles = [
moduleType: ISOMORPHIC,
entry: 'react-pg/index.browser.server',
global: 'ReactPostgres',
minifyWithProdErrorCodes: true,
minifyWithProdErrorCodes: false,
externals: [],
},

Expand Down Expand Up @@ -558,7 +558,7 @@ const bundles = [
moduleType: RENDERER,
entry: 'react-noop-renderer',
global: 'ReactNoopRenderer',
minifyWithProdErrorCodes: true,
minifyWithProdErrorCodes: false,
externals: ['react', 'scheduler', 'scheduler/unstable_mock', 'expect'],
},

Expand All @@ -568,7 +568,7 @@ const bundles = [
moduleType: RENDERER,
entry: 'react-noop-renderer/persistent',
global: 'ReactNoopRendererPersistent',
minifyWithProdErrorCodes: true,
minifyWithProdErrorCodes: false,
externals: ['react', 'scheduler', 'expect'],
},

Expand All @@ -578,7 +578,7 @@ const bundles = [
moduleType: RENDERER,
entry: 'react-noop-renderer/server',
global: 'ReactNoopRendererServer',
minifyWithProdErrorCodes: true,
minifyWithProdErrorCodes: false,
externals: ['react', 'scheduler', 'expect'],
},

Expand Down