How toDowngrade to MPA if users prefer reduced data in Remix

Users can enable a setting in their devices to indicate to websites that they prefer reduced data usage.

When this setting is enabled, websites should reduce the data they use. We can achieve this by disabling images, videos, and other media. It can also be done by disabling JavaScript.

In Remix, we can quickly stop sending client-side JS, and if we use progressive enhancement techniques, the user experience will be the same.

Detect Save Data in the loader

Browsers let you know if the user has enabled Data Saver by setting the Save-Data header to on in the request. You can detect this in your server-side code and send a different response.

export async function loader({ request }: LoaderArgs) {
  let saveData = request.headers.get("Save-Data") === "on";
  return json({ saveData });
}

Disable JS

We can do this by not rendering the Scripts component in the root route.

// imports here...

export async function loader({ request }: LoaderArgs) {
  let saveData = request.headers.get("Save-Data") === "on";
  return json({ saveData });
}

export default function App() {
  let { saveData } = useLoaderData<LoaderData>();

  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1" />
        {title ? <title>{title}</title> : null}
        <Meta />
        <Links />
      </head>
      <body>
        <Outlet />
        {!saveData ? (
          <>
            <ScrollRestoration />
            <Scripts />
          </>
        ) : null}
        <LiveReload />
      </body>
    </html>
  );
}

By conditionally rendering Scripts and ScrollRestoration we could downgrade the UX from a SPA that may need hundreds of KB of JS to an MPA with 0 KB of JS that still works thanks to progressive enhancement.

Finally, remember to add Vary: Save-Data to your response headers so that the browser knows to cache the response separately for users with and without Data Saver enabled in case you're using Cache-Control.