Removes `--extract-errors` argument from CI build script command.
Instead, the author is expected to run `yarn extract-errors` locally
or manually edit the error code map.
The lint rule should be sufficient to catch unminified errors, but
as an extra precaution, I added a post-build step that greps the
production bundles. The post-build step works even if someone disables
the lint rule for a specific line or file.
* 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
If React finishes rendering a tree, delays committing it (e.g.
Suspense), then subsequently starts over or renders a new tree, the
pending tree is no longer valid. That's because rendering a new work-in
progress mutates the old one in place.
The current structure of the work loop makes this hard to reason about
because, although `renderRoot` and `commitRoot` are separate functions,
they can't be interleaved. If they are interleaved by accident, it
either results in inconsistent render output or invariant violations
that are hard to debug.
This commit adds an invariant that throws if the new tree is the same as
the old one. This won't prevent all bugs of this class, but it should
catch the most common kind.
To implement the invariant, I store the finished tree on a field on the
root. We already had a field for this, but it was only being used for
the unstable `createBatch` feature.
A more rigorous way to address this type of problem could be to unify
`renderRoot` and `commitRoot` into a single function, so that it's
harder to accidentally interleave the two phases. I plan to do something
like this in a follow-up.
The React Native build does not minify error messages in production,
but it still needs to run the error messages transform to compile
`invariant` calls to `ReactError`. To do this, I added a `noMinify`
option to the Babel plugin. I also renamed it from
`minify-error-messages` to the more generic `transform-error-messages`.
* Transform invariant to custom error type
This transforms calls to the invariant module:
```js
invariant(condition, 'A %s message that contains %s', adj, noun);
```
Into throw statements:
```js
if (!condition) {
if (__DEV__) {
throw ReactError(`A ${adj} message that contains ${noun}`);
} else {
throw ReactErrorProd(ERR_CODE, adj, noun);
}
}
```
The only thing ReactError does is return an error whose name is set
to "Invariant Violation" to match the existing behavior.
ReactErrorProd is a special version used in production that throws
a minified error code, with a link to see to expanded form. This
replaces the reactProdInvariant module.
As a next step, I would like to replace our use of the invariant module
for user facing errors by transforming normal Error constructors to
ReactError and ReactErrorProd. (We can continue using invariant for
internal React errors that are meant to be unreachable, which was the
original purpose of invariant.)
* Use numbers instead of strings for error codes
* Use arguments instead of an array
I wasn't sure about this part so I asked Sebastian, and his rationale
was that using arguments will make ReactErrorProd slightly slower, but
using an array will likely make all the functions that throw slightly
slower to compile, so it's hard to say which way is better. But since
ReactErrorProd is in an error path, and fewer bytes is generally better,
no array is good.
* Casing nit
* Swap expect(ReactNoop) for expect(Scheduler)
In the previous commits, I upgraded our custom Jest matchers for the
noop and test renderers to use Scheduler under the hood.
Now that all these matchers are using Scheduler, we can drop
support for passing ReactNoop and test roots and always pass
Scheduler directly.
* Externalize Scheduler in noop and test bundles
I also noticed we don't need to regenerator runtime in noop anymore.
* use different eslint config for es6 and es5
* remove confusing eslint/baseConfig.js & add more eslint setting for es5, es6
* more clear way to run eslint on es5 & es6 file
* seperate ESNext, ES6, ES6 path, and use different lint config
* rename eslint config file & update eslint rules
* Undo yarn.lock changes
* Rename a file
* Remove unnecessary exceptions
* Refactor a little bit
* Refactor and tweak the logic
* Minor issues
* Update transforms to handle ES modules
* Update Jest to handle ES modules
* Convert react package to ES modules
* Convert react-art package to ES Modules
* Convert react-call-return package to ES Modules
* Convert react-test-renderer package to ES Modules
* Convert react-cs-renderer package to ES Modules
* Convert react-rt-renderer package to ES Modules
* Convert react-noop-renderer package to ES Modules
* Convert react-dom/server to ES modules
* Convert react-dom/{client,events,test-utils} to ES modules
* Convert react-dom/shared to ES modules
* Convert react-native-renderer to ES modules
* Convert react-reconciler to ES modules
* Convert events to ES modules
* Convert shared to ES modules
* Remove CommonJS support from transforms
* Move ReactDOMFB entry point code into react-dom/src
This is clearer because we can use ES imports in it.
* Fix Rollup shim configuration to work with ESM
* Fix incorrect comment
* Exclude external imports without side effects
* Fix ReactDOM FB build
* Remove TODOs I don’t intend to fix yet
* Added an automated test that would have caught the recent error code transform bug
* Renamed dev-expression-with-codes test to replace-invariant-error-codes
* Formatting nit
* Use relative paths in packages/react
* Use relative paths in packages/react-art
* Use relative paths in packages/react-cs
* Use relative paths in other packages
* Fix as many issues as I can
This uncovered an interesting problem where ./b from package/src/a would resolve to a different instantiation of package/src/b in Jest.
Either this is a showstopper or we can solve it by completely fobbidding remaining /src/.
* Fix all tests
It seems we can't use relative requires in tests anymore. Otherwise Jest becomes confused between real file and symlink.
https://github.com/facebook/jest/issues/3830
This seems bad... Except that we already *don't* want people to create tests that import individual source files.
All existing cases of us doing so are actually TODOs waiting to be fixed.
So perhaps this requirement isn't too bad because it makes bad code looks bad.
Of course, if we go with this, we'll have to lint against relative requires in tests.
It also makes moving things more painful.
* Prettier
* Remove @providesModule
* Fix remaining Haste imports I missed earlier
* Fix up paths to reflect new flat structure
* Fix Flow
* Fix CJS and UMD builds
* Fix FB bundles
* Fix RN bundles
* Prettier
* Fix lint
* Fix warning printing and error codes
* Fix buggy return
* Fix lint and Flow
* Use Yarn on CI
* Unbreak Jest
* Fix lint
* Fix aliased originals getting included in DEV
Shouldn't affect correctness (they were ignored) but fixes DEV size regression.
* Record sizes
* Fix weird version in package.json
* Tweak bundle labels
* Get rid of output option by introducing react-dom/server.node
* Reconciler should depend on prop-types
* Update sizes last time
* Update build size
* [CS] Clone container instead of new root concept
The extra "root" concept is kind of unnecessary. Instead of having a
mutable container even in the persistent mode, I'll instead make the
container be immutable too and be cloned. Then the "commit" just becomes
swapping the previous container for the new one.
* Change the signature or persistence again
We may need to clone without any updates, e.g. when the children are changed.
Passing in the previous node is not enough to recycle since it won't have the
up-to-date props and children. It's really only useful to for allocation pooling.
* Implement persistent updates
This forks the update path for host fibers. For mutation mode we mark
them as having an effect. For persistence mode, we clone the stateNode with
new props/children.
Next I'll do HostRoot and HostPortal.
* Refine protocol into a complete and commit phase
finalizeContainerChildren will get called at the complete phase.
replaceContainer will get called at commit.
Also, drop the keepChildren flag. We'll never keep children as we'll never
update a container if none of the children has changed.
* Implement persistent updates of roots and portals
These are both "containers". Normally we rely on placement/deletion effects
to deal with insertions into the containers. In the persistent mode we need
to clone the container and append all the changed children to it.
I needed somewhere to store these new containers before they're committed
so I added another field.
* Commit persistent work at the end by swapping out the container
* Unify cloneOrRecycle
Originally I tried to make the recyclable instance nullable but Flow didn't
like that and it's kind of sketchy since the instance type might not be
nullable.
However, the real difference which one we call is depending on whether they
are equal. We can just offload that to the renderer. Most of them won't
need to know about this at all since they'll always clone or just create
new.
The ones that do know now have to be careful to compare them so they don't
reuse an existing instance but that's probably fine to simplify the
implementation and API.
* Add persistent noop renderer for testing
* Add basic persistent tree test
* Test bail out
This adds a test for bailouts. This revealed a subtle bug. We don't set the
return pointer when stepping into newly created fibers because there
can only be one. However, since I'm reusing this mechanism for persistent
updates, I'll need to set the return pointer because a bailed out tree
won't have the right return pointer.
* Test persistent text nodes
Found another bug.
* Add persistent portal test
This creates a bit of an unfortunate feature testing in the unmount
branch.
That's because we want to trigger nested host deletions in portals in the
mutation mode.
* Don't consider container when determining portal identity
Basically, we can't use the container to determine if we should keep
identity and update an existing portal instead of recreate it. Because
for persistent containers, there is no permanent identity.
This makes it kind of strange to even use portals in this mode. It's
probably more ideal to have another concept that has permanent identity
rather than trying to swap out containers.
* Clear portals when the portal is deleted
When a portal gets deleted we need to create a new empty container and
replace the current one with the empty one.
* Add renderer mode flags for dead code elimination
* Simplify ReactNoop fix
* Add new type to the host config for persistent configs
We need container to stay as the persistent identity of the root atom.
So that we can refer to portals over time.
Instead, I'll introduce a new type just to temporarily hold the children
of a container until they're ready to be committed into the permanent
container. Essentially, this is just a fancy array that is not an array
so that the host can choose data structure/allocation for it.
* Implement new hooks
Now containers are singletons and instead their children swap. That way
portals can use the container as part of their identity again.
* Update build size and error codes
* Address comment
* Move new files to new location
Did find and replace in TextMate.
```
find: (?:( \*)( ))?Copyright (?:\(c\) )?(\d{4})\b.+Facebook[\s\S]+(?:this source tree|the same directory)\.$
replace: $1$2Copyright (c) $3-present, Facebook, Inc.\n$1\n$1$2This source code is licensed under the MIT license found in the\n$1$2LICENSE file in the root directory of this source tree.
```
FB bundles wrap warning() calls in __DEV__
Split dev-mode transforms into separate parts:
1) umd+cjs+fb: Wrap warning calls with process.env checks
2) umd+cjs: Replace error messages with minified codes
Also updated transforms to use __DEV__ since it transforms to smaller code after stripEnvVariables is run.
Also renamed 'scripts/error-codes/dev-expression-with-codes.js' -> 'scripts/error-codes/replace-invariant-error-codes.js'