• Stars
    star
    141
  • Rank 259,971 (Top 6 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created almost 2 years ago
  • Updated 9 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

utils to render remix into a dom-node instead of the whole document

remix-island

🚨 this package is a workaround to allow usage of remix with react@(18.0 - 18.2) which comes with a lot of hydration problems. I'll probably not maintain this for long after [email protected] hopefully fixes this.

ref https://github.com/remix-run/remix/issues/5463, remix-run/remix#5144, remix-run/remix#4822, remix-run/remix#5244, facebook/react#24430


utils to render remix into a dom-node (like <div id="root"></div>) instead of the whole document

This approach was pioneered by @kiliman in kiliman/remix-hydration-fix 🙏👍🎉

install

npm i remix-island

configure

1. Stop rendering the whole html document from within remix

--- a/app/root.tsx
+++ b/app/root.tsx
@@ -7,6 +7,7 @@ import {
   Scripts,
   ScrollRestoration,
 } from '@remix-run/react';
+import { createHead } from 'remix-island';

 export const meta: MetaFunction = () => ({
   charset: 'utf-8',
@@ -14,19 +15,21 @@ export const meta: MetaFunction = () => ({
   viewport: 'width=device-width,initial-scale=1',
 });

+export const Head = createHead(() => (
+  <>
+    <Meta />
+    <Links />
+  </>
+));
+
 export default function App() {
   return (
-    <html lang="en">
-      <head>
-        <Meta />
-        <Links />
-      </head>
-      <body>
-        <Outlet />
-        <ScrollRestoration />
-        <Scripts />
-        <LiveReload />
-      </body>
-    </html>
+    <>
+      <Head />
+      <Outlet />
+      <ScrollRestoration />
+      <Scripts />
+      <LiveReload />
+    </>
   );
 }

2. Manually render the <Head /> and create the document

--- a/app/entry.server.tsx
+++ b/app/entry.server.tsx
@@ -4,6 +4,8 @@ import { Response } from '@remix-run/node';
 import { RemixServer } from '@remix-run/react';
 import isbot from 'isbot';
 import { renderToPipeableStream } from 'react-dom/server';
+import { renderHeadToString } from 'remix-island';
+import { Head } from './root';

 const ABORT_DELAY = 5000;

@@ -41,6 +43,7 @@ function handleBotRequest(
       <RemixServer context={remixContext} url={request.url} />,
       {
         onAllReady() {
+          const head = renderHeadToString({ request, remixContext, Head });
           const body = new PassThrough();

           responseHeaders.set('Content-Type', 'text/html');
@@ -51,8 +54,11 @@ function handleBotRequest(
               status: didError ? 500 : responseStatusCode,
             }),
           );

+          body.write(
+            `<!DOCTYPE html><html><head>${head}</head><body><div id="root">`,
+          );
           pipe(body);
+          body.write(`</div></body></html>`);
         },
         onShellError(error: unknown) {
           reject(error);
@@ -82,6 +88,7 @@ function handleBrowserRequest(
       <RemixServer context={remixContext} url={request.url} />,
       {
         onShellReady() {
+          const head = renderHeadToString({ request, remixContext, Head });
           const body = new PassThrough();

           responseHeaders.set('Content-Type', 'text/html');
@@ -93,7 +100,11 @@ function handleBrowserRequest(
             }),
           );

+          body.write(
+            `<!DOCTYPE html><html><head>${head}</head><body><div id="root">`,
+          );
           pipe(body);
+          body.write(`</div></body></html>`);
         },
         onShellError(err: unknown) {
           reject(err);

3. hydrate <div id="root">

--- a/app/entry.client.tsx
+++ b/app/entry.client.tsx
@@ -5,7 +5,7 @@ import { hydrateRoot } from 'react-dom/client';
 function hydrate() {
   startTransition(() => {
     hydrateRoot(
-      document,
+      document.getElementById('root')!,
       <StrictMode>
         <RemixBrowser />
       </StrictMode>,

4. Value 💰

pitfalls/notes

TL;DR:

Everything that does not need to be managed by remix should be placed before ${head} in entry.server.tsx.

Order of elements in head might change

The remix-managed <Head /> which includes all the stuff from MetaFunction and LinksFunction will move to the end of <head /> once the client is hydrated. If you combine this with other libraries that inject elements into the head (like styled-components) this might lead to unexpected behaviour. Move all global styles out of remix into the static <head /> to minimize impact of this.

Scripts might run twice

Due to how this "hack" is working, if you have other bootstrap scripts (for example raygun). These might run twice. Move them out of remix into the static <head /> to prevent this.

Flash of unstyled content

Some users of this notice a flash of unstyled content when remix manages some of the CSS. We found that most of the time this only happens in development with browser cache disabled. When you observe something like this in production with cache enabled try moving all global styles out of remix into the static <head />.

Usage with Stitches

@louisremi found out that for stitches it's required to render the <Head /> after the rest of the document (#11)

More Repositories

1

cachified

wrap virtually everything that can store by key to act as cache with ttl/max-age, stale-while-validate, parallel fetch protection and type-safety support
TypeScript
575
star
2

budgetbudget

🧮 make financial decisions with confidence
TypeScript
93
star
3

github-sync-labels-milestones

Sync Labels and Milestones across Multiple repositories
JavaScript
47
star
4

test-real-styles

(test-)framework agnostic utilities to test real styling of (virtual) dom elements
TypeScript
38
star
5

din-5008-css

css for layouting a A4 paper according to DIN-5008
HTML
21
star
6

remix-polyglot

type-safe, cached-forever, split-able, non-flickering, pre-loading, persistence-agnostic internationalization made for remix ♥
TypeScript
11
star
7

WP-Project-Update-API

Handles Wordpress plugin and theme update requests by comparing the request data with files hosted on github, bitbucket or gitlab.
PHP
11
star
8

Password-Generator-for-zsh

A simple tool to generate random strings.
Shell
10
star
9

dom-to-playwright

move jsdom snapshots into a real browser
TypeScript
7
star
10

karma-environments

Run multiple test suites in one karma process.
CoffeeScript
6
star
11

alfred-translate

translation workflow for Alfred using deepL
PHP
4
star
12

SlimAssets

Simple Asset Manager for Slim PHP.
PHP
4
star
13

HTML

The clean code approach
PHP
3
star
14

Dynamic-PHP-Proxy

A PHP based, self-hosted alternative for Dynamic DNS Services.
PHP
3
star
15

LGTM

Alfred workflow to paste "LGTM" along with a random fun animal to brighten up everybody's day <3
JavaScript
2
star
16

Base

Basic logic for new projects. Provides singleton, configuration, callback and basic api methods.
PHP
2
star
17

DropboxConflictMerger

Can search in your Dropbox for conflicted files and present you a clear way to merge them into one file again.
PHP
2
star
18

THEMASTER

A Plugin to provide global access to the THEWPMASTER class. THEWPMASTER provides a lot of handy functions for plugins an themes. WP-stuff can be skipped for standalone usage.
PHP
2
star
19

WP-Relation-Boxes

A Wordpress Plugin for easy enabling n-1, 1-1 and n-n relationships between any Posttype.
PHP
1
star
20

yaml-doc-query

lookup values along with their position in yaml documents
TypeScript
1
star
21

pomodohub

one should™ build a pomodoro app that integrates with GitHub issues and possibly other issue trackers
1
star
22

uberconfig

configuration manager for multi-module configs
JavaScript
1
star
23

jquery.hrmny

A jQuery plugin that writes css rules for colors based on customizable rules and base colors.
JavaScript
1
star
24

next-dynamic-route-in-zone

JavaScript
1
star
25

get-project-usage

Get used versions of a package across all projects of a github user
JavaScript
1
star
26

xiphe.github.io

My personal website
HTML
1
star
27

droppipe

Pipe Dropbox Delta changes to gulp
CoffeeScript
1
star
28

HDHotKeys

Autohotkey compilation for webdesign and programming
AutoHotkey
1
star
29

markdown-to-test

extract code examples from markdown to test files
TypeScript
1
star
30

gulp-is-thirteen

streaming support for is-thirteen
JavaScript
1
star
31

npm_keychain_auth

npm wrapper for using _auth config without exposing your credentials in your global env or .npmrc files
JavaScript
1
star
32

jasmine-moar-matchers

Additional matchers for jasmine 2.0
JavaScript
1
star
33

cra-ts-tailwind

create react app with tailwind and typescript
TypeScript
1
star
34

minimal-wordpress-theme

A minimalistic, text-only, black&white wordpress theme
CSS
1
star
35

Interangement

Bring some programming magic to music notation.
JavaScript
1
star
36

THEDEBUG

Toolset for debugging PHP
PHP
1
star
37

jQuery.keyboardfilter

Enables/disables specific key events on a specific element using keyCodes or keyGroups
JavaScript
1
star
38

find-my-tracker

collection of scripts and helpers that can be used to monitor status and location of a apple device using find my iPhone
JavaScript
1
star
39

sc-variant

tiny helper to create variants of styled components
TypeScript
1
star