Do you ever look at a page on your site and think "why are we loading all of this JavaScript? There's nothing on this page but links!" This may seem a little odd for a JavaScript framework, but you can easily turn off JavaScript with a boolean but your data loading and links will still all work.
Here's how we like to do it:
handle
to JavaScript Enabled Route ModulesOpen up each route module you want to include JavaScript for and add this:
export let handle = { hydrate: true };
Now open root.tsx
, bring in useMatches
and add this:
import React from "react";
import {
Meta,
Links,
Scripts,
Outlet,
useMatches
} from "remix";
export default function App() {
let matches = useMatches();
// If at least one route wants to hydrate, this will return true
let includeScripts = matches.some(
match => match.handle?.hydrate
);
// then use the flag to render scripts or not
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<Meta />
<Links />
</head>
<body>
<Outlet />
{/* include the scripts, or not! */}
{includeScripts && <Scripts />}
</body>
</html>
);
}
All of your data loading will still work on the server render, and all of your <Link>
s render normal <a>
underneath, so they will continue to work.
On any page, at anytime, you can flip between plain HTML and full clientside transitions.
If you need one tiny bit of interactivity, use a <script dangerouslySetInnerHTML>
.
<select id="qty">
<option>1</option>
<option>2</option>
<option value="contact">Contact Sales for more</option>
</select>
<script
dangerouslySetInnerHTML={{
__html: `
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('qty').onchange = (event) => {
if (event.target.value === "contact") {
window.location.assign("/contact")
}
}
});
`,
}}
/>
There's little reason to load 100kb of JavaScript for one small interactive piece of a landing page.