Полноценные full-stack приложения

Solid.js — это современный фреймворк для создания быстрых и реактивных пользовательских интерфейсов на JavaScript. Его ключевая особенность — высокая производительность, основанная на использовании детерминированных реактивных систем и минимизации перерасчёта DOM. Однако Solid.js можно использовать не только для создания клиентской логики, но и в качестве основы для полноценного full-stack приложения.

Введение в концепцию full-stack разработки

Full-stack разработка предполагает создание как клиентской, так и серверной части приложения. Для этого традиционно используется связка таких технологий, как фронтенд-фреймворки и серверные библиотеки или фреймворки для работы с базами данных, а также взаимодействие с API.

В контексте Solid.js клиентская часть может быть связана с сервером через различные механизмы: REST API, GraphQL, WebSocket или серверные рендеринги. С помощью Solid.js можно создать высокопроизводительные интерфейсы, а серверная часть может быть построена на популярных технологиях, таких как Node.js, Express, или Deno.

Основные принципы full-stack приложений на Solid.js

Создание full-stack приложения на Solid.js начинается с разработки клиентской части и настройки серверной.

Клиентская часть: Использование реактивности Solid.js

Solid.js использует модель реактивности, схожую с реактивными фреймворками, такими как Vue или Svelte, но с отличием в том, как происходит обновление UI. В Solid.js изменения данных напрямую влияют на DOM, что минимизирует перерасчёты и обеспечивает невероятную скорость рендеринга.

На клиенте можно создавать компоненты, которые используют реактивные примитивы, такие как createSignal, createEffect, и createMemo. Эти примитивы позволяют управлять состоянием и побочными эффектами.

import { createSignal, createEffect } from "solid-js";

function Counter() {
  const [count, setCount] = createSignal(0);

  createEffect(() => {
    console.log(`Counter is now: ${count()}`);
  });

  return (
    <div>
      <p>{count()}</p>
      <button onCl ick={() => setCount(count() + 1)}>Increment</button>
    </div>
  );
}

В этом примере createSignal создаёт реактивное состояние count, а createEffect автоматически выполняет побочный эффект при изменении этого состояния. Это позволяет создавать динамичные и отзывчивые компоненты без дополнительных сложностей.

Серверная часть: Node.js и Express

Для создания серверной части можно использовать Node.js с Express, который позволяет легко обрабатывать HTTP-запросы и работать с базами данных.

Пример простого API-сервера, который отдаёт данные для фронтенда:

import express from 'express';

const app = express();
const port = 3000;

app.get('/api/data', (req, res) => {
  res.json({ message: 'Hello from server' });
});

app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});

Этот сервер отправляет простой JSON-ответ на GET-запросы по пути /api/data. Взаимодействие с таким сервером можно организовать на клиентской части, используя стандартные механизмы HTTP-запросов, такие как fetch.

Интеграция клиентской и серверной части

Интеграция клиента на Solid.js с сервером может быть выполнена с помощью API-запросов. Рассмотрим пример компонента, который запрашивает данные с сервера и отображает их на странице.

import { createSignal, createEffect } from "solid-js";

function DataFetcher() {
  const [data, setData] = createSignal(null);

  createEffect(async () => {
    const response = await fetch("/api/data");
    const json = await response.json();
    setData(json.message);
  });

  return <div>{data() ? data() : "Loading..."}</div>;
}

В этом примере создаётся сигнал для хранения данных (data), и createEffect выполняет запрос к серверу при монтировании компонента. После получения данных они устанавливаются в состояние и отображаются на экране.

Серверный рендеринг с Solid.js

Для создания full-stack приложений, в которых Solid.js используется не только на клиенте, но и на сервере, можно задействовать серверный рендеринг. Этот подход позволяет предварительно генерировать HTML на сервере, что ускоряет загрузку страницы и улучшает SEO.

Использование серверного рендеринга в Solid.js можно организовать с помощью библиотеки solid-start, которая предоставляет механизмы для создания универсальных приложений.

Пример серверного рендеринга с использованием Solid.js:

import { renderToString } from 'solid-js/web';
import { createServer } from 'http';

const server = createServer((req, res) => {
  if (req.url === '/') {
    const app = renderToString(() => <App />);
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.end(`<html><body>${app}</body></html>`);
  }
});

server.listen(3000, () => {
  console.log('Server is running at http://localhost:3000');
});

Здесь используется метод renderToString для рендеринга компонента App в строку HTML, которая затем отправляется клиенту. Это позволяет серверу генерировать полный HTML-код страницы и отправлять его клиенту, где он будет сразу отображён.

Хранение данных: Работа с базами данных

Для полноценного full-stack приложения важно иметь возможность работать с данными. Один из популярных подходов — использование базы данных, например, MongoDB или PostgreSQL.

Для работы с базами данных можно использовать ORM (например, TypeORM для SQL-баз данных) или стандартные библиотеки для работы с MongoDB (например, mongodb).

Пример использования MongoDB на серверной части:

import express from 'express';
import { MongoClient } from 'mongodb';

const app = express();
const port = 3000;

const client = new MongoClient('mongodb://localhost:27017');
let db;

client.connect().then(() => {
  db = client.db('mydb');
});

app.get('/api/users', async (req, res) => {
  const users = await db.collection('users').find().toArray();
  res.json(users);
});

app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});

Этот сервер получает список пользователей из MongoDB и отправляет их в виде JSON на клиентскую сторону.

Пример полного full-stack приложения

Объединив все элементы, можно создать полноценное full-stack приложение с клиентской частью на Solid.js и сервером на Express, который взаимодействует с базой данных.

  1. Клиентская часть (Solid.js): Запрашивает данные с сервера и отображает их.
  2. Серверная часть (Node.js/Express): Обрабатывает запросы и взаимодействует с базой данных.
  3. База данных (например, MongoDB): Хранит данные, такие как пользователи или записи.

Пример реализации:

Сервер:

import express from 'express';
import { MongoClient } from 'mongodb';

const app = express();
const port = 3000;

const client = new MongoClient('mongodb://localhost:27017');
let db;

client.connect().then(() => {
  db = client.db('mydb');
});

app.get('/api/users', async (req, res) => {
  const users = await db.collection('users').find().toArray();
  res.json(users);
});

app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});

Клиент:

import { createSignal, createEffect } from 'solid-js';

function UserList() {
  const [users, setUsers] = createSignal([]);

  createEffect(async () => {
    const response = await fetch('/api/users');
    const data = await response.json();
    setUsers(data);
  });

  return (
    <ul>
      {users().map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

Такое приложение представляет собой минимальный, но полноценный full-stack проект с интеграцией клиентской и серверной логики, а также с хранением данных в базе данных.

Заключение

Solid.js предоставляет мощные инструменты для создания высокопроизводительных клиентских приложений, которые легко интегрируются с серверной частью. С помощью серверного рендеринга, работы с базами данных и построения API можно создавать полностью функциональные full-stack приложения, которые имеют все необходимые элементы для современных веб-сервисов: быстрый интерфейс, серверную логику и хранение данных.