Веб-разработка, как и большинство технологий, движется волнами и циклами. Статические веб-сайты были всем, что у нас было в начале. Но довольно скоро благодаря Perl и PHP разработчики стали собирать первые серверные сайты. Это был прогресс, который в конечном итоге положил начало таким фреймворкам, как Laravel, Django или Rails.
Мобильные устройства изменят то, как люди используют Интернет. Итак, серверные веб-сайты, здравствуйте, клиентские приложения. Следующая волна принесла фреймворки, которые могли предоставить пользователям более похожий на приложение опыт — без перезагрузки — например, React или AngularJS.
Но хотя одностраничные приложения обеспечивают более плавную работу, у них есть свои недостатки. А именно, более длительные загрузки страниц, вызванные всем дополнительным JavaScript, который необходимо проанализировать и выполнить. Не говоря уже о всей работе по оптимизации для поисковых систем.
Astro — яркий пример текущей волны, в которой мы находимся со времен Next.js, проведя нас по кругу: веб-фреймворк, который сочетает в себе серверный и клиентский рендеринг, чтобы получить лучшее из обоих миров.
Что такое Астро?
Astro — это фреймворк с открытым исходным кодом для создания веб-приложений поверх популярных UI-фреймворков, таких как React, Preact, Vue или Svelte. Страница Astro состоит из нескольких независимых компонентов. Чтобы сократить время загрузки, Astro удаляет весь JavaScript и выполняет предварительную визуализацию страниц на сервере, если разработчики не помечают компонент как интерактивный, и в этом случае Astro отправит минимальное количество JavaScript, необходимое для интерактивности.
Благодаря этой стратегии страницы Astro загружаются быстро, так как для первого рендеринга не требуется выполнять JavaScript. В процессе, называемом гидратацией, Astro «заливает» JavaScript в компоненты, чтобы сделать их динамичными.
Почему Астро?
Astro во многом отличается от других веб-фреймворков:
- Скорость. Astro по возможности отображается статически и обрабатывается сервером, что делает его отличным выбором для веб-сайтов, оптимизированных для поисковой оптимизации, таких как блоги, обучающие программы или маркетинговые сайты.
- Независимый от пользовательского интерфейса: в отличие от Next.js, который работает только с React, или Nuxt.js, для которого требуется опыт работы с Vue, Astro не навязывает вам какую-либо структуру пользовательского интерфейса. Вы можете не использовать ничего, свернуть свой собственный или использовать любую из множества поддерживаемых интеграций.
- Темы. У Astro есть внушительный набор готовых тем и шаблонов, с помощью которых можно быстро приступить к работе.
- Легко освоить: вам не нужно изучать React или Vue, чтобы начать работу с Astro. Его механизм шаблонов выглядит как обычный HTML, а код четко отделен от представления. Вы можете выбрать пустой проект и создать его в своем собственном темпе.
- Батарейки в комплекте: Astro поставляется с функциями, которые мы ожидаем от современной платформы JavaScript/TypeScript, такими как ожидания верхнего уровня, поддержка Markdown и MDX, а также ESM.
- Острова: островная архитектура позволяет нам смешивать статический контент, компоненты, отображаемые сервером и клиентом, на одной странице без конфликтов, что позволяет нам создавать интерактивные сайты с минимальными затратами. Мы даже можем смешивать разные фреймворки на одной странице, что дает нам еще один способ создания микрофронтендов. Чуть позже мы узнаем больше о том, как работают острова.
Начало работы с Астро
Чтобы начать работу с Astro, установите Node версии 16.12.0 или выше и выполните следующую команду. Следуйте указаниям мастера на экране и при появлении запроса выберите создание пустого проекта:
$ npm create astro@latest astro v1.9.1 Launch sequence initiated. ✔ Where would you like to create your new project? … awesome-website ✔ How would you like to setup your new project? › an empty project ✔ Template copied! ✔ Would you like to install npm dependencies? (recommended) … yes ✔ Packages installed! ✔ Would you like to initialize a new git repository? (optional) … yes ✔ Git repository created! ✔ How would you like to setup TypeScript? › Relaxed ✔ TypeScript settings applied! next Liftoff confirmed. Explore your project!
Затем вы можете запустить веб-сайт в режиме разработчика, войдя в каталог только что созданного и запущенного проекта: npm run dev
и посетив http://localhost:3000
.
Страницы и маршруты
Самое интересное в Astro происходит внутри папки src
. Проверяя, что там, мы видим один каталог с именем pages
с файлом index.astro
.
Астро-страницы представляют собой смесь HTML, Javascript или TypeScript. Это значение по умолчанию index.astro
:
--- --- <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>Astro</title> </head> <body> <h1>Astro</h1> </body> </html>
Возможно, вы заметили, что файлы Astro начинаются с ограждений, обозначенных цифрой ---
. Какой бы код мы ни помещали внутрь этих ограждений, он выполняется на сервере и предварительно обрабатывается перед обслуживанием страницы.
Под главной темой мы находим содержимое этого маршрута, расширенную HTML-форму, допускающую переменные. Мы можем, например, определить переменную во вступительной части и использовать ее в HTML следующим образом:
--- // src/pages/index.astro const title = "Astro"; --- <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>{title}</title> </head> <body> <h1>{title}</h1> </body> </html>
Astro использует маршрутизацию на основе файлов, поэтому каждый файл в папке pages
сопоставляется с маршрутом на веб-сайте. Например, если мы создадим файл с именем greetings.astro
, мы должны увидеть его содержимое в http://localhost:3000/greetings
.
--- const greeting = "Hello, world!"; --- <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>Astro</title> </head> <body> <h1>{greeting}</h1> </body> </html>
Помимо файлов .astro
, Astro может анализировать файлы Markdown, MDX, JSX JavaScript и TypeScript. Например, если мы хотим написать сообщение в блоге в Markdown, мы создаем файл post.md
в папке pages
. Посещение маршрута заставит Astro конвертировать его в HTML на лету:
--- title: 'Learning Astro' pubDate: 2023-01-10 description: 'A post written in Markdown.'ma author: 'Tommy' --- # Learning Astro This Markdown file should be rendered as HTML when I visit http://localhost:3000/post
Компоненты
Компоненты Astro — это *.astro
файлов с повторно используемым кодом и HTML. Мы можем использовать компоненты для написания таких элементов, как заголовки, нижние колонтитулы, панели навигации, кнопки и формы — все, что может быть выражено в виде HTML, может составлять компонент.
Давайте создадим наш первый компонент в src/components/Header.astro
:
--- // src/components/Header.astro --- <meta charset="utf-8" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="viewport" content="width=device-width" /> <meta name="generator" <title>Astro</title>
После определения мы можем импортировать его на любую страницу (или в другие компоненты) и использовать следующим образом:
--- import Header from "../components/Header.astro"; --- <html lang="en"> <head> <Header /> </head> <body> </body> </html>
Компоненты Astro ничем не отличаются от страниц. Любой код, определенный между заборами, выполняется на сервере. JavaScript удаляется перед отправкой содержимого в браузер.
Макеты
Макеты используются для уточнения повторно используемых структур пользовательского интерфейса. Технически они являются компонентами, поэтому синтаксис остается прежним.
Давайте заменим содержимое index.astro
макетом:
--- // src/pages/index.astro import SiteLayout from "../layouts/SiteLayout.astro"; --- <SiteLayout></SiteLayout>
Как видите, макеты по соглашению хранятся в папке src/layouts
.
Макеты, как и компоненты, могут включать в себя другие компоненты. Здесь мы извлекли структуру из index.astro
и добавили компонент Footer
:
--- // src/layouts/SiteLayout.astro import Header from "../components/Header.astro"; import Footer from "../components/Footer.astro"; --- <html lang="en"> <head> <Header /> </head> <body> <Footer /> </body> </html>
Реквизит и слоты
До сих пор наш сайт был полностью статичен. Чтобы передавать данные между страницами и компонентами, нам нужно понять, как работают props и slots.
Компоненты и макеты могут определять и принимать реквизиты (сокращение от свойств) через глобальный файл Astro.props
. Значения, переданные через реквизиты, доступны компоненту перед рендерингом.
Мы можем прочитать реквизиты в нашем компоненте следующим образом:
--- // src/components/Header.astro const { title } = Astro.props; --- <meta charset="utf-8" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="viewport" content="width=device-width" /> <meta name="generator" <title>{title}</title>
Значение title
может быть указано при вызове компонента, что в следующем примере происходит через макет SiteLayout
.
--- // src/layouts/SiteLayout.astro import Header from "../components/Header.astro"; import Footer from "../components/Footer.astro"; --- <html lang="en"> <head> <Header title = "Welcome my Astro Blog!" /> </head> <body> <Footer /> </body> </html>
⚠️ Обратите внимание, что вам нужны пробелы вокруг знака равенства, т.е. title="Hello"
НЕ ПРАВИЛЬНО. Вместо этого должно быть: title = "Hello"
.
Элементы Slot создают заполнители для содержимого, которое будет добавлено позже. Чтобы увидеть, как это работает, мы можем добавить элемент <slot />
в src/layouts/SiteLayout.astro
:
--- // src/layouts/SiteLayout.astro import Header from "../components/Header.astro"; import Footer from "../components/Footer.astro"; --- <html lang="en"> <head> <Header title = "Welcome my Astro Blog!" /> </head> <body> <slot /> <Footer /> </body> </html>
Теперь HTML внутри <SiteLayout>
вставляется в точку, где расположен слот.
--- // src/pages/index.astro import SiteLayout from "../layouts/SiteLayout.astro"; --- <SiteLayout> <p>This content is rendered in the slot</p> </SiteLayout>
Вложенные компоненты, макеты, реквизиты и слоты дают нам возможность создавать многократно используемые файлы пользовательского интерфейса на веб-сайте.
Острова и увлажнение
До этого момента мы не отправляли пользователю JavaScript; все предварительно визуализируется и используется как чистый HTML+CSS. Как мы можем отправить Astro отправить JavaScript в браузер? Для этого нам нужно понять архитектуру островов.
Шаблон островной архитектуры направлен на уменьшение объема JavaScript, необходимого на стороне браузера. Меньше JavaScript означает меньше отправляемых данных и меньшую вычислительную мощность, требуемую на устройстве пользователя. Остров — это автономный компонент, который объединяет HTML, CSS и — опционально — JavaScript. В шаблоне островов страница состоит из нескольких независимых островов.
Каждый остров предварительно визуализируется, поэтому интерактивность сразу после загрузки страницы отсутствует. Как только начальная страница готова, островки преобразуются в интерактивный контент в процессе, называемом гидратацией. Гидратация — это метод, который преобразует статический контент, доставленный через статический хостинг или рендеринг на стороне сервера, в динамическую страницу путем прикрепления обработчиков событий к элементам HTML.
Использование островов
Ниже приведен пример, показывающий, как Astro реализует острова. Давайте сначала добавим интеграцию пользовательского интерфейса в проект. Следующая команда устанавливает @astrojs/preact
и preact
.
$ npx astro add preact
Давайте создадим простую кнопку для тестирования интеграции:
// src/components/MyButton.jsx export default function MyButton() { const clicked = () => { console.log('Hello!') }; return ( <div> <button style={{ color: 'purple' }} onClick={clicked}>Click me</button> </div> ) }
Как обычно, Astro попытается удалить любой JavaScript. Так что ничего не произойдет, если мы создадим экземпляр компонента с <MyButton />
. Нам нужно сообщить Astro, что мы хотим, чтобы этот компонент рассматривался как остров и соответственно гидратировался, добавив template директиву client:load
:
--- import MyButton from "../components/MyButton.jsx"; --- <html lang="en"> <body> <MyButton client:load /> </body> </html>
При нажатии на кнопку должно быть напечатано «Hello!» в консоли браузера.
Директива клиента заставила Astro гидратировать компонент. Существует пять уровней гидратации с разными приоритетами:
client:load
увлажняет компонент как можно быстрее.client:idle
увлажняет компонент, когда страница загружается. Полезно для низкоприоритетных компонентов, которым не требуется немедленная интерактивность.client:visible={string}
увлажняет компонент, как только он появляется в окне просмотра.client:media={string}
принимает запрос CSS в качестве аргумента и загружает компонент, как только он будет выполнен.client:only
полностью пропускает визуализацию HTML и отображает компонент в браузере.
Развертывание приложения Astro с CI/CD
Поскольку это Node-приложение, настроить сборку Astro с помощью CI/CD очень просто. Нам нужна всего пара работ.
Первое задание запускает npm ci для заполнения node_modules
. Мы используем sem-version для выбора текущей версии Node.
checkout sem-version node 19.4 npm ci cache store
Второе задание запускает npm run build
и сохраняет построенное приложение (находящееся в папке dist
) как артефакт рабочего процесса.
checkout sem-version node 19.4 cache restore npm run build artifact push workflow dist/
После того, как сайт построен, мы можем настроить непрерывное развертывание.
Цели развертывания
В зависимости от характера веб-приложения Astro можно развернуть как статический сайт а-ля Хьюго или Гэтсби, и в этом случае нам нужно только что-то простое, например, корзина S3 или страницы GitHub, или как полноценный серверный рендеринг. (SSR), где нам нужны конечные точки с поддержкой JavaScript или TypeScript.
Astro имеет встроенную поддержку различных популярных целей развертывания, таких как Netlify, Firebase, Vercel и Deno. Некоторые поддерживают только SSR или статический хостинг, в то время как другие могут делать и то, и другое.
После того, как мы выбрали наш метод развертывания, мы можем добавить конвейер непрерывного развертывания для автоматического развертывания веб-сайта при каждом изменении.
Вот пример конвейера развертывания, нацеленного на статический сайт Netlify.
Для справки, рабочие команды следующие. Это предполагает, что мы уже получили токен API и сохранили его как секрет на семафоре с переменными env NETLIFY_TOKEN и NETLIFY_SITE.
checkout artifact pull workflow dist npm install -g netlify-cli netlify deploy --dir=dist --prod --auth $NETLIFY_TOKEN --site $NETLIFY_SITE
Заключение
Популярность этого проекта была не чем иным, как астрономической: за первые пять месяцев с момента выпуска Astro 1.0 проект набрал более 25 000 звезд на GitHub. Успех Astro не случаен. Команда Astro создала веб-фреймворк, который предлагает отличную эргономику для разработчиков и быстро загружаемые веб-сайты для пользователей, даже если они используют маломощные устройства или медленное соединение.
Спасибо за прочтение и удачного строительства!
Первоначально опубликовано на https://semaphoreci.com 2 марта 2023 г.