theme | highlighter | lineNumbers | drawings | css | |
---|---|---|---|---|---|
the-unnamed |
shiki |
false |
|
unocss |
Ein Blick auf das Astro Framework
Timo Zander (timozander.de)
enterJS 2023
Web-Framework mit Fokus auf Performance und statischen Inhalten
Inhalte
(HTML, Markdown, APIs, ...)
+ UI-Frameworks
(HTML, Markdown, APIs, ...)
+ UI-Frameworks
Compiler
Statisches HTML, CSS, JS
- Fokus auf Inhalts-lastigen Webseiten
- Hohe Performance durch null Client-JavaScript
- Interaktivität dank Islands-Architektur
- Bring your own Framework
Single-Page Application (SPA) | Multi-Page Application (MPA) | |
---|---|---|
Rendering | Client | Server |
Navigation | Client | Server |
State-Management | Client | Server |
Client-JavaScript | viel | wenig bis keins |
Ein neues Projekt mit Astro erstellen
$ pnpm create astro@latest
Starten des Entwicklungs-Servers mit pnpm dev
├── README.md
├── astro.config.mjs
├── node_modules/
├── package.json
├── pnpm-lock.yaml
├── public/
│ └── ...
├── src/
│ └── ...
└── tsconfig.json
├ src
├── components
│ └── Card.astro
├── layouts
│ └── Layout.astro
├── pages
│ └── index.astro
└── env.d.ts
Astro-Webseiten bestehen aus Komponenten, Layouts und Seiten.
<style> p { @apply text-2xl; } </style><style> img { border: 2px solid var(--slidev-theme-accents-vulcan); width: 70%; } div.highlight { border: 3px solid var(--slidev-theme-accents-red); position: absolute; width: 606px; height: 100%; left: 0; top: 0; } div.highlight.layout { border-color: var(--slidev-theme-accents-teal); width: 600px; margin-left: 3px; margin-top: 3px; height: calc(100% - 6px) } div.highlight.component { border-color: var(--slidev-theme-accents-yellow); width: 120px; height: 45px; top: 240px; left: 340px; } span.highlight { @apply inline-block w-3 h-3; background-color: var(--slidev-theme-accents-red); } span.highlight.layout { background-color: var(--slidev-theme-accents-teal); } span.highlight.component { background-color: var(--slidev-theme-accents-yellow); } .text { @apply absolute text-2xl; left: 700px; top: 300px; } </style>
src/components/Date.astro
---
const date = new Date();
---
<p>Heute ist {date.toLocaleDateString()}</p>
src/components/LinkButton.astro
---
export type ButtonType = "primary" | "default";
interface Props {
href: string;
type?: ButtonType;
disabled?: boolean;
target?: HTMLAttributeAnchorTarget;
}
const { href, type = "default", disabled = false, target = undefined } = Astro.props;
---
<a
type="button"
href={disabled ? "#" : href}
tabindex={disabled ? "-1" : "0"}
class={`button-${type}`}
target={target}
>
<slot />
</a>
<style>
/* ... */
</style>
<LinkButton
href={email.href}
type="primary"
className={"cta-button"}
target="_blank"
>
Get in touch
</LinkButton>
Props sind typisiert
---
// ...
const {
href, type = "default",
disabled = false, target = undefined
} = Astro.props;
---
<a
type="button"
href={disabled ? "#" : href}
tabindex={disabled ? "-1" : "0"}
class={`button-${type}`}
target={target}
>
<slot />
</a>
src/pages/index.astro
---
import MyVueComponent from './components/MyComponent.vue';
---
<div>
<MyVueComponent />
</div>
Komponenten werden automatisch statisch gerendert
---
import Layout from "../layouts/Layout.astro";
import Date from "../components/Date.astro";
---
<Layout title="Welcome to Astro.">
<main>
<h1>
Welcome to <span class="text-gradient">Astro</span>
</h1>
<Date />
</main>
</Layout>
Der Dateiname bestimmt die URL der Seite
├── pages/
├── index.astro --> /
├── about.md --> /about
├── blog/
│ ├── index.astro --> /blog
│ └── [slug].astro --> /blog/:slug
└── rss.xml.ts --> /rss.xml
Client-seitiges JavaScript mit Astro
---
console.log("Hello aus dem Build!")
---
<button>Test</button>
<script>
console.log("Hello aus dem Browser!")
</script>
- Importe werden ge-bundled
- Das JavaSkript wird zum HTML-Head hinzugefügt
- Skripte werden nicht gedoppelt
- TypeScript wird unterstützt
---
console.log("Hello aus dem Build!")
---
<button>Test</button>
<script is:inline>
console.log("Hello aus dem Browser!")
</script>
is:inline
Skript-Tags werden nicht vom Build verarbeitet
---
// Wichtig: keine .astro Komponente
import LongTask from "../components/LongTask.vue";
---
<LongTask client:load />
<LongTask client:idle />
<p class="spacer">Scroll down</p>
<LongTask client:visible />
─ src/pages/
├── newsletter/
│ ├── new-subcriber.md
│ ├── featured-links-may-2023.md
│ └── ...
├── blog/
│ ├── welcome-post.md
│ ├── what-i-learned-2022-post.md
│ └── ...
└── authors/
├── zander.json
└── ...
// src/content/config.ts
import { z, defineCollection } from 'astro:content';
const blogCollection = defineCollection({
type: 'content', // oder 'data'
schema: z.object({
title: z.string(),
tags: z.array(z.string()),
image: z.string().optional(),
}),
});
export const collections = {
blog: blogCollection,
};
import { getCollection } from 'astro:content';
const blogPosts = await getCollection('blog');
<section>
<h2>Blog-Einträge</h2>
{
blogPosts.map((post) => (
<a href={"blog/" + post.slug}>{post.data.title}</a>
))
}
</section>
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
author: reference('authors'),
relatedPosts: z.array(reference('blog')),
})
});
const authors = defineCollection({
type: 'data',
schema: z.object({
name: z.string(),
})
});
classDiagram
class BlogPost
BlogPost : + title
class Author
Author : + name
BlogPost "*" --> "1" Author
Jedem Anfang wohnt ein Zauber inne.
- Loslegen unter astro.new
- Nutzt Astro für euren Blog, ein Portfolio, ...
- ...und nicht für interaktive Dashboards und co
- Lernt das Framework zu lieben (oder zu hassen!)
Alle Unterlagen findet Ihr auf timozander.de
<style> blockquote { @apply !p-6; } li { @apply text-2xl mb-3; } </style>