Developer Blog

Tipps und Tricks für Entwickler und IT-Interessierte

Astro Tutorial – Working with Preact

TL;DR

Code for this tutorial is on Github

Starter Project

Create Starter

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
❯ 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! 🚀
╰─────╯
❯ 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! 🚀 ╰─────╯
❯ 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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
❯ 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...
❯ 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...
❯ 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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"allowJs": true,
"strictNullChecks": true,
"baseUrl": ".",
"lib": ["es2022", "dom", "dom.iterable"],
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "**/node_modules/*", ".vscode", "dist"]
}
{ "extends": "astro/tsconfigs/strict", "compilerOptions": { "allowJs": true, "strictNullChecks": true, "baseUrl": ".", "lib": ["es2022", "dom", "dom.iterable"], "paths": { "@/*": ["src/*"] } }, "exclude": ["node_modules", "**/node_modules/*", ".vscode", "dist"] }
{
  "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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import Layout from '../../layouts/BlogPost.astro';
import Layout from '../../layouts/BlogPost.astro';
import Layout from '../../layouts/BlogPost.astro';

becomes to

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import Layout from '@/layouts/BlogPost.astro';
import Layout from '@/layouts/BlogPost.astro';
import Layout from '@/layouts/BlogPost.astro';
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import Layout from '../styles/global.css';
import Layout from '../styles/global.css';
import Layout from '../styles/global.css';

becomes to

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import Layout from '@/styles/global.css';
import Layout from '@/styles/global.css';
import Layout from '@/styles/global.css';

Install Preact Integration

Add integration for preact

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
❯ 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
❯ 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
❯ 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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npm install preact/signal
npm install preact/signal
npm install preact/signal

Modify src/pages/index.astro

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
---
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>
--- 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>
---
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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
mkdir src/components
mkdir src/components
mkdir src/components

Create file Counter.tsx

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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>
</>
);
}
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> </> ); }
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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
.counter {
display: grid;
font-size: 2em;
grid-template-columns: repeat(3, minmax(0, 1fr));
margin-top: 2em;
place-items: center;
}
.counter { display: grid; font-size: 2em; grid-template-columns: repeat(3, minmax(0, 1fr)); margin-top: 2em; place-items: center; }
.counter {
	display: grid;
	font-size: 2em;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	margin-top: 2em;
	place-items: center;
}

Create Message.tsx

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import type { ComponentChildren } from 'preact';
import './Message.css';
export default function Message({ children }: { children: ComponentChildren }) {
return <div class="message">{children}</div>;
}
import type { ComponentChildren } from 'preact'; import './Message.css'; export default function Message({ children }: { children: ComponentChildren }) { return <div class="message">{children}</div>; }
import type { ComponentChildren } from 'preact';
import './Message.css';

export default function Message({ children }: { children: ComponentChildren }) {
	return <div class="message">{children}</div>;
}

Create Message.css

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
.message {
text-align: center;
}
.message { text-align: center; }
.message {
	text-align: center;
}

Run App

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npm run dev
npm run dev
npm run dev

Astro – Cookbook

Installation

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
❯ npm create astro@latest
❯ npm create astro@latest
❯ npm create astro@latest
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
❯ npm create astro@latest --template with-tailwindcss
❯ npm add -D vite-plugin-static-copy
❯ npm add @shoelace-style/shoelace
❯ npm create astro@latest --template with-tailwindcss ❯ npm add -D vite-plugin-static-copy ❯ npm add @shoelace-style/shoelace
❯ npm create astro@latest --template with-tailwindcss
❯ npm add -D vite-plugin-static-copy
❯ npm add @shoelace-style/shoelace

Command Line / CLI

npm create astro@latest — –template basics
npm installInstalls dependencies
npm run devStarts local dev server at localhost:4321
npm run build Build your production site to ./dist/
npm run previewPreview your build locally, before deploying
npm run astro …Run CLI commands like astro add, astro check
npm run astro — –helpGet help using the Astro CLI

Add packages

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
❯ npx astro add tailwind
❯ npx astro add tailwind
❯ npx astro add tailwind

Frameworks – WebComponents

Shoelace

Lit

https://lit.dev/docs

Animation

Animate Image by MouseOver / Hover

CSS

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
.book {
width: 300px;
height: 480px;
position: relative;
transform-style: preserve-3d;
transform: rotateY(-30deg);
transition: 1s ease;
animation: 1s ease 0s 1 initAnimation;
}
.book:hover {
transform: rotateY(0deg);
}
.book { width: 300px; height: 480px; position: relative; transform-style: preserve-3d; transform: rotateY(-30deg); transition: 1s ease; animation: 1s ease 0s 1 initAnimation; } .book:hover { transform: rotateY(0deg); }
.book {
    width: 300px;
    height: 480px;
    position: relative;
    transform-style: preserve-3d;
    transform: rotateY(-30deg);
    transition: 1s ease;
    animation: 1s ease 0s 1 initAnimation;
}

.book:hover {
    transform: rotateY(0deg);
}

page.astro

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<div class="book">
<Image
src={"/cover-2.jpeg"}
width={300}
height={600}
alt={book.title}
format={"avif"}
/>
</div>
<div class="book"> <Image src={"/cover-2.jpeg"} width={300} height={600} alt={book.title} format={"avif"} /> </div>
<div class="book">
    <Image
        src={"/cover-2.jpeg"}
        width={300}
        height={600}
        alt={book.title}
        format={"avif"}
    />
</div>