* Add failing tests for lazy components
* Fix bailout broken in lazy components due to default props resolving
We should never compare unresolved props with resolved props. Since comparing
resolved props by reference doesn't make sense, we use unresolved props in that
case. Otherwise, resolved props are used.
* Avoid reassigning props warning when we bailout
* Bugfix: Render phase update leads to dropped work
Render phase updates should not affect the `fiber.expirationTime` field.
We don't have to set anything on the fiber because we're going to
process the render phase update immediately.
We also shouldn't reset the `expirationTime` field in between render
passes because it represents the remaining work left in the update
queues. During the re-render, the updates that were skipped in the
original pass are not processed again.
I think my original motivation for using this field for render phase
updates was so I didn't have to add another module level variable.
* Add repro case for #18486
Co-authored-by: Dan Abramov <dan.abramov@me.com>
* Add another test for #18515 using pings
Adds a regression test for the same underlying bug as #18515 but using
pings.
Test already passes, but I confirmed it fails if you revert the fix
in #18515.
* Set nextPendingLevel after commit, too
* Reproduce a bug where `flushDiscreteUpdates` causes fallback never to be committed
* Ping suspended level when canceling its timer
Make sure the suspended level is marked as pinged so that we return back
to it later, in case the render we're about to start gets aborted.
Generally we only reach this path via a ping, but we shouldn't assume
that will always be the case.
* Clear finished discrete updates during commit phase
If a root is finished at a priority lower than that of the latest pending discrete
updates on it, these updates must have been finished so we can clear them now.
Otherwise, a later call of `flushDiscreteUpdates` would start a new empty render
pass which may cause a scheduled timeout to be cancelled.
* Add TODO
Happened to find this while writing a test. A JSX element comparison
failed because one of them elements had a functional component as an
owner, which should ever happen.
I'll add a regression test later.
Co-authored-by: Andrew Clark <git@andrewclark.io>
* Filter certain DOM attributes (e.g. src, href) if their values are empty strings
This prevents e.g. <img src=""> from making an unnecessar HTTP request for certain browsers.
* Expanded warning recommendation
* Improved error message
* Further refined error message
* Add useOpaqueIdentifier Hook
We currently use unique IDs in a lot of places. Examples are:
* `<label for="ID">`
* `aria-labelledby`
This can cause some issues:
1. If we server side render and then hydrate, this could cause an
hydration ID mismatch
2. If we server side render one part of the page and client side
render another part of the page, the ID for one part could be
different than the ID for another part even though they are
supposed to be the same
3. If we conditionally render something with an ID , this might also
cause an ID mismatch because the ID will be different on other
parts of the page
This PR creates a new hook `useUniqueId` that generates a different
unique ID based on whether the hook was called on the server or client.
If the hook is called during hydration, it generates an opaque object
that will rerender the hook so that the IDs match.
Co-authored-by: Andrew Clark <git@andrewclark.io>
* Add feature flag
* Split stack from current fiber
You can get stack from any fiber, not just current.
* Refactor description of component frames
These should use fiber tags for switching. This also puts the relevant code
behind DEV flags.
* We no longer expose StrictMode in component stacks
They're not super useful and will go away later anyway.
* Update tests
Context is no longer part of SSR stacks. This was already the case on the
client.
forwardRef no longer is wrapped on the stack. It's still in getComponentName
but it's probably just noise in stacks. Eventually we'll remove the wrapper
so it'll go away anyway. If we use native stack frames they won't have this
extra wrapper.
It also doesn't pick up displayName from the outer wrapper. We could maybe
transfer it but this will also be fixed by removing the wrapper.
* Forward displayName onto the inner function for forwardRef and memo in DEV
This allows them to show up in stack traces.
I'm not doing this for lazy because lazy is supposed to be called on the
consuming side so you shouldn't assign it a name on that end. Especially
not one that mutates the inner.
* Use multiple instances of the fake component
We mutate the inner component for its name so we need multiple copies.
* Remove unnecessary CapturedError fields.
componentName is not necessary and is misleading when the error is caused
elsewhere in the stack. The stack is sufficient.
The many error boundary fields are unnecessary because they can be inferred
by the boundary itself.
* Don't attempt to build a stack twice
If it was possible, it would've been done in createCapturedValue.
* Push the work needed by the works into the forks
This avoids needing this in the npm published case.
* Lazily initialize models as they're read intead of eagerly when received
This ensures that we don't spend CPU cycles processing models that we're
not going to end up rendering.
This model will also allow us to suspend during this initialization if
data is not yet available to satisfy the model.
* Refactoring carefully to ensure bundles still compile to something optimal
* Remove generic from Response
The root model needs to be cast at one point or another same as othe
chunks. So we can parameterize the read instead of the whole Response.
* Read roots from the 0 key of the map
The special case to read the root isn't worth the field and code.
* Store response on each Chunk
Instead of storing it on the data tuple which is kind of dynamic, we store
it on each Chunk. This uses more memory. Especially compared to just making
initializeBlock a closure, but overall is simpler.
* Rename private fields to underscores
Response objects are exposed.
* Encode server components as delayed references
This allows us to stream in server components one after another over the
wire. It also allows parallelizing their fetches and resuming only the
server component instead of the whole parent block.
This doesn't yet allow us to suspend deeper while waiting on this content
because we don't have "lazy elements".
* Eject CRA from Flight
We need to eject because we're going to add a custom Webpack Plugin.
We can undo this once the plugin has upstreamed into CRA.
* Add Webpack plugin build
I call this entry point "webpack-plugin" instead of "plugin" even though
this is a webpack specific package. That's because there will also be a
Node.js plugin to do the server transform.
* Add Flight Webpack plugin to fixture
* Rm UMD builds
* Transform classes
* Rename webpack-plugin to plugin
This avoids the double webpack name. We're going to reuse this for both
server and client.
* Remove /dist/ UMD builds
We publish UMDs to npm (and we're considering stopping even that).
This means we'll stop publishing to http://react.zpao.com/builds/master/latest/
* Update fixture paths
This is a variant of the fix in 5a0f1d. We can't rely on the primary
fiber's `childExpirationTime` field to be correct.
In this case, we can read from the Suspense boundary fiber instead.
This will include updates that exist in the fallback fiber, but that's
not a big deal; the important thing is that we don't drop updates.