Upgrade to Astro 5

This commit is contained in:
Mikkel Svartveit 2024-12-22 20:45:50 +01:00
parent ff787453ab
commit c5a44e7fab
16 changed files with 2578 additions and 2018 deletions

View file

@ -7,7 +7,7 @@ import cloudflare from "@astrojs/cloudflare";
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
integrations: [tailwind(), svelte(), mdx()], integrations: [tailwind(), svelte(), mdx()],
output: "hybrid", output: "static",
adapter: cloudflare({ adapter: cloudflare({
imageService: "compile", imageService: "compile",
platformProxy: { platformProxy: {
@ -19,8 +19,5 @@ export default defineConfig({
external: ["node:async_hooks"], external: ["node:async_hooks"],
}, },
}, },
experimental: {
actions: true,
},
site: "https://mikkelsvartveit.com", site: "https://mikkelsvartveit.com",
}); });

View file

@ -10,20 +10,20 @@
"astro": "astro" "astro": "astro"
}, },
"dependencies": { "dependencies": {
"@astrojs/cloudflare": "^10.4.2", "@astrojs/cloudflare": "^12.1.0",
"@astrojs/mdx": "^3.1.3", "@astrojs/mdx": "^4.0.3",
"@astrojs/svelte": "^5.7.0", "@astrojs/svelte": "^7.0.2",
"@astrojs/tailwind": "^5.1.0", "@astrojs/tailwind": "^5.1.4",
"astro": "^4.12.2", "@tailwindcss/typography": "^0.5.15",
"astro": "^5.1.1",
"sharp": "^0.32.6", "sharp": "^0.32.6",
"svelte": "^4.2.18", "svelte": "^5.15.0",
"tailwindcss": "^3.4.7" "tailwindcss": "^3.4.17"
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/typography": "^0.5.13",
"prettier": "3.0.3", "prettier": "3.0.3",
"prettier-plugin-astro": "^0.12.3", "prettier-plugin-astro": "^0.12.3",
"prettier-plugin-svelte": "^3.2.6", "prettier-plugin-svelte": "^3.3.2",
"prettier-plugin-tailwindcss": "^0.5.14" "prettier-plugin-tailwindcss": "^0.5.14"
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -1,18 +1,9 @@
import { defineAction, z, getApiContext } from "astro:actions"; import { defineAction } from "astro:actions";
export const server = { export const server = {
registerView: defineAction({ dummy: defineAction({
input: z.object({ articleSlug: z.string() }), handler: async () => {
handler: async ({ articleSlug }) => { return 0;
const context = getApiContext();
// @ts-ignore
const { ViewCountKV } = context.locals.runtime.env;
let viewCount = (await ViewCountKV.get(articleSlug)) || 0;
await ViewCountKV.put(articleSlug, ++viewCount);
return viewCount;
}, },
}), }),
}; };

View file

@ -0,0 +1,29 @@
---
export const prerender = false;
const { articleSlug } = Astro.props;
const { ViewCountKV } = Astro.locals.runtime.env;
let counter = await ViewCountKV.get(articleSlug);
await ViewCountKV.put(articleSlug, ++counter);
---
<span class="inline-flex items-center space-x-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" height="12">
<!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
<style>
svg {
fill: currentColor;
}
</style>
<path
d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM144 256a144 144 0 1 1 288 0 144 144 0 1 1 -288 0zm144-64c0 35.3-28.7 64-64 64c-7.1 0-13.9-1.2-20.3-3.3c-5.5-1.8-11.9 1.6-11.7 7.4c.3 6.9 1.3 13.8 3.2 20.7c13.7 51.2 66.4 81.6 117.6 67.9s81.6-66.4 67.9-117.6c-11.1-41.5-47.8-69.4-88.6-71.1c-5.8-.2-9.2 6.1-7.4 11.7c2.1 6.4 3.3 13.2 3.3 20.3z"
>
</path>
</svg>
<span>{counter}</span>
</span>

View file

@ -1,38 +0,0 @@
<script lang="ts">
import { actions } from "astro:actions";
import { onMount } from "svelte";
import { expoIn } from "svelte/easing";
import { fade } from "svelte/transition";
export let articleSlug: string;
let counter: number | null = null;
onMount(async () => {
const readCount = await actions.registerView({ articleSlug });
counter = readCount;
});
</script>
{#if counter !== null}
<span
class="inline-flex items-center space-x-1"
transition:fade={{ duration: 200, easing: expoIn }}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" height="12">
<!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
<style>
svg {
fill: currentColor;
}
</style>
<path
d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM144 256a144 144 0 1 1 288 0 144 144 0 1 1 -288 0zm144-64c0 35.3-28.7 64-64 64c-7.1 0-13.9-1.2-20.3-3.3c-5.5-1.8-11.9 1.6-11.7 7.4c.3 6.9 1.3 13.8 3.2 20.7c13.7 51.2 66.4 81.6 117.6 67.9s81.6-66.4 67.9-117.6c-11.1-41.5-47.8-69.4-88.6-71.1c-5.8-.2-9.2 6.1-7.4 11.7c2.1 6.4 3.3 13.2 3.3 20.3z"
/>
</svg>
<span>{counter}</span>
</span>
{/if}

28
src/content.config.ts Normal file
View file

@ -0,0 +1,28 @@
import { defineCollection, z } from "astro:content";
import { glob } from "astro/loaders";
const blog = defineCollection({
loader: glob({ pattern: "*.md*", base: "./src/content/blog" }),
schema: ({ image }) =>
z.object({
intro: z.string(),
image: image(),
date: z.date(),
}),
});
const programming = defineCollection({
loader: glob({ pattern: "*.md*", base: "./src/content/programming" }),
schema: ({ image }) =>
z.object({
title: z.string(),
description: z.string(),
image: image(),
date: z.date(),
technologies: z.array(z.string()),
website: z.string().optional(),
repository: z.string().optional(),
}),
});
export const collections = { blog, programming };

View file

@ -1,30 +0,0 @@
import { z, defineCollection } from "astro:content";
const programmingCollection = defineCollection({
type: "content",
schema: ({ image }) =>
z.object({
title: z.string(),
description: z.string(),
image: image(),
technologies: z.array(z.string()),
website: z.string().url(),
repository: z.string().url().optional(),
date: z.date(),
}),
});
const blogCollection = defineCollection({
type: "content",
schema: ({ image }) =>
z.object({
image: image(),
intro: z.string(),
date: z.date(),
}),
});
export const collections = {
programming: programmingCollection,
blog: blogCollection,
};

12
src/env.d.ts vendored
View file

@ -1,3 +1,13 @@
/// <reference path="../.astro/actions.d.ts" />
/// <reference path="../.astro/types.d.ts" /> /// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" /> /// <reference types="astro/client" />
type KVNamespace = import("@cloudflare/workers-types").KVNamespace;
type ENV = {
ViewCountKV: KVNamespace;
};
// use a default runtime configuration (advanced mode).
type Runtime = import("@astrojs/cloudflare").Runtime<ENV>;
declare namespace App {
interface Locals extends Runtime {}
}

View file

@ -1,26 +1,26 @@
--- ---
import { getCollection, render } from "astro:content";
import ContainerLayout from "@layouts/ContainerLayout.astro"; import ContainerLayout from "@layouts/ContainerLayout.astro";
import BaseLayout from "@layouts/BaseLayout.astro"; import BaseLayout from "@layouts/BaseLayout.astro";
import TextContentLayout from "@layouts/TextContentLayout.astro"; import TextContentLayout from "@layouts/TextContentLayout.astro";
import type { GetStaticPaths } from "astro";
import { getCollection } from "astro:content";
import ProseLayout from "@layouts/ProseLayout.astro"; import ProseLayout from "@layouts/ProseLayout.astro";
import ArticleViewCounter from "@components/ArticleViewCounter.svelte"; import ArticleViewCounter from "@components/ArticleViewCounter.astro";
import HeadContent from "@components/HeadContent.astro"; import HeadContent from "@components/HeadContent.astro";
import type { GetStaticPaths } from "astro";
export const getStaticPaths = (async () => { export const getStaticPaths = (async () => {
const blogCollection = await getCollection("blog"); const blogCollection = await getCollection("blog");
return blogCollection.map((entry) => ({ return blogCollection.map((entry) => ({
params: { params: {
article: entry.slug, article: entry.id,
}, },
props: { entry }, props: { entry },
})); }));
}) satisfies GetStaticPaths; }) satisfies GetStaticPaths;
const project = Astro.props.entry; const blogPost = Astro.props.entry;
const { Content, headings } = await project.render(); const { Content, headings } = await render(blogPost);
const { date, intro, image } = project.data; const { date, intro, image } = blogPost.data;
const title = headings[0].text; const title = headings[0].text;
--- ---
@ -42,7 +42,7 @@ const title = headings[0].text;
<span class="px-2">⋅</span> <span class="px-2">⋅</span>
<ArticleViewCounter articleSlug={project.slug} client:only="svelte" /> <ArticleViewCounter server:defer articleSlug={blogPost.id} />
</p> </p>
<ProseLayout> <ProseLayout>

View file

@ -1,10 +1,10 @@
--- ---
import { getCollection, render } from "astro:content";
import { Image } from "astro:assets"; import { Image } from "astro:assets";
import Paragraph from "@components/Paragraph.astro"; import Paragraph from "@components/Paragraph.astro";
import ContainerLayout from "@layouts/ContainerLayout.astro"; import ContainerLayout from "@layouts/ContainerLayout.astro";
import BaseLayout from "@layouts/BaseLayout.astro"; import BaseLayout from "@layouts/BaseLayout.astro";
import TextContentLayout from "@layouts/TextContentLayout.astro"; import TextContentLayout from "@layouts/TextContentLayout.astro";
import { getCollection } from "astro:content";
import Head from "@components/HeadContent.astro"; import Head from "@components/HeadContent.astro";
const articles = await getCollection("blog"); const articles = await getCollection("blog");
@ -31,13 +31,13 @@ const articles = await getCollection("blog");
articles articles
.sort((p2, p1) => p1.data.date.getTime() - p2.data.date.getTime()) .sort((p2, p1) => p1.data.date.getTime() - p2.data.date.getTime())
.map(async (article) => { .map(async (article) => {
const { slug, data } = article; const { id, data } = article;
const { image, intro } = data; const { image, intro } = data;
const { headings } = await article.render(); const { headings } = await render(article);
const title = headings[0].text; const title = headings[0].text;
return ( return (
<a <a
href={`/articles/${slug}`} href={`/articles/${id}`}
class="group mx-auto my-8 grid max-w-xs grid-cols-1 overflow-hidden rounded-lg bg-white shadow duration-100 hover:translate-x-1 hover:shadow-md sm:max-w-none sm:grid-cols-3" class="group mx-auto my-8 grid max-w-xs grid-cols-1 overflow-hidden rounded-lg bg-white shadow duration-100 hover:translate-x-1 hover:shadow-md sm:max-w-none sm:grid-cols-3"
> >
<Image <Image

View file

@ -1,5 +1,5 @@
--- ---
import { getCollection } from "astro:content"; import { getCollection, render } from "astro:content";
import { Image } from "astro:assets"; import { Image } from "astro:assets";
import BaseLayout from "../layouts/BaseLayout.astro"; import BaseLayout from "../layouts/BaseLayout.astro";
import Link from "@components/Link.astro"; import Link from "@components/Link.astro";
@ -11,8 +11,8 @@ const articles = await getCollection("blog");
const latestArticle = articles.sort( const latestArticle = articles.sort(
(p2, p1) => p1.data.date.getTime() - p2.data.date.getTime() (p2, p1) => p1.data.date.getTime() - p2.data.date.getTime()
)[0]; )[0];
const latestArticleSlug = latestArticle.slug; const latestArticleSlug = latestArticle.id;
const latestArticleTitle = (await latestArticle.render()).headings[0].text; const latestArticleTitle = (await render(latestArticle)).headings[0].text;
const latestArticleImage = latestArticle.data.image; const latestArticleImage = latestArticle.data.image;
--- ---

View file

@ -2,10 +2,9 @@
import type { GetStaticPaths } from "astro"; import type { GetStaticPaths } from "astro";
import { Image } from "astro:assets"; import { Image } from "astro:assets";
import { getFileNameFromPath } from "./index.astro"; import { getFileNameFromPath } from "./index.astro";
import RootLayout from "@layouts/RootLayout.astro";
import HeadContent from "@components/HeadContent.astro"; import HeadContent from "@components/HeadContent.astro";
export const getStaticPaths = (async () => { export const getStaticPaths: GetStaticPaths = (async () => {
const photos = await Astro.glob("../../assets/photos/*"); const photos = await Astro.glob("../../assets/photos/*");
return photos.map((photo: any) => ({ return photos.map((photo: any) => ({
@ -18,7 +17,7 @@ export const getStaticPaths = (async () => {
})); }));
}) satisfies GetStaticPaths; }) satisfies GetStaticPaths;
const { photo } = Astro.props; const photo = Astro.props.photo as any;
--- ---
<html lang="en"> <html lang="en">

View file

@ -6,19 +6,20 @@ import type { GetStaticPaths } from "astro";
import { getCollection } from "astro:content"; import { getCollection } from "astro:content";
import ProseLayout from "@layouts/ProseLayout.astro"; import ProseLayout from "@layouts/ProseLayout.astro";
import HeadContent from "@components/HeadContent.astro"; import HeadContent from "@components/HeadContent.astro";
import { render } from "astro:content";
export const getStaticPaths = (async () => { export const getStaticPaths = (async () => {
const programmingEntries = await getCollection("programming"); const programmingEntries = await getCollection("programming");
return programmingEntries.map((entry) => ({ return programmingEntries.map((entry) => ({
params: { params: {
project: entry.slug, project: entry.id,
}, },
props: { entry }, props: { entry },
})); }));
}) satisfies GetStaticPaths; }) satisfies GetStaticPaths;
const project = Astro.props.entry; const project = Astro.props.entry;
const { Content } = await project.render(); const { Content } = await render(project);
const { title, description, image, date, technologies, website, repository } = const { title, description, image, date, technologies, website, repository } =
project.data; project.data;
--- ---

View file

@ -33,9 +33,9 @@ const projects = await getCollection("programming");
{ {
projects projects
.sort((p2, p1) => p1.data.date.getTime() - p2.data.date.getTime()) .sort((p2, p1) => p1.data.date.getTime() - p2.data.date.getTime())
.map(({ data, slug }) => ( .map(({ data, id }) => (
<a <a
href={`/programming/${slug}`} href={`/programming/${id}`}
class="mx-auto overflow-hidden rounded-lg bg-white pb-8 shadow-md duration-100 hover:-translate-y-1 hover:shadow-lg" class="mx-auto overflow-hidden rounded-lg bg-white pb-8 shadow-md duration-100 hover:-translate-y-1 hover:shadow-lg"
> >
<Image <Image

View file

@ -1,5 +1,7 @@
{ {
"extends": "astro/tsconfigs/strict", "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"],
"compilerOptions": { "compilerOptions": {
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {