Astro Best Practices

Astro Best Practices

Learn how you can get the most out of Astro projects
Ferenc Almasi β€’ 2024 January 29 β€’ Read time 7 min read
Learn how you can get the most out of Astro to improve your project's structure and SEO score.
  • twitter
  • facebook

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.

undefined
Different pages with the same layout

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

Copied to clipboard! Playground
---
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>
Layout.astro
Using slots for dynamic layouts

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.

Copied to clipboard! Playground
---
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} />
SEO.astro
The SEO component used for this project

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:

Copied to clipboard! Playground
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>
index.astro
Customizing SEO for a page
Copied to clipboard! Playground
---
import SEO from '@components/SEO.astro'

const { seo } = Astro.props
---

<!DOCTYPE html>
<html lang="en">
    <head>
        <SEO {...seo} />
    </head>
    ...
Layout.astro
Inside the Layout component, we can pass along the seo prop
Looking to improve your skills? Master Astro + SEO from start to finish.
info Remove ads

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:

Copied to clipboard! Playground
import classNames from 'classnames';

<h1 className={classNames([highlighted && 'highlighted'])}>
    {welcome}
</h1>
Using classNames in JSX

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:

Copied to clipboard! Playground
<!-- Button.astro -->
<a {...rest} class:list={[theme]}>

<!-- Rating.astro -->
<div class:list={['rating-container', theme, useMargin && 'margin']}>
Use class:list in Astro

Optimize Your Builds

Lastly, make sure you optimize your builds to ensure your bundled assets are optimized for the end user. This includes:

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.

  • twitter
  • facebook
Did you find this page helpful?
πŸ“š More Webtips
Mentoring

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:

Courses

Recommended

This site uses cookies We use cookies to understand visitors and create a better experience for you. By clicking on "Accept", you accept its use. To find out more, please see our privacy policy.