Я создал NexusLite, чтобы понять устройство фронтенд-фреймворка и иметь небольшую кодовую базу, которую можно изучать во время работы. В нём есть функции элементов, хранилище состояния, маршрутизация и статический рендеринг без зависимостей времени выполнения.
Этот сайт использует NexusLite для создания страниц во время сборки. Браузер получает HTML, CSS и несколько скриптов для меню, выбора темы, фильтров и интерактивных обзоров проектов.
Что делает фреймворк
Основная реализация находится в framework/src/nexuslite.ts. Генерация статического сайта вынесена в отдельный модуль prerender.ts. Оба модуля входят в один пакет.
Функции элементов описывают дерево обычными вызовами функций.
createDOM()превращает дерево в элементы браузера.createStore()хранит состояние и уведомляет подписчиков об изменениях.createApp()связывает хранилище, корневой элемент и функцию отображения.createRouter()поддерживает маршруты через hash и History API.renderToString()создаёт HTML из тех же описаний элементов.prerender()записывает таблицу маршрутов в статические файлы.
В пакете также есть HTTP-клиент, делегирование событий, перетаскивание и отложенное отображение списков. Приложение может использовать нужные ему части.
Небольшой интерактивный пример
Если в HTML есть элемент с id="app", этот код создаст счётчик:
import { createApp, createStore, div, h1, button, on } from 'nexuslite';
const store = createStore({ count: 0 });
createApp({
root: '#app',
state: store,
render: (state) => div([
h1(`Счётчик: ${state.count}`),
button('Уменьшить', on('click', () => {
store.setState({ count: state.count - 1 });
})),
button('Увеличить', on('click', () => {
store.setState({ count: state.count + 1 });
})),
]),
});
В NexusLite 1.2.0 функция createApp() очищает и заново строит корневой элемент при изменении состояния. Она не сравнивает старое и новое дерево через виртуальный DOM.
Реализация проста для чтения, но у этого есть цена. Замена активного поля может сбросить фокус или состояние, которым управляет браузер. В больших интерфейсах может возникать лишняя работа. Эти ограничения нужно учитывать при выборе фреймворка и размера реактивной области.
Создание статической страницы
Большей части портфолио не нужен реактивный корень. Содержимое можно создать один раз во время сборки:
import { readFileSync } from 'node:fs';
import { h } from 'nexuslite';
import { prerender } from 'nexuslite/prerender';
await prerender({
routes: {
'/': () => h('main', {}, [
h('h1', {}, 'Мои проекты'),
h('p', {}, 'Что я разработал и для чего это нужно.'),
]),
},
outDir: 'dist',
template: readFileSync('index.template.html', 'utf8'),
notFoundPath: false,
});
Шаблон представляет собой строку HTML с маркером <!--ROOT-->. NexusLite заменяет его содержимым страницы. Отдельная функция transform(html, path) позволяет задать заголовки и метаданные для каждого маршрута.
Сборка этого сайта находится в scripts/prerender.ts. Она создаёт языковые версии страниц, копирует ресурсы, формирует карту сайта и изображения для ссылок. Главная страница, каталог и подробные страницы используют один список проектов.
Что добавляет сам сайт
NexusLite работает с деревьями элементов и генерацией HTML. Сайт добавляет содержимое, дизайн-систему, метаданные и браузерные взаимодействия.
Master Design System хранит палитру, типографику, отступы и темы в одном файле токенов. Сборка создаёт из него CSS и использует ту же палитру для изображений ссылок. Шрифты загружаются с самого сайта.
Карточки проектов присутствуют в исходном HTML. Поиск и фильтры дополняют каталог после загрузки, а запрос сохраняется в адресе страницы. Содержимое остаётся доступным без JavaScript, а результатами поиска можно делиться.
Проверки и ограничения
В используемой здесь версии NexusLite 1.2.0 есть 167 тестов основных функций и генерации страниц. У сайта есть отдельные проверки маршрутов, метаданных, изображений, поиска и исправлений безопасности.
Эти проверки не доказывают универсальную производительность. Скорость загрузки зависит от ресурсов, сервера, кеша, устройства и соединения. Для полезного сравнения нужно записать условия измерения. Для меня важнее, что путь отображения достаточно мал и его можно изучить при ошибке.
NexusLite подходит для обучения, небольших интерфейсов и сайтов со статическим содержимым. Большим приложениям могут понадобиться более сложное обновление DOM и широкая библиотека компонентов. Выбор стоит делать по требованиям задачи, а не только по размеру фреймворка.
Посмотреть код
Исходный код находится в github.com/AG064/nexuslite. Фреймворк распространяется по лицензии MIT. Начать знакомство можно с README и примеров.
Этот сайт показывает статический рендеринг в работе. Его HTML можно сопоставить с функциями в src/pages/, а на странице NexusLite есть интерактивный пример.