Is Astro really that fast compared to Nuxt 3

Foreword:

Hello everyone, lately, I see / read / hear a lot about astro, about how fast, productive it is. Therefore, I decided to poke Astro and at the same time check how fast it is – I wrote a primitive blog on it with 600 cards and compared it in performance with Nuxt 3 SSG.

Performance was measured using page speed.

I want to say right away that I do not claim the correctness of these tests – I was just wondering how things are in some cases + it was interesting to poke Astro.

Test 1 (Fully static site)

Wrote a card component in Nuxt 3 and Astro using tailwind and made a page with 600 cards (the usual number of blog posts in a couple of years).

components/blog/Card.vue

<script lang="ts" setup></script>

<template>
  <div class="flex flex-col gap-6 bg-[#c6c6c6] rounded-[16px] p-8">
    <img alt="test image" height="200" src="https://habr.com/ru/articles/748366/assets/images/test-image.png" width="400" />
    <h2 class="font-bold text-[20px] leading-6">Article Title</h2>
    <p class="font-medium text-base leading-5">Article Description Lorem Ipsum is simply dummy text of the printing and
      typesetting industry. Lorem Ipsum has
      been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and
      scrambled it to make a type specimen book.</p>
  </div>
</template>

<style lang="scss" scoped></style>

components/blog/Card.astro

---
import image from '~/assets/images/test-image.png';
---
<a class="flex flex-col gap-6 bg-[#c6c6c6] rounded-[16px] p-8" href="https://google.com">
    <img alt="test image" height="200" src={image.src} width="400" />
    <h2 class="font-bold text-[20px] leading-6">Article Title</h2>
    <p class="font-medium text-base leading-5">Article Description Lorem Ipsum is simply dummy text of the printing and
      typesetting industry. Lorem Ipsum has
      been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and
      scrambled it to make a type specimen book.</p>
</a>

I uploaded all this to the hosting and got the following results:

Astro

Astro

Nuxt 3

Nuxt 3

We get a fairly predictable result of Astro – 97% -100%, Nuxt 3 – 92% -96%. An understandable result, since Astro generated just pure html (in fact, what is written on their main page full speed – zero js), it is not surprising that it has a result in the region of a hundred, there is essentially nothing to reduce performance. Nuxt is still loading the bundle with the framework itself, so the results are below.

Test 2 (Added 1 js library)

In this test, I decided to add the library @sentry/browser is a fairly well-known library for monitoring errors in your application. Seems like a pretty likely library on any site to me.

I connected it like this on the page:

import * as Sentry from "@sentry/browser";

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  integrations: [new Sentry.BrowserTracing()],
  tracesSampleRate: 1.0,
});

Again uploaded it to the hosting and got the following results:

Astro

Astro

Nuxt 3

Nuxt 3

We see the same result, Astro loads the same html file + js libraries and has excellent performance of 93% -97% on average. Nuxt 3 also loads its bundle + html + js libraries, but since there is more js code, it has 84%-88% on average.

Test 3 (I made a primitive js slider inside the card)

Here I decided to add js code and see how Astro will show itself this time, there will be 2 Astro tests, first I wrote js code using the syntax web componentsand then decided to use Astro with Vue component Card (In fact, I just connected the Vue component to Astro), well, I just wrote the code in Nuxt 3.

components/blog/Card.vue

<script lang="ts" setup>
import { ref } from '#imports';

const selectedSlide = ref<number>(1);

const handlePrevButtonClick = () => {
  selectedSlide.value = selectedSlide.value === 1 ? 5 : selectedSlide.value - 1;
};

const handleNextButtonClick = () => {
  selectedSlide.value = selectedSlide.value === 5 ? 1 : selectedSlide.value + 1;
};
</script>

<template>
  <a class="flex flex-col gap-6 bg-[#c6c6c6] rounded-[16px] p-8">
    <div class="relative">
      <button class="absolute left-0 top-[50%] translate-y-[-50%] p-4 bg-[#7a75e2] rounded-[8px]"
              @click="handlePrevButtonClick"
      >Prev
      </button>
      <span class="absolute top-2 left-[50%] translate-x-[-50%]">{{ selectedSlide }}</span>
      <img v-for="index in 5" :key="index" v-show="selectedSlide === index" alt="test image" height="200"
           src="https://habr.com/ru/articles/748366/assets/images/test-image.png"
           width="400"
      />
      <button class="absolute right-0 top-[50%] translate-y-[-50%] p-4 bg-[#7a75e2] rounded-[8px]"
              @click="handleNextButtonClick"
      >Next
      </button>
    </div>
    <h2 class="font-bold text-[20px] leading-6">Article Title</h2>
    <p class="font-medium text-base leading-5">Article Description Lorem Ipsum is simply dummy text of the printing and
      typesetting industry. Lorem Ipsum has
      been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and
      scrambled it to make a type specimen book.</p>
  </a>
</template>

<style lang="scss" scoped></style>

components/blog/Card.astro

---
import image from '~/assets/images/test-image.png';
---
<astro-card>
  <a class="flex flex-col gap-6 bg-[#c6c6c6] rounded-[16px] p-8">
      <div class="relative">
          <button class="prev-button absolute left-0 top-[50%] translate-y-[-50%] p-4 bg-[#7a75e2] rounded-[8px]">Prev</button>
          <span class="selected-slide absolute top-2 left-[50%] translate-x-[-50%]"></span>
          {
          [1, 2, 3, 4, 5].map((index) =>
          (<img alt="test image" height="200"
             src={image.src}
             width="400"
             class:list={[{ hidden: index !== 1 }, `slide-${index}`]}
          />))
          }
          <button class="next-button absolute right-0 top-[50%] translate-y-[-50%] p-4 bg-[#7a75e2] rounded-[8px]">Next</button>
      </div>
      <h2 class="font-bold text-[20px] leading-6">Article Title</h2>
      <p class="font-medium text-base leading-5">Article Description Lorem Ipsum is simply dummy text of the printing and
        typesetting industry. Lorem Ipsum has
        been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and
        scrambled it to make a type specimen book.</p>
  </a>
</astro-card>

<script>
class AstroCard extends HTMLElement {
  constructor() {
    super();
    let selectedSlide = 1;
    let selectedSlideItem = this.querySelector(`.slide-${selectedSlide}`);
    let selectSlideNumberItem = this.querySelector('.selected-slide');
    
    selectSlideNumberItem.innerText = selectedSlide;

    this.querySelector('.prev-button').addEventListener('click', (event) => {
      selectedSlideItem = this.querySelector(`.slide-${selectedSlide}`);
      selectedSlideItem.classList.remove('visible');
      selectedSlideItem.classList.add('hidden');

      selectedSlide = selectedSlide === 1 ? 5 : selectedSlide - 1;

      selectedSlideItem = this.querySelector(`.slide-${selectedSlide}`);
      selectedSlideItem.classList.remove('hidden');
      selectedSlideItem.classList.add('visible');

      selectSlideNumberItem.innerText = selectedSlide;
    })


    this.querySelector('.next-button').addEventListener('click', (event) => {
      selectedSlideItem = this.querySelector(`.slide-${selectedSlide}`);
      selectedSlideItem.classList.remove('visible');
      selectedSlideItem.classList.add('hidden');

      selectedSlide = selectedSlide === 5 ? 1 : selectedSlide + 1;

      selectedSlideItem = this.querySelector(`.slide-${selectedSlide}`);
      selectedSlideItem.classList.remove('hidden');
      selectedSlideItem.classList.add('visible');

      selectSlideNumberItem.innerText = selectedSlide;
    })
  }
}
  customElements.define('astro-card', AstroCard);
</script>

<style>
.hidden {
  display: none;
}

.visible {
  display: block;
}
</style>

I upload to the hosting and get the following:

Astro with Web Components

Astro with Web Components

Astro with Vue component

Astro with Vue component

Nuxt 3

Nuxt 3

Astro with web components performed well, 76%-80% on average. Astro with Vue is worse, but here you already have to drag the vue bundle with you, which leads to a significant increase in js code and we get 70% -74% on average. Nuxt 3 is about the same as Astro with Vue 68%-72% on average.

Total:

Astro is really very fast, as the developers say, but only if you write in pure js, or your site doesn’t have js code in principle (various landing pages / blogs), but if you want to use it with Vue / React / Preact – you get +- the same result as on Nuxt/Next. It was interesting to poke him, but it seems it’s too early to move to him =)

I advise everyone to poke it in their free time, quite an interesting thing!

Their approach with astro islands looks very interesting, I advise everyone to read – poke.

If the article seemed interesting to you, then I have TG-channelwhere I write about new technologies in the front, share good books and interesting articles by other authors.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *