Перейти к содержимому

32. Script-теги и JS на клиенте

Astro предоставляет гибкую систему управления JavaScript-скриптами. Вы полностью контролируете, как, когда и где загружается клиентский код.

В .astro-файлах можно писать скрипты прямо в шаблоне:

---
// Frontmatter — серверный код
const message = 'Привет с сервера';
---
<button id="btn">Нажми меня</button>
<script>
// Клиентский JavaScript
const btn = document.getElementById('btn');
btn.addEventListener('click', () => alert('Клик!'));
</script>

По умолчанию Astro автоматически бандлит скрипты: объединяет дублирующиеся импорты, удаляет неиспользуемый код и минифицирует.

Все скрипты Astro по умолчанию — ES-модули (type="module"):

  • Выполняются после парсинга HTML (не блокируют рендеринг)
  • Поддерживают import / export
  • Выполняются один раз при загрузке страницы
<script>
import confetti from 'canvas-confetti';
// Astro автоматически подтянет npm-пакет
confetti();
</script>

Используйте is:inline, чтобы отключить обработку Astro и оставить скрипт как есть:

<script is:inline>
// НЕ бандлится, НЕ оптимизируется
// Выполняется при каждом рендере страницы
// Может использоваться для legacy-кода
window.myGlobal = 'значение';
</script>

Когда использовать is:inline:

  • Скрипты, которые должны выполняться синхронно до парсинга
  • Встроенные скрипты инициализации (тема, locale)
  • Сторонние скрипты без поддержки ES modules

Передавайте данные из frontmatter (сервер) в клиентский скрипт:

---
const theme = 'dark';
const user = { name: 'Алекс', role: 'admin' };
---
<script define:vars={{ theme, user }}>
console.log(theme); // 'dark'
console.log(user.name); // 'Алекс'
document.documentElement.setAttribute('data-theme', theme);
</script>

define:vars автоматически добавляет is:inline, так как переменные уникальны для каждого рендера.

<!-- Внешний скрипт — также бандлится если локальный -->
<script src="../scripts/menu.js"></script>
<!-- Внешний URL — не бандлится -->
<script src="https://cdn.example.com/library.js"></script>

При использовании View Transitions страница не перезагружается полностью. Используйте события Astro:

document.addEventListener('astro:page-load', () => {
// Код выполняется после каждой навигации
initializeComponents();
});
document.addEventListener('astro:before-preparation', () => {
// Страница начинает загружаться
});

Astro идеально подходит для Web Components — нативных кастомных элементов:

<my-counter start="0"></my-counter>
<script>
class MyCounter extends HTMLElement {
connectedCallback() {
const start = parseInt(this.getAttribute('start') || '0');
this.innerHTML = '<button>' + start + '</button>';
this.querySelector('button').onclick = () => {
this.querySelector('button').textContent = ++start;
};
}
}
customElements.define('my-counter', MyCounter);
</script>