Astro Tutorial – Working with Preact
TL;DR
Code for this tutorial is on Github
Starter Project
Create Starter
❯ npm create astro@latest "Tutorial - Working with Preact" .../21.6.2/pnpm/store/v3/tmp/dlx-99714 | +39 ++++ .../21.6.2/pnpm/store/v3/tmp/dlx-99714 | Progress: resolved 39, reused 39, downloaded 0, added 39, done astro Launch sequence initiated. ◼ dir Using Tutorial - Working with Preact as project directory tmpl How would you like to start your new project? Empty ts Do you plan to write TypeScript? Yes use How strict should TypeScript be? Strict deps Install dependencies? Yes git Initialize a new git repository? Yes ✔ Project initialized! ■ Template copied ■ TypeScript customized ■ Dependencies installed ■ Git initialized next Liftoff confirmed. Explore your project! Enter your project directory using cd "./Tutorial - Working with Preact" Run pnpm dev to start the dev server. CTRL+C to stop. Add frameworks like react or tailwind using astro add. Stuck? Join us at https://astro.build/chat ╭─────╮ Houston: │ ◠ ◡ ◠ Good luck out there, astronaut! 🚀 ╰─────╯
Run Starter
❯ cd "Tutorial - Working with Preact" ❯ npm run dev > tutorial---working-with-preact@0.0.1 dev /Users/Shared/CLOUD/Programmier-Workshops/Kurse/Astro/Einsteiger/Tutorial - Working with Preact > astro dev astro v4.5.13 ready in 156 ms ┃ Local http://localhost:4321/ ┃ Network use --host to expose 14:34:39 watching for file changes...
Modify Project Structur and add helper code
tsconfig.json
{ "extends": "astro/tsconfigs/strict", "compilerOptions": { "allowJs": true, "strictNullChecks": true, "baseUrl": ".", "lib": ["es2022", "dom", "dom.iterable"], "paths": { "@/*": ["src/*"] } }, "exclude": ["node_modules", "**/node_modules/*", ".vscode", "dist"] }
Replace relative path with reference to path alias in every page
import Layout from '../../layouts/BlogPost.astro';
becomes to
import Layout from '@/layouts/BlogPost.astro';
import Layout from '../styles/global.css';
becomes to
import Layout from '@/styles/global.css';
Install Preact Integration
Add integration for preact
❯ npx astro add preact ✔ Resolving packages... Astro will run the following command: If you skip this step, you can always run it yourself later ╭──────────────────────────────────────────────────╮ │ pnpm add @astrojs/preact@^3.1.2 preact@^10.20.1 │ ╰──────────────────────────────────────────────────╯ ✔ Continue? … yes ✔ Installing dependencies... Astro will make the following changes to your config file: ╭ astro.config.mjs ─────────────────────────────╮ │ import { defineConfig } from 'astro/config'; │ │ │ │ import preact from "@astrojs/preact"; │ │ │ │ // https://astro.build/config │ │ export default defineConfig({ │ │ integrations: [preact()] │ │ }); │ ╰───────────────────────────────────────────────╯ ✔ Continue? … yes success Added the following integration to your project: - @astrojs/preact Astro will make the following changes to your tsconfig.json: ╭ tsconfig.json ───────────────────────────────────────────────────────╮ │ { │ │ "extends": "astro/tsconfigs/strict", │ │ "compilerOptions": { │ │ "allowJs": true, │ │ "strictNullChecks": true, │ │ "baseUrl": ".", │ │ "lib": [ │ │ "es2022", │ │ "dom", │ │ "dom.iterable" │ │ ], │ │ "paths": { │ │ "@/*": [ │ │ "src/*" │ │ ] │ │ }, │ │ "jsx": "react-jsx", │ │ "jsxImportSource": "preact" │ │ }, │ │ "exclude": [ │ │ "node_modules", │ │ "**/node_modules/*", │ │ ".vscode", │ │ "dist" │ │ ] │ │ } │ ╰──────────────────────────────────────────────────────────────────────╯ ✔ Continue? … yes success Successfully updated TypeScript settings
Install preact/signale
npm install preact/signal
Modify src/pages/index.astro
--- import Counter from "@/components/Counter"; import { signal } from "@preact/signals"; const count = signal(0); --- <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <meta name="generator" content={Astro.generator} /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <style> html, body { font-family: system-ui; margin: 0; } body { padding: 2rem; } h1 { text-align: center; } </style> </head> <body> <main> <h1 style="halign:center">Working with Astro and Preact</h1> <Counter count={count} client:visible><h3>Hello, Preact 1!</h3></Counter> <Counter count={count} client:visible><h3>Hello, Preact 2!</h3></Counter> </main> </body> </html>
Create Component Counter
Create folder src/components
mkdir src/components
Create file Counter.tsx
import type { ComponentChildren } from "preact"; import type { Signal } from "@preact/signals"; import { lazy, Suspense } from "preact/compat"; import "./Counter.css"; const Message = lazy(async () => import("./Message")); const Fallback = () => <p>Loading...</p>; type Props = { children: ComponentChildren; count: Signal<number>; }; export default function Counter({ children, count }: Props) { const add = () => count.value++; const subtract = () => count.value--; return ( <> <div class="counter"> <button onClick={subtract}>-</button> <pre>{count}</pre> <button onClick={add}>+</button> </div> <Suspense fallback={Fallback}> <Message>{children}</Message> </Suspense> </> ); }
Create file Counter.css
.counter { display: grid; font-size: 2em; grid-template-columns: repeat(3, minmax(0, 1fr)); margin-top: 2em; place-items: center; }
Create Message.tsx
import type { ComponentChildren } from 'preact'; import './Message.css'; export default function Message({ children }: { children: ComponentChildren }) { return <div class="message">{children}</div>; }
Create Message.css
.message { text-align: center; }
Run App
npm run dev