Astro Best Practices
This lesson is a preview from our interactive course
Astro ships many optimizations out of the box to speed up our site and maximize the results of our efforts. However, there are some best practices we need to keep in mind that can elevate the quality of our project even further. In this lesson, we'll take a look at different practices that can ensure you get the maximum from your Astro project.
Use Layouts for Consistency#
This point not only applies to Astro projects but to web applications in general. Whether you're building a React application, using Svelte, or Astro, make sure you always have a Layout
component that ensures a consistent look and feel across your pages. Even if you have multiple types of pages, the same layout applies at least to your header, footer, and main content.
Notice how the header, footer, and width of the content match across different pages in the above example, using a single Layout
component. Astro also supports the use of slots, meaning we can dynamically build multiple layouts from the same component. Take the following as an example where we use two different named slots (slots with a name
attribute):
---
import SEO from '@components/SEO.astro'
import Header from '@components/Header.astro'
import Footer from '@components/Footer.astro'
import '../styles/global.css'
const { seo } = Astro.props
const hasLeftSidebar = Astro.slots.has('left-sidebar')
const hasRightSidebar = Astro.slots.has('right-sidebar')
---
<!DOCTYPE html>
<html lang="en">
<head>
<SEO {...seo} />
</head>
<body>
<Header />
{hasLeftSidebar && (
<aside>
<slot name="left-sidebar" />
</aside>
)}
<main>
<slot />
</main>
{hasRightSidebar && (
<aside>
<slot name="right-sidebar" />
</aside>
)}
<Footer />
</body>
</html>
We can use the global Astro.slots.has
method to check if there's a named slot passed to the Layout
component, either called left-sidebar
or right-sidebar
. We can then conditionally render the slots with some wrapper elements. This makes it possible to further customize our layout while still sharing core elements. Using this component, it's possible to create four different layouts: one without sidebars, one with a left/right sidebar, and one with multiple sidebars.
Use SEO Component#
Creating an SEO
component referenced through the Layout
is another best practice that can improve overall SEO. By using it with our layout and defining many default values, we can ensure optimal technical SEO for all pages without having to redefine important tags for all pages.
---
import config from '@config'
const services = config.services.services
const websiteSchema = `
{
"@context": "https://schema.org",
"@type": "WebSite",
"url": "https://webtips.dev",
"name": "${config.title}",
"description": "${config.description}"
}
`
const localBusinessSchema = `
{
"@context": "https://schema.org",
"@type": "HousePainter",
"name": "John Doe",
"legalName": "John Doe Legal Name",
"description": "${config.description}",
"url": "${config.url}",
"logo": "${config.url + config.logo}",
"telephone": "${config.contact.tel}",
"email": "${config.contact.email}",
"address": {
"@type": "PostalAddress",
"addressLocality": "City",
"addressCountry": "Country"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "5",
"reviewCount": "6"
},
"openingHours": [
"Mo-Fr 07:00-17:00"
],
"hasOfferCatalog": {
"@type": "OfferCatalog",
"name": "Offer Title",
"itemListElement": [
${services.map(service => `
{
"@type": "Offer",
"itemOffered": {
"@type": "Service",
"name": "${service.text.replace(/"/g, "'")}"
}
}
`)}
]
}
}
`
---
<title>{config.title}</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="theme-color" content="#1D1A1D" />
<meta name="description" content={config.description} />
<meta name="author" content={config.name} />
<meta name="keywords" content={config.keywords} />
<meta property="og:title" content={config.title} />
<meta property="og:type" content="website" />
<meta property="og:url" content={config.url} />
<meta property="og:image" content={config.url + config.logo} />
<meta property="og:description" content={config.description} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={config.title} />
<meta name="twitter:description" content={config.description} />
<meta name="twitter:image:src" content={config.url + config.logo} />
<link rel="canonical" href={config.url} />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="manifest" href="/manifest.webmanifest" />
<script type="application/ld+json" set:html={websiteSchema} />
<script type="application/ld+json" set:html={localBusinessSchema} />
In this project, we used a configuration file to customize our SEO needs. However, for projects with multiple pages, there's also another approach. We can accept an seo
prop inside this component to make it customizable from the outside:
const seo = {
title: post.data.title,
description: post.data.excerpt.substring(0, 150) + '...',
publishDate: post.data.publishDate,
updatedDate: post.data.updatedDate,
image: post.data.heroImage,
}
---
<Layout seo={seo}>
...
</Layout>
---
import SEO from '@components/SEO.astro'
const { seo } = Astro.props
---
<!DOCTYPE html>
<html lang="en">
<head>
<SEO {...seo} />
</head>
...
Use class:list over classNames#
Astro uses a JSX-like syntax; however, it's not JSX. In JSX, we usually use a third-party utility package called classNames
to create conditional classes:
import classNames from 'classnames';
<h1 className={classNames([highlighted && 'highlighted'])}>
{welcome}
</h1>
However, Astro comes with its built-in way of handling conditional classes, making the classNames
package obsolete. When working with Astro components, always use class:list
over classNames
to simplify your code and avoid using external packages unnecessarily, just like we did for the Button
or Rating
components:
<!-- Button.astro -->
<a {...rest} class:list={[theme]}>
<!-- Rating.astro -->
<div class:list={['rating-container', theme, useMargin && 'margin']}>
Optimize Your Builds#
Lastly, make sure you optimize your builds to ensure your bundled assets are optimized for the end user. This includes:
- Serializing and hashing your sitemap if necessary.
- Adding a
robots.txt
file to inform crawlers how to crawl your site. - Creating a post-build script to remove unwanted files or perform further optimizations.
Make sure you also minify your images to prevent large network requests. Astro compresses your HTML, JavaScript, and CSS files by default to reduce the size of your assets. With these best practices in mind, you can ensure optimal performance for your site.
Rocket Launch Your Career
Speed up your learning progress with our mentorship program. Join as a mentee to unlock the full potential of Webtips and get a personalized learning experience by experts to master the following frontend technologies: