Предисловие

Всем привет, в последнее время, много вижу/читаю/слышу про astro, про то, какой он быстрый, производительный. Поэтому я решил потыкать Astro и параллельно проверить насколько он быстр - я написал на нем примитивный блог с 600 карточками и сравнил его по производительности с Nuxt 3 SSG.

Производительность замерял с помощью pagespeed.

Сразу хочу сказать, что я не претендую на правильность этих тестов - мне просто было интересно как обстоят дела в некоторых кейсах + было интересно потыкать Astro.

Тест 1 (Полностью статический сайт)

Написал компонент карточки на Nuxt 3 и Astro с помощью tailwind и сделал страницу с 600 карточками(обычное количество постов на блоге за пару лет).

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="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>

Залил все это на хостинг и получил следующие результаты:

Astro
Astro
Nuxt 3
Nuxt 3

Получаем довольно предсказуемый результат Astro - 97%-100%, Nuxt 3 - 92%-96%. Понятный результат, так как Astro сгенерил просто чистый html(собственно что и написано у них на главной full speed - zero js), не удивительно что у него результат в районе сотки, тут по-сути нечему снижать производительность. Nuxt еще подгружается бандл с самим фреймфорком, поэтому и результаты ниже.

Тест 2 (Добавил 1 js библиотеку)

В этом тесте я решил добавить библиотеку @sentry/browser - довольно известная библиотека для мониторинга ошибок в вашем приложении. Мне кажется довольно вероятная библиотека на любом сайте.

Подключил ее следующим образом на странице:

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

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

Снова залил это на хостинг и получил следующие результаты:

Astro
Astro
Nuxt 3
Nuxt 3

Видим все тот же результат, Astro подгружает все тот же html файл + js библиотеки и имеет отличные показатели 93%-97% в среднем. Nuxt 3 также подгружает свой бандл + html + js библиотеки, но так как js кода больше, имеет 84%-88% в среднем.

Тест 3 (Сделал внутри карточки примитивный слайдер на js)

Тут я решил добавить js кода и посмотреть как Astro покажет себя на этот раз, тут будет 2 теста Astro, сначала я написал js код с помощью синтаксиса web-components, а потом решил использовать Astro с Vue компонентом Card(По сути просто подключил компонент Vue к Astro), ну и просто написал код на 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="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>

Заливаю на хостинг и получаю следующее:

Astro with Web-Components
Astro with Web-Components
Astro with Vue component
Astro with Vue component
Nuxt 3
Nuxt 3

Astro с веб компонентами неплохо себя показал, 76%-80% в среднем. Astro с Vue похуже, но тут уже приходится тащить за собой бандл vue, что приводит к значительному увеличению js кода и мы получаем 70%-74% в среднем. Nuxt 3 примерно также как Astro с Vue 68%-72% в среднем.

Итого

Astro и правда очень быстрый как и заявляют разработчики, но только в том случае, если ты пишешь на чистом js, либо на твоем сайте впринципе нет js кода(различные лендинги/блоги), однако если хочется использовать его с Vue/React/Preact - ты получаешь +- такой же результат как на Nuxt/Next. Было интересно его потыкать, но, кажется, пока переезжать на него рановато =)

Всем советую его потыкать в свободное время, довольно интересная штука!

Их подход с astro островами выглядит очень интересно, советую всем почитать - тык.

Если статья показалась вам интересной, то у меня есть Тг-канал, где я пишу про новые технологии во фронте, делюсь хорошими книжками и интересными статьями других авторов.

Комментарии (2)


  1. francyfox
    19.07.2023 06:09

    Речь в astro шла о преимуществе над SPA. Я замечал как админки популярных ресурсов написанных в нулевых на php работают значительно быстрее чем после редизайна на React/Vue. Приходиться ждать по 10-15 сек на подгрузку скриптов + загрузка при смене view. Из плюсов анимированные дашборды и куча реактивных цифр и графиков, сменяющихся каждые 3 секунды. То ли ждать пока прогрузиться компонент, то ли все приложение целиком. Наверное по этой причине gitlab состоит из куча инстансов vue.

    Плюс в астро можно использовать несколько фреймворков из коробки. Серьезных боевых проектов на астро я пока еще не видел, хз как он там поведет. Про middleware еще не все написано в доках, для хранения nano store, но пока нет примера коммуникации между компонентами (или островами).


    1. Dragonek Автор
      19.07.2023 06:09

      Astro все-таки скорее про преимущество над SSR/SSG, так как даже на главной сайта - https://astro.build, весит сравнение именно с SSR/SSG фреймворками. Мне кажется, что люди перешли на Vue/React с условных php потому что появилось разделение на frontend + backend плюс эти фреймфорки просто удобнее конкретно для разработки frontend части. ИМХО стали они грузится больше, по причине того, что появился толстый клиент, куда перекочевало куча логики.
      Поддержка нескольких фреймворков выглядит очень перспективно, мне тоже зашла эта тема, но хз насколько она приживется.
      По-поводу серьезных проектов - у них на сайте висят пару сайтов крупных компаний, nordvpn главная и блог firebase.