a first look at wmr
wmrpreactesmwmr is an all-in-one development tool for modern web apps. Since it leverages ESM modules, it only requires an HTML files with <script type=module>
. It stands for Waldo's My Roommate and anyone who tells you otherwise is wrong.
Setup project with blank package.json #
mkdir ajcwebdev-wmr
cd ajcwebdev-wmr
touch package.json
Add wmr to devDependencies #
{
"devDependencies": {
"wmr": "^1.2.0"
}
}
Install preact dependencies #
yarn add preact preact-iso
preact-iso includes Isomorphic async tools for Preact including:
- Lazy-load components using
lazy()
and<ErrorBoundary>
- Generate static HTML for your app using
prerender()
, waiting forlazy()
components and data dependencies. - Implement async-aware client and server-side routing using
<Router>
Add scripts #
"scripts": {
"start": "wmr",
"build": "wmr build --prerender",
"serve": "wmr serve"
},
Create a public folder containing index.js and index.html #
mkdir public
touch public/index.js public/index.html
index.js #
// public/index.js
import hydrate from 'preact-iso/hydrate'
import Home from './pages/HomePage.js'
export function App() {
return (
<>
<Home />
</>
)
}
hydrate(
<App />
)
hydrate.js
#
hydrate()
is a thin wrapper around Preact's hydrate() method. It performs hydration when the HTML for the current page includes pre-rendered output from prerender()
. It falls back to plain rendering in any other cases and checks if it's running in a browser context before attempting any rendering.
index.html #
<!-- public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>ajcwebdev-wmr</title>
<meta
name="description"
content="what's more random"
/>
<meta
name="viewport"
content="width=device-width,initial-scale=1"
/>
<link
rel="preload"
as="script"
href="/index.js"
crossorigin
/>
</head>
<body>
<script
type="module"
src="/index.js"
>
</script>
</body>
</html>
Create pages directory and HomePage.js #
mkdir public/pages
touch public/pages/HomePage.js
Create Home component #
// public/pages/HomePage.js
export default function Home() {
return (
<>
<h1>ajcwebdev</h1>
</>
)
}
yarn start
Add prerendering #
prerender()
renders a Virtual DOM tree to an HTML string using preact-render-to-string. The difference is that it is asynchronous, and waits for any Promises thrown by components during rendering (Suspense-style) to resolve before returning the HTML.
The Promise returned from prerender()
resolves to an Object with html
and links[]
properties.
html
contains pre-rendered static HTML markuplinks
is an Array of any non-external URL strings found in links on generated page
// public/index.js
export async function prerender(data) {
const {
default: prerender
} = await import('preact-iso/prerender')
return await prerender(
<App {...data} />
)
}