SolidStart — метафреймворк поверх Solid.js, который добавляет файловый роутинг, серверные функции, SSR и сборку. Solid славится тонкой реактивностью без виртуального DOM, а SolidStart делает его пригодным для полноценных веб-приложений. Разберём создание проекта, работу с данными, сборку и ошибки, которые чаще всего встречаются на практике.

Чем SolidStart отличается от Solid

Сам Solid.js — это библиотека реактивного рендеринга. Она не знает, как устроены маршруты, откуда брать данные и как собирать серверную часть. SolidStart добавляет:

  • маршрутизацию по файлам в каталоге src/routes;
  • серверные функции с директивой "use server";
  • загрузку данных через query и мутации через action;
  • SSR, гидрацию и режим одностраничного приложения;
  • пресеты сборки для Node, статики и облачных платформ.

Актуальная ветка — SolidStart 1.x. В основе сборки лежат Vite и серверный рантайм Nitro, поэтому знакомые по экосистеме плагины и пресеты деплоя работают предсказуемо.

Создание проекта

Проще всего начать с официального генератора. Он задаст вопросы о шаблоне и типе приложения, после чего останется установить зависимости.

npm create solid@latest my-app
cd my-app
npm install
npm run dev

Dev-сервер по умолчанию слушает порт 3000. Структура проекта минимальна: src/app.tsx — корневой компонент, src/routes — страницы, app.config.ts — конфигурация сборки. Не добавляйте в проект лишние слои, пока не появится реальная потребность.

Проверить версии установленных пакетов полезно сразу: несовместимость solid-js и @solidjs/start — частая причина странных ошибок гидрации.

npm ls solid-js @solidjs/start @solidjs/router

Маршрутизация по файлам

Файл src/routes/index.tsx отвечает за главную страницу, src/routes/about.tsx — за /about. Динамические сегменты задаются квадратными скобками: src/routes/users/[id].tsx. Вложенные каталоги создают вложенные маршруты, а файл [id].tsx внутри них получает параметр через useParams.

import { useParams } from "@solidjs/router";

export default function UserPage() {
  const params = useParams();
  return <p>Пользователь: {params.id}</p>;
}

Для страницы 404 достаточно файла [...404].tsx. Не смешивайте маршруты и компоненты в одном каталоге: первые должны оставаться тонкими, а логику выносите в отдельные модули.

Данные: query и action

В SolidStart серверные функции объявляются в отдельном файле с директивой "use server". Чтение оборачивается в query, запись — в action. Такой подход даёт кэширование, повторную валидацию и безопасную границу между клиентом и сервером.

"use server";

import { query } from "@solidjs/router";

export const getPosts = query(async () => {
  const res = await fetch("https://api.example.com/posts");
  return res.json();
}, "posts");

На странице результат подключается через createAsync и Suspense. Пока данные грузятся, показывайте скелетон, а не пустой экран. Ошибки обрабатывайте через ErrorBoundary: без него сбой запроса уронит всю страницу.

import { createAsync } from "@solidjs/router";
import { Suspense } from "solid-js";
import { getPosts } from "~/lib/posts";

export default function Home() {
  const posts = createAsync(() => getPosts());
  return (
    <Suspense fallback={<p>Загрузка…</p>}>
      <ul>
        {posts()?.map((p) => <li>{p.title}</li>)}
      </ul>
    </Suspense>
  );
}

Мутации оформляйте через action и обычную форму. Это работает без JavaScript на клиенте и упрощает прогрессивное улучшение. После успешного действия обновите связанный query, иначе пользователь увидит устаревшие данные.

SSR, SPA и статика

По умолчанию приложение рендерится на сервере. Для внутреннего дашборда без SEO иногда проще отключить SSR и получить классическое SPA. Режим задаётся в app.config.ts:

import { defineConfig } from "@solidjs/start/config";

export default defineConfig({
  ssr: false,
  server: { preset: "node-server" }
});

Для статического сайта используйте пресет static и убедитесь, что все страницы могут быть предрендерены. Если маршрут зависит от cookies или заголовков запроса, статическая генерация для него не подойдёт.

Пресет node-server — универсальный вариант для собственного VPS. Сборка кладёт серверный бандл в .output, и запуск сводится к одной команде.

npm run build
node .output/server/index.mjs

Переменные окружения и секреты

Серверные функции читают переменные через process.env, но на клиенте их не будет. Держите ключи в файле .env локально и в переменных окружения платформы при деплое, а в репозиторий добавляйте только пример .env.example. Публичные значения с префиксом VITE_ попадают в клиентский бандл, поэтому не используйте этот префикс для токенов.

При сборке в контейнере передавайте переменные на этапе запуска, а не только сборки: иначе серверная часть получит пустые значения и упадёт при первом запросе.

Типичные ошибки

  • Ошибка гидрации. Причина — разное содержимое на сервере и клиенте: даты, случайные числа, обращение к window в теле компонента.
  • Секреты на клиенте. Всё, что импортировано в клиентский компонент, попадает в бандл. Ключи API держите только в серверных функциях.
  • Тяжёлые зависимости. Импорт библиотеки целиком увеличивает бандл; используйте точечные импорты.
  • Отсутствие Suspense. Без него асинхронные данные ведут себя непредсказуемо.

Для проверки типов запускайте npx tsc --noEmit в CI. Это дешевле, чем ловить ошибку в рантайме после деплоя. Логи сборки читайте целиком: предупреждения Nitro часто указывают на несовместимый пресет.

Стоит ли выбирать SolidStart

Фреймворк хорош для команд, которым нужна максимальная производительность при небольшом размере бандла и которые готовы разбираться в реактивной модели. Экосистема заметно меньше, чем у Next.js или Nuxt, поэтому часть готовых решений придётся писать самостоятельно. Зато отладка проще: нет виртуального DOM, а зависимости отслеживаются точечно.

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

Итог

SolidStart даёт Solid.js полноценную инфраструктуру: маршруты, серверные функции, SSR и предсказуемую сборку. Начать можно с npm create solid@latest, а дальше наращивать проект по мере необходимости. Держите серверные функции отдельно от клиентского кода, не забывайте про Suspense и проверяйте типы в CI. Этого достаточно, чтобы приложение оставалось быстрым и понятным в сопровождении.

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 0 / 5. Количество оценок: 0

Оценок пока нет. Поставьте оценку первым.

Поделиться: Telegram ВКонтакте