Pedro Cattori · @pcattori



Legendary DX
The Quest for

Part I
<Link to="the past"/>
1: File Server 🗡️
🤩
Browser
📚
html, css, js
🫥
📚
🫥
📚
📚
🫥
📚
📚
🤩
📚
2: Build + Watch 🗡️
📁
Source code
ESM
📁
Source code
ESM
📁
Source code
🤓
Compiler
🫥
🤓
📁
🤓
📁
🫥
📚
🫥
📚
🤓
📁
📚
🫥
📚
📚
🤓
📁
🤩
📚
🤓
📁
🤩
📚
✍️
🤓
📁
👀
📁
🤩
📚
✍️
✍️
🤓
📁
🤩
📚
✍️
✍️
🤓
📁
🤩
📚
✍️
✍️

3: Live Reload 🗡️
🤩
📚
✍️
🤓
📁
👀
📁
🤩
📚
✍️
✍️
🤓
📁
🤩
📚
✍️
✍️
🔁
🤩
📚
🤓
📁
🤓
📁
🔁
✍️
✍️
🔁
📚
🤓
📁
🤓
📁
✍️
✍️
🫥
📚
🤓
📁
🤓
📁
📚
✍️
✍️
🫥
📚
🤓
📁
🤓
📁
📚
🤩
📚
🤓
📁
🤓
📁
✍️


4: HMR 🗡️





🤠
hot-swap.js
🤠
hot-swap.js
(aka HMR runtime)
🫥
🤓
📁
🤓
📁
🫥
📚
🤠
🫥
📚
🤓
📁
📚
🤠
🤠
🫥
📚
📚
🤓
📁
🤠
🤠
🤩
📚
🤓
📁
🤠
🤠
🤩
📚
✍️
🤓
📁
🤠
🤠
👀
📁
🤩
📚
✍️
✍️
🤠
🤠
🤓
📁
🤩
📚
✍️
✍️
✍️
🤠
🤠
🤩
📚
🤓
📁
🤓
📁
✍️
✍️
✍️
🤠
🤠
🤩
📚
🤓
📁
🤓
📁
✍️
✍️
✍️
🔁
🤠
🤩
📚
🤓
📁
🤓
📁
✍️
✍️
✍️
🤠
🤠
DEMO #1
Tears of the Server
Part II
😎
App Server
📙
server.js
🤓
🫥
📁
🤓
🫥
📁
📚
📙
🤠
🤓
🫥
📁
📚
📙
🤠
🏃♂️
📙
🤓
🫥
📁
📚
📙
🤠
🏃♂️
📙
🤓
🫥
📁
📚
📙
🤠
😎
localhost:3000
🤓
🫥
📁
📚
📙
🤠
😎
🤓
🫥
📁
📚
📙
🤠
😎
📚
🤠
🤓
🫥
📁
📚
📙
🤠
😎
📚
🤠
{"place": "world"}
🤓
🫥
📁
📚
📙
🤠
😎
📚
🤠
{"place": "world"}
🤓
🤩
📁
📚
📙
🤠
😎
🤠
🌇
{"place": "world"}
import { json } from "@remix-run/node"
import { useLoaderData } from "@remix-run/react"
export let loader = () => {
return json({ place: "world" })
}
export default Component() {
let { place } = useLoaderData<typeof loader>()
return (
<main>
<h1>Hey there, Remix Conf 👋</h1>
<h2>And hello, {place}!</h2>
</main>
)
}
✍️
import { json } from "@remix-run/node"
import { useLoaderData } from "@remix-run/react"
export let loader = () => {
return json({ place: "world" })
}
export default Component() {
let { place } = useLoaderData<typeof loader>()
return (
<main>
<h1>Hey there, friends 👋</h1>
<h2>And hello, {place}!</h2>
</main>
)
}
✍️
import { json } from "@remix-run/node"
import { useLoaderData } from "@remix-run/react"
export let loader = () => {
return json({ location: "Salt Lake City" })
}
export default Component() {
let { place } = useLoaderData<typeof loader>()
return (
<main>
<h1>Hey there, friends 👋</h1>
<h2>And hello, {place}!</h2>
</main>
)
}
✍️
import { json } from "@remix-run/node"
import { useLoaderData } from "@remix-run/react"
export let loader = () => {
return json({ location: "Salt Lake City" })
}
export default Component() {
let { location } = useLoaderData<typeof loader>()
return (
<main>
<h1>Hey there, friends 👋</h1>
<h2>And hello, {location}!</h2>
</main>
)
}
✍️
SAVE
✍️
import { json } from "@remix-run/node"
import { useLoaderData } from "@remix-run/react"
export let loader = () => {
return json({ location: "Salt Lake City" })
}
export default Component() {
let { location } = useLoaderData<typeof loader>()
return (
<main>
<h1>Hey there, friends 👋</h1>
<h2>And hello, {location}!</h2>
</main>
)
}
🤓
🤩
📁
📚
📙
🤠
😎
🤠
🌇
✍️
{"place": "world"}
👀
🤩
📁
📚
📙
🤠
😎
🤠
🌇
✍️
✍️
✍️
{"place": "world"}
🤓
🤩
📁
📚
📙
🤠
😎
🤠
🌇
✍️
✍️
✍️
✍️
{"place": "world"}
🤓
🤩
📁
📚
📙
🤠
😎
🤠
🌇
✍️
✍️
✍️
✍️
{"place": "world"}
🤓
🤩
📁
📚
📙
🤠
😎
🔁
🌇
✍️
✍️
✍️
✍️
{"place": "world"}
🤓
🤯
📁
📚
📙
🤠
😎
🤠
✍️
✍️
✍️
✍️
{"place": "world"}
let { location } =
Demo #2
🤓
😎
🥸
?
🥸
!=
😎
🥸
!=
😎
🐞
🐛
🥸
!=
😎
🐞
🐛
🐰
🐆
🥸
!=
😎
❌
🥸
~=
😎
🥸
~=
😎



