examples/tutorials/astro.md
Astro is a modern web framework focused on content-centric websites, which leverages islands architecture and sends zero JavaScript to the client by default. You can see the finished app on GitHub.
You can see a live version of the app on Deno Deploy.
:::info Deploy your own
Want to skip the tutorial and deploy the finished app right now? Click the button below to instantly deploy your own copy of the complete Astro dinosaur app to Deno Deploy. You'll get a live, working application that you can customize and modify as you learn!
:::
Astro provides a CLI tool to quickly scaffold a new Astro project. In your terminal, run the following command to create a new Astro project with Deno.
deno init --npm astro@latest
For this tutorial, we’ll select the “Empty” template so we can start from scratch and we'll install the dependencies.
this will set us up with a basic Astro project structure, including a
package.json file, and a src directory where our application code will live.
We can start the local Astro server with the dev task. In your terminal,
change directory into your new project and run run
deno task dev
This will start the Astro development server, which will watch for changes in
your files and automatically reload the page in your browser. You should see a
message indicating that the server is running on http://localhost:4321.
Upon visiting the output URL in your browser, you should see a very basic Astro welcome page.
Now that we have a basic Astro project set up, let's build out the architecture of our app. We'll create a few directories to organize our code and set up some basic routing. Create the following directories
src/
├── data/
├── lib/
└── pages/
└── index.astro
In the data directory, create a new file called data.json file, which will
contain the hard coded dinosaur data.
Copy and paste
this json file
into the data.json file. (If you were building a real app, you would probably
fetch this data from a database or an external API.)
Next, we’ll create a lib directory to hold our business logic. In this case,
we’ll create a file called dinosaur-service.ts that will contain a function to
fetch the dinosaur data. Create src/lib/dinosaur-service.ts with the following
code:
// Simple utility functions for working with dinosaur data
import dinosaursData from "../data/data.json";
export interface Dinosaur {
name?: string;
description: string;
}
export class DinosaurService {
private static dinosaurs: Dinosaur[] = dinosaursData;
// Get all dinosaurs with names (filter out unnamed ones)
static getNamedDinosaurs(): Dinosaur[] {
return this.dinosaurs.filter((dino) => dino.name);
}
// Create a URL-friendly slug from dinosaur name
static createSlug(name: string): string {
return name
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "");
}
// Get dinosaur by slug
static getDinosaurBySlug(slug: string): Dinosaur | undefined {
return this.dinosaurs.find((dino) => {
if (!dino.name) return false;
return this.createSlug(dino.name) === slug;
});
}
// Get all dinosaurs with their slugs for linking
static getDinosaursWithSlugs() {
return this.getNamedDinosaurs().map((dino) => ({
...dino,
slug: this.createSlug(dino.name!),
}));
}
}
export default DinosaurService;
This file contains a DinosaurService class with methods to get all dinosaurs,
create a URL-friendly slug from a dinosaur name, and get a dinosaur by its slug.
Now we can update our index.astro page to use the DinosaurService to fetch
the dinosaur data and render it as a list of links. Update the
src/pages/index.astro file to look like this:
---
import DinosaurService from '../lib/dinosaur-service';
import '../../styles/index.css';
// Get all dinosaurs with slugs for linking
const dinosaursWithSlugs = DinosaurService.getDinosaursWithSlugs();
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>Dinosaur Directory</title>
</head>
<body>
<h1>🦕 Dinosaur Directory</h1>
<p>Click on any dinosaur name to learn more about it!</p>
<div class="dinosaur-list">
{dinosaursWithSlugs.map((dinosaur) => (
<a href={`/dinosaur/${dinosaur.slug}`} class="dinosaur-link">
{dinosaur.name}
</a>
))}
</div>
</body>
</html>
We import the DinosaurService, then map over the dinosaurs to create links to
individual dinosaur pages.
Next, we’ll create individual pages for each dinosaur. In the src/pages
directory, create a directory called dinosaurs, and inside that directory,
create a file called [slug].astro. This file will be used to render the
individual dinosaur pages:
---
import DinosaurService from '../../lib/dinosaur-service';
import '../../styles/index.css';
export async function getStaticPaths() {
const dinosaursWithSlugs = DinosaurService.getDinosaursWithSlugs();
return dinosaursWithSlugs.map((dinosaur) => ({
params: { slug: dinosaur.slug },
props: { dinosaur }
}));
}
const { dinosaur } = Astro.props;
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>{dinosaur.name} - Dinosaur Directory</title>
<meta name="description" content={dinosaur.description} />
<link rel="stylesheet" href="https://demo-styles.deno.deno.net/styles.css">
</head>
<body class="dinosaur">
<main>
<h1>🦕 {dinosaur.name}</h1>
<div class="info-card">
<p>{dinosaur.description}</p>
</div>
<a href="/" class="btn-secondary">Back to Directory</a>
</main>
</body>
</html>
This file uses the getStaticPaths function to generate static paths for each
dinosaur based on the slugs we created earlier. The Astro.props object will
contain the dinosaur data for the specific slug, which we can then render in the
page.
You can style your app to make it your own in the src/styles/index.css. This
file is imported in both the index.astro and [slug].astro files, so any
styles you add here will apply to both pages.
Astro has a built-in command to build your site for production:
deno run build
This will:
dist directory.You can deploy this app to your favorite cloud provider. We recommend using Deno Deploy for a simple and easy deployment experience. You can deploy your app directly from GitHub, simply create a GitHub repository and push your code there, then connect it to Deno Deploy.
Create a new GitHub repository, then initialize and push your app to GitHub:
git init -b main
git remote add origin https://github.com/<your_github_username>/<your_repo_name>.git
git add .
git commit -am 'initial commit'
git push -u origin main
Once your app is on GitHub, you can deploy to Deno Deploy dashboard.
For a walkthrough of deploying your app, check out the Deno Deploy tutorial.
🦕 Now you can scaffold and develop an Astro app that will run on Deno! You could extend this app by adding more features, such as user authentication, a database, or even a CMS. We can’t wait to see what you build with Astro and Deno!