Skip to content

Latest commit

 

History

History
1213 lines (917 loc) · 21.6 KB

slides.md

File metadata and controls

1213 lines (917 loc) · 21.6 KB
theme highlighter lineNumbers drawings css
the-unnamed
shiki
false
persist
unocss

Zurück in die Zukunft mit statischen Webseiten

Ein Blick auf das Astro Framework


Timo Zander (timozander.de)
enterJS 2023


layout: section

Was?

Web-Framework mit Fokus auf Performance und statischen Inhalten
Inhalte
(HTML, Markdown, APIs, ...)


+ UI-Frameworks
Compiler
Statisches HTML, CSS, JS

layout: section

Static Site Generators (SSG)

<style> .slidev-page { background: #303c5f !important; } svg { font-size: 120px; } .distribute { display: flex; padding: 20px 0; justify-content: space-between; align-items: center; } </style>

layout: section

Warum Astro?

  1. Fokus auf Inhalts-lastigen Webseiten
  2. Hohe Performance durch null Client-JavaScript
  3. Interaktivität dank Islands-Architektur
  4. Bring your own Framework
<style> li { @apply my-5; } ol { @apply !list-none } svg { @apply mr-4; } </style>

layout: center

Islands Architektur

Interaktive Elemente werden nachgeladen


Statische Elemente sind sofort verfügbar


layout: center

MPA-Architektur

Single-Page Application (SPA) Multi-Page Application (MPA)
Rendering Client Server
Navigation Client Server
State-Management Client Server
Client-JavaScript viel wenig bis keins
<style> th, td { @apply p-4 text-xl; } th { @apply font-bold; } td { @apply text-center; } </style>

Rendering Modi von Astro

Static Site Generation (SSG)

Astro-Quellcode
Compiler
Webserver
HTML, CSS, JS

Server-side Rendering (SSR)

URL Aufruf
Astro-Runtime
Astro-Quellcode

layout: section

Astro in der Praxis

Ein neues Projekt mit Astro erstellen



Ein Astro-Projekt zum Leben erwecken


$ pnpm create astro@latest

oder online auf astro.new


Starten des Entwicklungs-Servers mit pnpm dev

<style> p { @apply text-2xl pt-5 text-center; } </style>

Ein neues Astro Projekt

├── README.md
├── astro.config.mjs
├── node_modules/
├── package.json
├── pnpm-lock.yaml
├── public/
│   └── ...
├── src/
│   └── ...
└── tsconfig.json


Das src Verzeichnis

├ 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>

layout: center

Anatomie einer Astro Seite

Seite
Layout
Komponente
<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>

Astro Komponenten

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>
<style> .slidev-code { --slidev-code-font-size: 14px; --slidev-code-line-height: 20px; --slidev-code-padding: 12px; } </style>

Props in Astro-Komponenten

 <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>


Frontend-Frameworks nutzen

src/pages/index.astro

---
import MyVueComponent from './components/MyComponent.vue';
---

<div>
  <MyVueComponent />
</div>

Komponenten werden automatisch statisch gerendert


layout: section

Pages und Navigation



Die index.astro Page

---
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>

File-based routing

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
  

layout: section

Islands-Architektur angewandt

Client-seitiges JavaScript mit Astro


script in Komponenten

---
console.log("Hello aus dem Build!")
---

<button>Test</button>

<script>
  console.log("Hello aus dem Browser!")
</script>


Verarbeitung von client-side JavaScript

  1. Importe werden ge-bundled
  2. Das JavaSkript wird zum HTML-Head hinzugefügt
  3. Skripte werden nicht gedoppelt
  4. TypeScript wird unterstützt
<style> li { @apply text-3xl mb-6; } </style>

Skripte "pur" verwenden

---
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


Client-Rendering mit Direktiven steuern

---
// 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 />

layout: section

Dynamische Inhalte und statische Seiten



Content Collections

src/pages/
  ├── newsletter/
  │   ├── new-subcriber.md
  │   ├── featured-links-may-2023.md
  │   └── ...
  ├── blog/
  │   ├── welcome-post.md
  │   ├── what-i-learned-2022-post.md
  │   └── ...
  └── authors/
      ├── zander.json
      └── ...


Einträge typisieren

// 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,
};
<style> .slidev-code { --slidev-code-font-size: 22px; --slidev-code-line-height: 26px; --slidev-code-padding: 8px; } </style>

Inhalte aus Collections nutzen

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>


Daten referenzieren

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
<style> .slidev-code { --slidev-code-font-size: 20px; --slidev-code-line-height: 24px; --slidev-code-padding: 12px; } </style>

layout: center

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>