UNPKG

velund

Version:

Ядро согласованного рендеринга

230 lines (181 loc) 18.3 kB
# Velund – Модульная UI-система на Vite для полиглотных бэкендов ## 🚀 Обзор **Velund** — это не просто плагин для Vite, а **интегрированная экосистема** для создания кросс-платформенных UI-компонентов. Он позволяет фронтенд-разработчикам создавать компоненты с использованием привычных шаблонизаторов, а Velund компилирует их в готовые к использованию библиотеки, которые могут быть интегрированы и рендерены на любом бэкенде (Node.js, Python, PHP) через четко определенные API. Velund фокусируется на: - **Контрактной разработке**: Четкие схемы данных между фронтендом и бэкендом. - **Модульности**: Возможность использовать готовые или создавать собственные рендереры и генераторы. - **Изоляции**: UI-компоненты независимы от конкретной логики бэкенда. - **Автоматизации**: Генерация библиотек и DTO для бэкенда. ## ✨ Основные возможности - **Агностик к шаблонизатору**: Поддержка Twig (`@zebrains/velund-twig`), Jinja/Nunjucks (`@zebrains/velund-jinja`), HTML (`@velund/html`). Система позволяет легко добавлять новые шаблонизаторы. - **Типизированные компоненты**: Строгое определение `props` и `context` компонентов с помощью схем TypeBox (транслируются в JSON Schema). - **Backend-интеграция**: Автоматическая генерация специализированных библиотек для бэкенд-языков (Node.js, Python, PHP), которые предоставляют готовый `Renderer` класс для рендеринга компонентов. - **Горячая перезагрузка (HMR)**: Мгновенные обновления UI-компонентов в процессе разработки. - **Управление ассетами**: Автоматическое управление путями к статическим ассетам, готовое к употреблению бэкендом. - **Асинхронные данные**: Поддержка асинхронной подготовки данных (`prepare` метод) для компонентов. - **Расширяемая архитектура**: Возможность использования готовых или создания собственных рендереров и генераторов благодаря API, предоставляемому `@velund/core`. ## 📦 Установка ### 1. Создание нового проекта с `create-velund` (рекомендуется) Используйте CLI-инструмент `create-velund` для быстрой инициализации проекта: ```bash pnpm create velund # или npm create velund@latest # или yarn create velund ``` `create-velund` интерактивно спросит вас о названии проекта, предпочитаемом шаблонизаторе и генераторе для бэкенда, и автоматически настроит `vite.config.ts` и установит необходимые зависимости. ### 2. Добавление Velund в существующий проект Vite Установите `velund` и необходимые рендереры/генераторы: ```bash pnpm add velund @zebrains/velund-twig # Для поддержки Twig-шаблонов # и/или pnpm add @velund/node # Для генерации Node.js-библиотеки # и/или другие рендереры/генераторы ``` ## 🛠️ Базовая настройка `vite.config.ts` ```typescript // vite.config.ts import { defineConfig } from 'vite'; import velund from 'velund'; // Основной плагин Velund import twigRenderer from '@zebrains/velund-twig'; // Пример: рендерер для Twig import phpGenerator from '@zebrains/velund-php'; // Пример: генератор для PHP export default defineConfig({ plugins: [ velund({ // -- Основной шаблонизатор и генератор для проекта -- renderer: 'twig', // Указывает основной шаблонизатор (Twig, Jinja, HTML) generator: 'php', // Указывает основной генератор для бэкенда (Node.js, Python, PHP) // -- Регистрация рендереров -- // Все используемые рендереры должны быть зарегистрированы здесь. // @velund/html уже встроен. renderers: [ twigRenderer(), // Экземпляр Twig-рендерера ], // -- Регистрация генераторов -- // Все используемые генераторы должны быть зарегистрированы здесь. // @velund/node уже встроен. generators: [ phpGenerator(), // Экземпляр Python-генератора ], // -- Опции для интеграции с бэкендом -- assetsUrl: '/assets', // URL-путь по которому бэкенд должен отдавать статические ассеты Velund. // Velund ожидает, что бэкенд будет обслуживать dist/assets по этому пути. renderUrl: '/__render', // URL-путь для API-эндпоинта, который бэкенд должен предоставить. // Используется в dev-режиме для рендеринга компонентов в рантайме. // -- Прочие опции -- strictTemplateExtensions: false, // `true` если нужно строго проверять расширения файлов шаблонов (например, только .twig) // nodeConfig?: VelundNodeGeneratorOptions; // Конфигурация для `@velund/node` генератора. }), ], }); ``` ## 🧩 Определение UI-компонентов (`.vel.ts`) Velund-компоненты определяются в виде TypeScript-файлов (обычно `.vel.ts`) и являются вашим основным способом создания UI. Вы можете автоматически собирать их через виртуальный модуль `virtual:velund/components` ```typescript // src/components/ProductCard.vel.ts import { defineComponent } from 'velund/common'; // Хелпер для определения компонента import { Type } from '@sinclair/typebox'; // Используется для описания схем данных import template from './ProductCard.twig'; // Путь к файлу шаблона export default defineComponent({ name: 'ProductCard', // Уникальное имя компонента template, // Путь к связанному файлу шаблона (например, `.twig`, `.j2`, `.html`) // -- Схема входных свойств (PropTypes) -- // `propsSchema` определяет данные, которые компонент принимает извне. // Бэкенд-библиотека будет использовать эту схему для валидации входных данных. propsSchema: Type.Object({ id: Type.Number(), // ID продукта }), // -- Схема контекста шаблона (ContextType) -- // `contextSchema` определяет структуру данных, которые будут доступны внутри шаблона. // Это может быть объединение входных props и данных, полученных в `prepare` методе. contextSchema: Type.Object({ title: Type.String(), // Название продукта price: Type.Number(), // Цена продукта description: Type.Optional(Type.String()), // Описание (необязательно) }), // -- Метод подготовки данных (Runtime Data Fetching) -- // `prepare` - асинхронная функция, которая вызывается для получения или подготовки данных для компонента. // Она принимает `props` в соответствии с `propsSchema` и должна возвращать объект, // который будет объединен с `props` и передан в шаблон в качестве `context`. async prepare(props) { // Пример: получить данные о продукте из API const res = await fetch(`/api/products/${props.id}`); // Используется `fetch` (доступен в Node.js и браузере) const productData = await res.json(); return productData; // Эти данные будут доступны в шаблоне как часть `context` }, }); ``` ## 🔌 Интеграция с бэкендом Velund **не просто генерирует JSON-схемы**, он создает **полноценные библиотеки для вашего бэкенд-языка**. ### Как это работает: 1. **Генерация библиотеки**: При сборке вашего фронтенд-проекта (`npm run build`), выбранный `generator` (например, `@velund/node`) генерирует библиотеку в вашей `build.outDir` (например, `dist/`) директории. 2. **`Renderer` класс**: Эта сгенерированная библиотека предоставляет основной класс `Renderer` (или аналогичный) и специализированные классы/функции для каждого вашего компонента (например, `ProductCard`). 3. **API для бэкенда**: Бэкенд-разработчик использует этот `Renderer` класс для: - Инициализации (обычно требуется указать путь к скомпилированным шаблонам). - Регистрации `prepare` методов: Если компонент использует асинхронный `prepare` метод (как в примере выше), бэкенд должен будет **предоставить синхронную или асинхронную реализацию этого метода** в своей среде. Сгенерированная типизация или описание для IDE поможет бэкенду понять, какие аргументы (`props`) должен принимать этот метод и какой контекст возвращать. - Рендеринга компонента: Вызов метода `render(componentName, context, meta?: boolean)` предоставит готовый HTML. ### Пример использования в Node.js (генерируемый `@velund/node`): После сборки фронтенда, вы можете использовать сгенерированную библиотеку в вашем Node.js-проекте: ```javascript import express from 'express'; import path from 'path'; import { HomePageComponent, ProductPageComponent, Renderer, } from '../velund/lib'; const app = express(); const port = 3333; // Предоставление директории с ассетами const publicDir = path.join(process.cwd(), 'velund/assets'); app.use('/assets', express.static(publicDir)); // Регистрация prepare-метода дла компонента HomePage HomePageComponent.registerPrepare(async () => { const products = await ( await fetch('https://fakestoreapi.com/products') ).json(); products[0].title = Date.now() + products[0].title; return { products, }; }); // Регистрация prepare-метода для компонента ProductPage ProductPageComponent.registerPrepare(async ({ id }) => { const product = await ( await fetch('https://fakestoreapi.com/products/' + id) ).json(); return product; }); // Инициализация рендер-класса const renderer = new Renderer(); // Регистрация роутов app.get('/', async (req, res) => { const html = await renderer.render('HomePage', {}); res.status(200).send(html).end(); }); app.get('/ProductPage', async (req, res) => { const r = await renderer.render('ProductPage', req.query); res.status(200).send(r).end(); }); app.listen(port, () => { console.log(`🚀 Server running at http://localhost:${port}`); }); ``` ### Важные нюансы для бэкенда: - **Сервировка ассетов**: Бэкенд должен быть настроен на обслуживание статических файлов из директории Velund `dist/assets` по пути, указанному в `assetsUrl` (`/assets` по умолчанию). - **Runtime-рендеринг**: Бэкенд может реализовать эндпоинт по пути `renderUrl` (`/__render` по умолчанию) для динамического рендеринга компонентов в рантайме, используя логику, подобную той, что предоставляют генераторы. Это полезно для SSR или API-запросов. ## ⚙️ Детальная конфигурация плагина `velund` Интерфейс `iTwigPluginConfig` (определен в `src/types.ts`) для функции `velund()`: | Опция | Тип | По умолчанию | Описание | | -------------------------- | ----------------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `renderer` | `string` | `'html'` | **Обязательный**. ID основного рендерера для проекта (например, `'twig'`, `'jinja'`, `'html'`). Используется для выбора дефолтного рендерера. | | `generator` | `string` | `'node'` | **Обязательный**. ID основного генератора для проекта (например, `'node'`, `'python'`, `'php'`). Указывает, какую бэкенд-библиотеку Velund должен генерировать. | | `assetsUrl` | `string` | `'/assets'` | **Путь URL**, по которому бэкенд должен будет **обслуживать статические ассеты** (JS,CSS, изображения), сгенерированные Vite. Это критически важный контракт для бэкенда. | | `renderUrl` | `string` | `'/__render'` | **Путь URL** для API-эндпоинта, который бэкенд _должен_ будет предоставить для **динамического рендеринга компонентов в рантайме**. Velund использует этот же URL в режиме разработки для собственного отладочного сервера. | | `strictTemplateExtensions` | `boolean` | `false` | Если `true`, Velund будет строго проверять, что расширения файлов шаблонов соответствуют зарегистрированным для рендереров (например, только `.twig` для Twig-рендерера). | | `generators` | `VelundGeneratorDescriptor[]` | `[]` | Массив **экземпляров** генераторов, которые Velund должен использовать (например, `[pythonGenerator(), phpGenerator()]`). **`@velund/node` встроен по умолчанию.** | | `renderers` | `VelundRendererDescriptor[]` | `[]` | Массив **экземпляров** рендереров, которые Velund должен использовать (например, `[twigRenderer(), jinjaRenderer()]`). **`@velund/html` встроен по умолчанию.** | | `nodeConfig` | `VelundNodeGeneratorOptions` | `{}` | Конфигурация, специфичная для `@velund/node` генератора (если используется). | ## 📜 Лицензия MIT © DNTZ