v0.21.0
Branches
main (2.15.1)dev
Versions
2.15.11.19.3v0.21.0
Viewing docs for an older release. View latest
On this page

v0.10.0 Release Notes

Release Overview on YouTube

Root Layout Route

Background

The App.tsx file has been a little bit goofy. This release cleans that up. Instead of needing to import the app file into both entry-server and entry-client, we've now got the concept of a "root route". This root route works like all others, it can export a loader and error boundary, etc.

This small change removes a few APIs and a lot of complexity in Remix's internals. It was one of those -200 line changes without losing any features, which always feels amazing.

Upgrading:

Move App.tsx to root.tsx

Move your App.tsx to root.tsx. "root" has special meaning, so it must be named that.

Change <Routes/> to <Outlet/>

Now that root.tsx is a route, you render an Outlet just like every other layout route.

// OLD
import { Routes } from "remix";

export default function App() {
  return (
    <html>
      {/* ... */}
      <body>
        <Routes />
      </body>
    </html>
  );
}

// NEW
// Note it's from "react-router-dom"!
import { Outlet } from "react-router-dom";

export default function App() {
  return (
    <html>
      {/* ... */}
      <body>
        <Outlet />
      </body>
    </html>
  );
}

Move global data code

Because root.tsx iss now a route it can export a loader for it's own data. If you had a global-data.ts file, cut and paste the code into root.tsx so it's co-located like all of your other routes.

Also, there is no longer a useGlobalData hook because this is now normal route data. So change your useGlobalData() to useRouteData().

Update your server and browser entries

Don't import or render App.tsx in entry-server or entry-browser anymore:

// OLD: entry-server
import App, { ErrorBoundary } from "./App";

let markup = ReactDOMServer.renderToString(
  <Remix
    context={remixContext}
    url={request.url}
    ErrorBoundary={ErrorBoundary}
  >
    <App />
  </Remix>
);

// NEW: entry-server
// - no more App import because you moved it to `root.tsx`
// - no more ErrorBoundary prop because the root route exports
//   it's own error boundary like any other route
let markup = ReactDOMServer.renderToString(
  <Remix context={remixContext} url={request.url} />
);

Do the same thing in entry-browser.tsx, it'll end up looking something like this:

import ReactDOM from "react-dom";
import Remix from "@remix-run/react/browser";

ReactDOM.hydrate(<Remix />, document);

Much nicer! No more special casing the root layout. We're also thinking this opens up the possibility for multiple root layouts: think signed-in-layout and signed-out-layout". We're not there yet though :)

Importing images

You can now import and resize images as a JavaScript module containing links to the assets, height and width attributes, and even responsive image source sets. Check it out!

// - change quality to 50
// - reformat to avif
// - generate a server rendered Base64 blurry placeholder
// - resize to 500
import guitar from "img:./guitar.jpg?quality=50&format=avif&placeholder&width=500";

// - change quality to 80
// - generate 3 responsive image sizes and a srcset for the `<img srcSet/>`
// - generate a ssr placeholder
import guitar2 from "img:./guitar.jpg?quality=80&srcset=720,1080,2048&placeholder";

export default function Guitar() {
  return (
    <div>
      <p>Fixed Image</p>
      <img
        alt="Guitar"
        src={guitar.src}
        style={{
          backgroundImage: `url(${guitar.placeholder})`,
          backgroundSize: "cover"
        }}
        width={guitar.width / 2}
        height={guitar.height / 2}
      />

      <p>Responsive</p>
      <img
        alt="Guitar"
        src={guitar2.src}
        srcSet={guitar2.srcset}
        style={{
          backgroundImage: `url(${guitar2.placeholder})`,
          backgroundSize: "cover"
        }}
      />
    </div>
  );
}

Go read the docs for more information!

Docs and examples licensed under MIT