Log entry #6: on the day React’s own dispatcher attempted to become window.dispatchEvent
Today six items were shipped; one took a lot longer to track down than it should have.
The bug: clicking search crashed the site, but only in production
Click the search bar, and the command palette should appear. Instead, the deployed build produced:
Cannot read properties of undefined (reading ‘target’)
Deep inside React’s event system. Not during development. Only in production.
It has now been discovered that the island bundle is shipped as a classic rather than as a module, as a result, top-level declarations end up on the window object. In the minified bundle there was a top-level function called dispatchEvent: this was React DOM’s internal event dispatcher, having the same name as the browser’s actual dispatchEvent function, and it quietly overwritten window.dispatchEvent.
The search trigger causes a synthetic ⌘K keydown event to be sent to the window in order to activate the palette island. It was doing this by calling React’s internal dispatcher with a raw keydown event and without a nativeEvent, which caused React to fail when it tried to read .target from an object of the incorrect shape.
Solution: wrap each emitted island bundle (including the build output and the dev path) in an IIFE so that no top-level declaration now reaches the window object at all. This has been tested to ensure it works correctly.
Nested layouts were rendering inside-out
The _layout.tsx files contained within the route folders were behaving incorrectly by having the section layout wrap the root rather than the reverse. In order to correct this, the wrap order was reversed in the function renderPageWithLayout so that the root always remains the outermost element.
Hydration mismatches stopped spamming the console
Islands that have a non-deterministic initial state (mostly games) will always cause a mismatch with SSR output; although React handles the situation without any problems by re-rendering on the client side, each mismatch is still logged as a full error which could in turn spread through the event system. A no-op function was passed to the onRecoverableError handler so that these errors fail silently.
Shipped: ⌘K command palette + a konami code easter egg
The fuzzy-search palette is now its own island with React as its root, appearing through the same synthetic keydown event that brought up the bug mentioned above (as usual, dogfooding), and I’ve also included a Konami code easter egg.
Vercel adapter
The x build –adapter vercel now produces a proper .vercel/output in accordance with Vercel’s Build Output API, including the static HTML and island chunks as well as a bundled serverless render function. The route preloading and createApp have been adjusted so that the behaviour of the static and serverless versions matches that of local development. The packages/adapter-vercel have been divided into their own workspace package.
Landing redesign + /play
New styles, fonts, loading states, and the logo on the docs site. The bigger addition is the /play feature, which turns the framework into a small arcade—route matching treated as a game, an interactive environment leak-protection demonstration, and a static-versus-server call behaviour that you can click through. Two components have already been developed: leak-check (to provide a visual indication of the client/server boundary) and mode-call (comparing static and server rendering side by side).
There are six fixes, one adapter, one new page, and a bug resulting from two functions sharing a name rather too casually. Tomorrow: it will probably be more of the same.
Comments 0
No comments yet. Be the first!
Sign in to join the conversation.