🥸
~=
😎



❌
💡
💡
🤓
👂
📣
😎
"Ready!"
Part III
A between Worlds
fetch
🤓
🤩
📁
😎
🤓
🤩
📁
😎
💪
🤓
🫥
📁
📚
📙
🤠
🤓
🫥
📁
📚
📙
🤠
📙
🏃♂️
🤓
🫥
📁
📚
📙
🤠
📙
🏃♂️
🤓
🫥
📁
📚
📙
🤠
😎
🤠
📚
🤓
🫥
📁
📚
📙
🤠
😎
🤠
📚
🤓
🫥
📁
📚
📙
🤠
😎
🤠
📚
📚
🤓
🫥
📁
📚
📙
🤠
😎
🤠
📚
📚
🤓
🤩
📁
📚
📙
🤠
😎
🤠
📚
🤓
🤩
📁
📚
📙
🤠
😎
🤠
📚
✍️
👀
🤩
📁
📚
📙
🤠
😎
🤠
📚
✍️
✍️
✍️
🤓
🤩
📁
📚
📙
🤠
😎
🤠
📚
✍️
✍️
✍️
🤓
🤩
📁
📚
📙
🤠
😎
🤠
📚
✍️
✍️
✍️
⏳
👂
🤓
🤩
📁
📚
📙
🤠
👀
🤠
📚
✍️
✍️
✍️
⏳
👂
🤓
🤩
📁
📚
📙
🤠
💀
🤠
📚
✍️
✍️
✍️
⏳
👂
🤓
🤩
📁
📚
🤠
🏃♂️
🤠
📚
✍️
✍️
⏳
👂
✍️
📙
📙
✍️
🤓
🤩
📁
📚
🤠
😎
🤠
📚
✍️
✍️
⏳
👂
✍️
📙
✍️
✅
🤓
🤩
📁
📚
🤠
😎
🤠
📚
✍️
✍️
⏳
👂
✍️
📙
✍️
✅
🤓
🤩
📁
📚
🤠
😎
🤠
📚
✍️
✍️
✍️
📙
✍️
✍️
🤓
🤩
📁
📚
🤠
😎
🤠
📚
✍️
✍️
✍️
📙
✍️
✍️
🤓
🤩
📁
📚
🤠
😎
⏳
📚
✍️
✍️
✍️
📙
✍️
✍️
{"location": "world"}
🤓
🤩
📁
📚
🤠
😎
🔁
📚
✍️
✍️
✍️
📙
✍️
{"location": "world"}
✍️
🤓
🤩
📁
📚
🤠
😎
🔁
📚
✍️
✍️
✍️
📙
✍️
{"location": "world"}
✍️
🤓
🤩
📁
📚
🤠
😎
🤠
📚
✍️
✍️
✍️
📙
✍️
✍️
let { location } =
{"location": "world"}
Hot Data Revalidation
🔥
🔥
😎
💀
🏃♂️
😎
✍️
😎
💀
🏃♂️
😎
✍️
downtime
😎
💀
🏃♂️
😎
✍️
downtime
👎
Part IV
Ocarina of Downtime
😎
😎
✍️
💀
🏃♂️
🤠
hot-swap-server.js
😎
🤠
📙
😎
🤠
📙
✍️
😎
👀
📙
✍️
✍️
😎
🤠
📙
✍️
✍️
😎
🔁
📙
✍️
✍️
😎
🤠
📙
✍️
✍️
const BUILD_PATH = path.resolve(__dirname, "build");
function purgeRequireCache() {
for (const key in require.cache) {
if (key.startsWith(BUILD_DIR)) {
delete require.cache[key];
}
}
}
const watcher = chokidar.watch(BUILD_PATH);
watcher.on("all", () => {
// 1. purge require cache
purgeRequireCache();
// 2. load updated server build
const build = require(BUILD_PATH);
// 3. tell dev server that this app server is now ready
broadcastDevReady(build);
});
let createDevRequestHandler = (req, res, next) => {
return createRequestHandler({
build: require(BUILD_DIR),
mode: "development",
})(req, res, next);
}
CJS
function createDevRequestHandler() {
let devBuild = build;
const watcher = chokidar.watch(BUILD_PATH, { ignoreInitial: true });
watcher.on("all", async () => {
// 1. purge require cache && load updated server build
const stat = fs.statSync(BUILD_PATH);
devBuild = import(BUILD_PATH + "?t=" + stat.mtimeMs);
// 2. tell dev server that this app server is now ready
broadcastDevReady(await devBuild);
});
return async (req, res, next) => {
return createRequestHandler({
build: await devBuild,
mode: "development",
})(req, res, next);
};
}
ESM
🤓
🤩
😎
🤓
🤩
😎
🤓
🤩
😎
🤓
🤩
😎
🤓
🤩
😎
🤓
🤩
😎
https://remix.run/blog/remix-data-flow

🤓
🤩
😎

https://redux.js.org/tutorials/fundamentals/part-2-concepts-data-flow
🤓
🤩
😎
🤓
🤩
😎
🤓
🤩
😎
Legendary DX
By pcattori
Legendary DX
- 255