Skip to content

Commit 112168f

Browse files
authored
Lint rule for unminified errors (#15757)
* Lint rule for unminified errors Add a lint rule that fails if an invariant message is not part of the error code map. The goal is to be more disciplined about adding and modifiying production error codes. Error codes should be consistent across releases even if their wording changes, for continuity in logs. Currently, error codes are added to the error code map via an automated script that runs right before release. The problem with this approach is that if someone modifies an error message in the source, but neglects to modify the corresponding message in the error code map, then the message will be assigned a new error code, instead of reusing the existing one. Because the error extraction script only runs before a release, people rarely modify the error code map in practice. By moving the extraction step to the PR stage, it forces the author to consider whether the message should be assigned a new error code. It also allows the reviewer to review the changes. The trade off is that it requires more effort and context to land new error messages, or to modify existing ones, particular for new contributors who are not familiar with our processes. Since we already expect users to lint their code, I would argue the additional burden is marginal. Even if they forget to run the lint command locally, they will get quick feedback from the CI lint job, which typically finishes within 2-3 minutes. * Add unreleased error messages to map
1 parent 142cf56 commit 112168f

File tree

12 files changed

+72
-7
lines changed

12 files changed

+72
-7
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
"linc": "node ./scripts/tasks/linc.js",
9898
"lint": "node ./scripts/tasks/eslint.js",
9999
"lint-build": "node ./scripts/rollup/validate/index.js",
100+
"extract-errors": "yarn build --type=dev --extract-errors",
100101
"postinstall": "node node_modules/fbjs-scripts/node/check-dev-engines.js package.json && node ./scripts/flow/createFlowConfigs.js",
101102
"debug-test": "cross-env NODE_ENV=development node --inspect-brk node_modules/.bin/jest --config ./scripts/jest/config.source.js --runInBand",
102103
"test": "cross-env NODE_ENV=development jest --config ./scripts/jest/config.source.js",

packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/InitializeNativeFabricUIManager.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8+
/* eslint-disable react-internal/warning-and-invariant-args */
9+
810
'use strict';
911

1012
// Mock of the Native Hooks

packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/ReactNativeViewConfigRegistry.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
* @flow strict-local
88
*/
99

10+
/* eslint-disable react-internal/warning-and-invariant-args */
11+
1012
'use strict';
1113

1214
import type {

packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/UIManager.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8+
/* eslint-disable react-internal/warning-and-invariant-args */
9+
810
'use strict';
911

1012
// Mock of the Native Hooks

packages/react-reconciler/src/ReactFiberHostConfig.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
* @flow
88
*/
99

10+
/* eslint-disable react-internal/warning-and-invariant-args */
11+
1012
import invariant from 'shared/invariant';
1113

1214
// We expect that our Rollup, Jest, and Flow configurations

packages/react-stream/src/ReactFizzFormatConfig.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
* @flow
88
*/
99

10+
/* eslint-disable react-internal/warning-and-invariant-args */
11+
1012
import invariant from 'shared/invariant';
1113

1214
// We expect that our Rollup, Jest, and Flow configurations

packages/react-stream/src/ReactFizzHostConfig.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
* @flow
88
*/
99

10+
/* eslint-disable react-internal/warning-and-invariant-args */
11+
1012
import invariant from 'shared/invariant';
1113

1214
// We expect that our Rollup, Jest, and Flow configurations

scripts/error-codes/README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ provide a better debugging support in production. Check out the blog post
99
the file will never be changed/removed.
1010
- [`extract-errors.js`](https://github.com/facebook/react/blob/master/scripts/error-codes/extract-errors.js)
1111
is an node script that traverses our codebase and updates `codes.json`. You
12-
can test it by running `yarn build -- --extract-errors`, but you should only
13-
commit changes to this file when running a release. (The release tool will
14-
perform this step automatically.)
12+
can test it by running `yarn extract-errors`.
1513
- [`transform-error-messages`](https://github.com/facebook/react/blob/master/scripts/error-codes/transform-error-messages)
1614
is a Babel pass that rewrites error messages to IDs for a production
1715
(minified) build.

scripts/error-codes/codes.json

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,6 @@
222222
"220": "Container does not support insertBefore operation",
223223
"221": "Tried to register two views with the same name %s",
224224
"222": "View config not found for name %s",
225-
"223": "Trying to release an event instance into a pool of a different type.",
226225
"224": "Can't read from currently-mounting component. This error is likely caused by a bug in React. Please file an issue.",
227226
"225": "Unexpected object passed to ReactTestInstance constructor (tag: %s). This is probably a bug in React.",
228227
"226": "Unsupported component type %s in test renderer. This is probably a bug in React.",
@@ -321,5 +320,18 @@
321320
"319": "A dehydrated suspense boundary must commit before trying to render. This is probably a bug in React.",
322321
"320": "Expected ReactFiberErrorDialog.showErrorDialog to be a function.",
323322
"321": "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.",
324-
"322": "forwardRef requires a render function but was given %s."
323+
"322": "forwardRef requires a render function but was given %s.",
324+
"323": "React has blocked a javascript: URL as a security precaution.%s",
325+
"324": "An event responder context was used outside of an event cycle. Use context.setTimeout() to use asynchronous responder context outside of event cycle .",
326+
"325": "addRootEventTypes() found a duplicate root event type of \"%s\". This might be because the event type exists in the event responder \"rootEventTypes\" array or because of a previous addRootEventTypes() using this root event type.",
327+
"326": "Expected a valid priority level",
328+
"327": "Should not already be working.",
329+
"328": "Should have a work-in-progress.",
330+
"329": "Unknown root exit status.",
331+
"330": "Should be working on an effect.",
332+
"331": "Cannot flush passive effects while already rendering.",
333+
"332": "Unknown priority level.",
334+
"333": "This should have a parent host component initialized. This error is likely caused by a bug in React. Please file an issue.",
335+
"334": "accumulate(...): Accumulated items must not be null or undefined.",
336+
"335": "ReactDOMServer does not yet support the event API."
325337
}

scripts/eslint-rules/__tests__/warning-and-invariant-args-test.internal.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ ruleTester.run('eslint-rules/warning-and-invariant-args', rule, {
1717
valid: [
1818
"warning(true, 'hello, world');",
1919
"warning(true, 'expected %s, got %s', 42, 24);",
20-
"invariant(true, 'hello, world');",
21-
"invariant(true, 'expected %s, got %s', 42, 24);",
20+
'arbitraryFunction(a, b)',
21+
// These messages are in the error code map
22+
"invariant(false, 'Do not override existing functions.')",
23+
"invariant(false, '%s(...): Target container is not a DOM element.', str)",
2224
],
2325
invalid: [
2426
{
@@ -96,5 +98,18 @@ ruleTester.run('eslint-rules/warning-and-invariant-args', rule, {
9698
},
9799
],
98100
},
101+
{
102+
code: "invariant(false, 'Not in error map')",
103+
errors: [
104+
{
105+
message:
106+
'Error message does not have a corresponding production error code.\n\n' +
107+
'Run `yarn extract-errors` to add the message to error code map, ' +
108+
'so it can be stripped from the production builds. ' +
109+
"Alternatively, if you're updating an existing error message, " +
110+
'you can modify `scripts/error-codes/codes.json` directly.',
111+
},
112+
],
113+
},
99114
],
100115
});

0 commit comments

Comments
 (0)