Meta uses various tools built on top of the "react-reconciler" package
but that package needs to match the version of the "react" package.
This means that it should be synced at the same time. However, more than
that the feature flags between the "react" package and the
"react-reconciler" package needs to line up. Since FB has custom feature
flags, it can't use the OSS version of react-reconciler.
In #26446 we started publishing non-minified versions of our production
build artifacts, along with source maps, for easier debugging of React
when running in production mode.
The way it's currently set up is that these builds are generated
*before* Closure compiler has run. Which means it's missing many of the
optimizations that are in the final build, like dead code elimination.
This PR changes the build process to run Closure on the non-minified
production builds, too, by moving the sourcemap generation to later in
the pipeline.
The non-minified builds will still preserve the original symbol names,
and we'll use Prettier to add back whitespace. This is the exact same
approach we've been using for years to generate production builds for
Meta.
The idea is that the only difference between the minified and non-
minified builds is whitespace and symbol mangling. The semantic
structure of the program should be identical.
To implement this, I disabled symbol mangling when running Closure
compiler. Then, in a later step, the symbols are mangled by Terser. This
is when the source maps are generated.
Stacked on #28872
renderToStaticNodeStream was not originally deprecated when
renderToNodeStream was deprecated because it did not yet have a clear
analog in the modern streaming implementation for SSR. In React 19 we
have already removed renderToNodeStream. This change removes
renderToStaticNodeStream as well because you can replicate it's
semantics using renderToPipeableStream with onAllReady or
renderToReadableStream with await stream.allready.
This commit adds warnings indicating that `renderToStaticNodeStream`
will be removed in an upcoming React release. This API has been legacy,
is not widely used (renderToStaticMarkup is more common) and has
semantically eqiuvalent implementations with renderToReadableStream and
renderToPipeableStream.
stacked on #28870
inline script children have been encoded as HTML for a while now but
this can easily break script parsing so practically if you were
rendering inline scripts you were using dangerouslySetInnerHTML. This is
not great because now there is no escaping at all so you have to be even
more careful. While care should always be taken when rendering untrusted
script content driving users to use dangerous APIs is not the right
approach and in this PR the escaping functionality used for
bootstrapScripts and importMaps is being extended to any inline script.
the approach is to escape 's' or 'S" with the appropriate unicode code
point if it is inside a <script or </script sequence. This has the nice
benefit of minimally escaping the text for readability while still
preserving full js parsing capabilities. As articulated when we
introduced this escaping for prior use cases this is only safe because
we are escaping the entire script content. It would be unsafe if we were
not escaping the entirety of the script because we would no longer be
able to ensure there are no earlier or later <script sequences that put
the parser in unexpected states.
style text content has historically been escaped as HTML which is
non-sensical and often leads users to using dangerouslySetInnerHTML as a
matter of course. While rendering untrusted style rules is a security
risk React doesn't really provide any special protection here and
forcing users to use a completely unescaped API is if anything worse. So
this PR updates the style escaping rules for Fizz to only escape the
text content to ensure the tag scope cannot be closed early. This is
accomplished by encoding "s" and "S" as hexadecimal unicode
representation "\73 " and "\53 " respectively when found within a
sequence like </style>. We have to be careful to support casing here
just like with the script closing tag regex for bootstrap scripts.
## Summary
The Forget codename needs to be hidden from the UI to avoid confusion.
Going forward, we'll be referring to this set of features as part of the
larger React compiler. We'll be describing the primary feature that
we've built so far as auto-memoization, and this badge helps devs see
which components have been automatically memoized by the compiler.
## How did you test this change?
- force Forget badge on with and without the presence of other badges
- confirm colors/UI in light and dark modes
- force badges on for `ElementBadges`, `InspectableElementBadges`,
`IndexableElementBadges`
- Running yarn start in packages/react-devtools-shell
[demo
video](https://github.com/facebook/react/assets/973058/fa829018-7644-4425-8395-c5cd84691f3c)
For fbsource we've historically used a separate repo for imports due to
internal limitations in Diff Train. Those have been lifted so we can now
commit this branch here and then we can import from this repo (and get
rid of the other repo)
Previously, the `refs` property of a class component instance was
read-only by user code — only React could write to it, and until/unless
a string ref was used, it pointed to a shared empty object that was
frozen in dev to prevent userspace mutations.
Because string refs are deprecated, we want users to be able to codemod
all their string refs to callback refs. The safest way to do this is to
output a callback ref that assigns to `this.refs`.
So to support this, we need to make `this.refs` writable by userspace.
## Summary
This PR adds early return to the `diff` function. We don't need to go
through all the entries of `nextProps`, process and deep-diff the values
if `nextProps` is the same object as `prevProps`. Roughly 6% of all
`diffProperties` calls can be skipped.
## How did you test this change?
RNTester.
<!--
Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.
Before submitting a pull request, please make sure the following is
done:
1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
10. If you haven't already, complete the CLA.
Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->
## Summary
<!--
Explain the **motivation** for making this change. What existing problem
does the pull request solve?
-->
## How did you test this change?
<!--
Demonstrate the code is solid. Example: The exact commands you ran and
their output, screenshots / videos if the pull request changes the user
interface.
How exactly did you verify that your PR solves the issue you wanted to
solve?
If you leave this empty, your PR will very likely be closed.
-->
## Summary
This pull request converts the CircleCI workflows to GitHub actions
workflows. [Github Actions
Importer](https://github.com/github/gh-actions-importer) was used to
convert the workflows initially, then I edited them manually to correct
errors in translation.
**Issues**
1. facebook/react/devtools_regression_tests
The scripts that this workflow calls need to be modified.
## How did you test this change?
I tested these changes in a forked repo. You can [view the logs of this
workflow in my fork](https://github.com/robandpdx/react/actions).
https://fburl.com/workplace/f6mz6tmw
In React 19 React will finally stop publishing UMD builds. This is
motivated primarily by the lack of use of UMD format and the added
complexity of maintaining build infra for these releases. Additionally
with ESM becoming more prevalent in browsers and services like esm.sh
which can host React as an ESM module there are other options for doing
script tag based react loading.
This PR removes all the UMD build configs and forks.
There are some fixtures that still have references to UMD builds however
many of them already do not work (for instance they are using legacy
features like ReactDOM.render) and rather than block the removal on
these fixtures being brought up to date we'll just move forward and fix
or removes fixtures as necessary in the future.
Fixes issue where if the first letter of the expected string appeared
anywhere in actual message, the assertion would pass, leading to false
negatives. We should check the entire expected string.
---------
Co-authored-by: Ricky <rickhanlonii@gmail.com>
This wasn't clearly articulated and tested why the code structure is
like this but I think the logic is correct - or at least consistent with
the weird semantics.
We place this top-level fragment check inside the recursion so that you
can resolve how many every Lazy or Usable wrappers you want and it still
preserves the same semantics if they weren't there (which they might not
be as a matter of a race condition).
However, we don't actually recurse with the top-level fragment
unwrapping itself because nesting a bunch of keyless fragments isn't the
same as a single fragment/element.
So that when we end up referring to it in more places, it's only one.
We don't do this same pattern for regular `Symbol.iterator` because we
also support the string `"@@iterator"` for backwards compatibility.
This adds support in Flight for serializing four kinds of streams:
- `ReadableStream` with objects as a model. This is a single shot
iterator so you can read it only once. It can contain any value
including Server Components. Chunks are encoded as is so if you send in
10 typed arrays, you get the same typed arrays out on the other side.
- Binary `ReadableStream` with `type: 'bytes'` option. This supports the
BYOB protocol. In this mode, the receiving side just gets `Uint8Array`s
and they can be split across any single byte boundary into arbitrary
chunks.
- `AsyncIterable` where the `AsyncIterator` function is different than
the `AsyncIterable` itself. In this case we assume that this might be a
multi-shot iterable and so we buffer its value and you can iterate it
multiple times on the other side. We support the `return` value as a
value in the single completion slot, but you can't pass values in
`next()`. If you want single-shot, return the AsyncIterator instead.
- `AsyncIterator`. These gets serialized as a single-shot as it's just
an iterator.
`AsyncIterable`/`AsyncIterator` yield Promises that are instrumented
with our `.status`/`.value` convention so that they can be synchronously
looped over if available. They are also lazily parsed upon read.
We can't do this with `ReadableStream` because we use the native
implementation of `ReadableStream` which owns the promises.
The format is a leading row that indicates which type of stream it is.
Then a new row with the same ID is emitted for every chunk. Followed by
either an error or close row.
`AsyncIterable`s can also be returned as children of Server Components
and then they're conceptually the same as fragment arrays/iterables.
They can't actually be used as children in Fizz/Fiber but there's a
separate plan for that. Only `AsyncIterable` not `AsyncIterator` will be
valid as children - just like sync `Iterable` is already supported but
single-shot `Iterator` is not. Notably, neither of these streams
represent updates over time to a value. They represent multiple values
in a list.
When the server stream is aborted we also close the underlying stream.
However, closing a stream on the client, doesn't close the underlying
stream.
A couple of possible follow ups I'm not planning on doing right now:
- [ ] Free memory by releasing the buffer if an Iterator has been
exhausted. Single shots could be optimized further to release individual
items as you go.
- [ ] We could clean up the underlying stream if the only pending data
that's still flowing is from streams and all the streams have cleaned
up. It's not very reliable though. It's better to do cancellation for
the whole stream - e.g. at the framework level.
- [ ] Implement smarter Binary Stream chunk handling. Currently we wait
until we've received a whole row for binary chunks and copy them into
consecutive memory. We need this to preserve semantics when passing
typed arrays. However, for binary streams we don't need that. We can
just send whatever pieces we have so far.
Per team discussion, this upgrades the `initialValue` argument for
`useDeferredValue` from experimental to canary.
- Original implementation PR:
https://github.com/facebook/react/pull/27500
- API documentation PR: https://github.com/reactjs/react.dev/pull/6747
I left it disabled at Meta for now in case there's old code somewhere
that is still passing an `options` object as the second argument.
This allows the plugin to be configured to run on an allowlist, rather
than compiling all files helping with an incremental rollout plan.
The sources option takes both an array of path strings or a function
to be flexible.
For now I've left this be optional but we can make it required.
ghstack-source-id: 282a33dc8d08d47f699894692e0fcc813dff5b77
Pull Request resolved: https://github.com/facebook/react-forget/pull/2855
No need to commit this in the repo, but keeping this locally helps with
building the feedback repo.
ghstack-source-id: 28f08992b1ab856567a5338af07e12ac820a7298
Pull Request resolved: https://github.com/facebook/react-forget/pull/2854
With the enableBinaryFlight flag on we should encode typed arrays and
blobs in the Reply direction too for parity.
It's already possible to pass Blobs inside FormData but you should be
able to pass them inside objects too.
We encode typed arrays as blobs and then unwrap them automatically to
the right typed array type.
Unlike the other protocol, I encode the type as a reference tag instead
of row tag. Therefore I need to rename the tags to avoid conflicts with
other tags in references. We are running out of characters though.
This hasn't been updated in a long time, and it getting really large.
You can view the authors locally via the git history with:
``
git shortlog -se | perl -spe 's/^\s+\d+\s+//'
``
## Overview
There's currently a bug in RN now that we no longer re-throw errors. The
`showErrorDialog` function in React Native only logs the errors as soft
errors, and never a fatal. RN was depending on the global handler for
the fatal error handling and logging.
Instead of fixing this in `ReactFiberErrorDialog`, we can implement the
new root options in RN to handle caught/uncaught/recoverable in the
respective functions, and delete ReactFiberErrorDialog. I'll follow up
with a RN PR to implement these options and fix the error handling.
<!--
Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.
Before submitting a pull request, please make sure the following is
done:
1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
10. If you haven't already, complete the CLA.
Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->
## Summary
<!--
Explain the **motivation** for making this change. What existing problem
does the pull request solve?
-->
The ReadableStreamController for [direct
streams](https://bun.sh/docs/api/streams#direct-readablestream) in Bun
supports a flush() method to flush all buffered items to its underlying
sink.
Without manually calling flush(), all buffered items are only flushed to
the underlying sink when the stream is closed. This behavior causes the
shell rendered against Suspense boundaries never to be flushed to the
underlying sink.
## How did you test this change?
<!--
Demonstrate the code is solid. Example: The exact commands you ran and
their output, screenshots / videos if the pull request changes the user
interface.
How exactly did you verify that your PR solves the issue you wanted to
solve?
If you leave this empty, your PR will very likely be closed.
-->
A lot of changes to the test runner will need to be made in order to
support the Bun runtime. A separate test was manually run in order to
ensure that the changes made are correct.
The test works by sanity-checking that the shell rendered against
Suspense boundaries are emitted first in the stream.
This test was written and run on Bun v1.1.3.
```ts
import { Suspense } from "react";
import { renderToReadableStream } from "react-dom/server";
if (!import.meta.resolveSync("react-dom/server").endsWith("server.bun.js")) {
throw new Error("react-dom/server is not the correct version:\n " + import.meta.resolveSync("react-dom/server"));
}
const A = async () => {
await new Promise(resolve => setImmediate(resolve));
return <div>hi</div>;
};
const B = async () => {
return (
<Suspense fallback={<div>loading</div>}>
<A />
</Suspense>
);
};
const stream = await renderToReadableStream(<B />);
let text = "";
let count = 0;
for await (const chunk of stream) {
text += new TextDecoder().decode(chunk);
count++;
}
if (
text !==
`<!--$?--><template id="B:0"></template><div>loading</div><!--/$--><div hidden id="S:0"><div>hi</div></div><script>$RC=function(b,c,e){c=document.getElementById(c);c.parentNode.removeChild(c);var a=document.getElementById(b);if(a){b=a.previousSibling;if(e)b.data="$!",a.setAttribute("data-dgst",e);else{e=b.parentNode;a=b.nextSibling;var f=0;do{if(a&&8===a.nodeType){var d=a.data;if("/$"===d)if(0===f)break;else f--;else"$"!==d&&"$?"!==d&&"$!"!==d||f++}d=a.nextSibling;e.removeChild(a);a=d}while(a);for(;c.firstChild;)e.insertBefore(c.firstChild,a);b.data="$"}b._reactRetry&&b._reactRetry()}};$RC("B:0","S:0")</script>`
) {
throw new Error("unexpected output");
}
if (count !== 2) {
throw new Error("expected 2 chunks from react ssr stream");
}
```
The compiler has an optimisation where it transforms a simple arrow
function with only a return statement to a implicit arrow function.
In the case, there's a directive in this simple arrow function, the
directive gets dropped.
Instead of dropping the directive, the compiler should perform this
optimisation only if there are no directives.
ghstack-source-id: 514cd2440025986a2d6d950694a7339d779b09f2
Pull Request resolved: https://github.com/facebook/react-forget/pull/2848
The useMemoCache polyfill doesn't have access to the fiber, and it
simply uses state, which does not work with the existing devtools
badge for the compiler.
With this PR, devtools will look on the very first hook's state for the
memo cache sentinel and display the Forget badge if present.
The polyfill will add this sentinel to it's state (the cache array).