Федеративные виджеты: Компоненты фронтенда и конечные точки бэкенда в одном модуле

TLDR; В этом посте изложена идея о модулях с открытым исходным кодом, содержащих как компоненты фронтенда, так и конечные точки бэкенда (FCBE), которые имитируют встраиваемые html и скрипты из популярных сторонних сервисов, но на собственном хостинге. Пропустите резюме и перейдите к техническим идеям.

Существует масса компаний, которые предлагают встроенные функции за месячную плату. Типичный сервис обычно предоставляет вам возможность настроить «видимые параметры» через какую-то внутреннюю панель управления или панель администратора. Некоторые предлагают способы минимальной настройки внешнего вида и настроек. Эти вставки обычно обеспечивают определенную интерактивность, некоторые популярные примеры включают аудио (spotify), видео (youtube), карты (openstreetmap) и такие вещи, как формы ввода (calendly) или подписка на рассылку (substack). Общее у этих типов услуг одно — все данные хранятся на серверах. Подобные сервисы различаются по сложности и цене.

Сегодня многие компании, приложения или веб-сайты являются одноцелевыми. Одно приложение для обмена фотографиями, одно для микроблогов, одно для информационных бюллетеней, одно для видео короткой формы, большинство имеют ленту времени, одно для электронной коммерции. Большинство из них хорошо делают что-то одно, и когда вам нужно сделать что-то еще, вы должны постоянно искать новый сервис для этого.

Меня интересует более децентрализованный способ ведения дел. Благодаря размещению собственного веб-сервера вы можете «владеть» своими данными. Зачем платить 10 долларов в месяц за что-то, если можно заплатить меньше, просто разместив сервер и данные самостоятельно? Я считаю, что мы как программисты можем сделать больше, чтобы преодолеть этот разрыв и предложить что-то лучшее тем, кто этого хочет. Более дешевый вариант с большей настраиваемостью.

Я считаю, что будущее Интернета — это предоставление решений с низким кодом, которые вдохновляют людей на владение инструментами, которые они используют, если они хотят это сделать. Веб построен на стандартах, и люди должны изучать их, а не пользовательский интерфейс некоторых компаний, которые делают все по-своему.

Когда существуют варианты с открытым исходным кодом, они обычно выпускаются на уровне сервера и включают в себя большой фреймворк, все это не предназначено для работы друг с другом.

Я думаю об этом так: я представляю себе приложение, в котором есть посты или блоки, но сами типы постов/блоков являются компонентами ui с открытым исходным кодом, они могут быть чем угодно. Картой? Заметка в блоге? Планировщик календаря? Опрос? Карточка товара с кнопкой покупки? Почему мы ограничены в том, что мы можем размещать?

Я действительно впечатлен такими приложениями, как mastodon. Однако я разочарован тем, что децентрализованные / федеративные инструменты выглядят как платформы социальных сетей, которые они призваны заменить, и что они не предлагают никакой возможности настройки, кроме основных постов.

Мне нравится идея о том, что в будущем люди будут создавать не полноценные веб-приложения, а отдельные «виджеты» пользовательского интерфейса, представляющие собой набор компонентов пользовательского интерфейса и данных с интерактивностью. Я думаю, что свидетельством этого является медленное распространение компаний, копирующих отдельные функции пользовательского интерфейса, такие как истории.

Меня вдохновляет WordPress. WordPress был процветающей экосистемой тем и плагинов, которая позволяла любому человеку создавать свой собственный сайт на хостинге и настраивать его по своему усмотрению. Я думаю, что как CMS для написания текстов WordPress был великолепен, однако как платформа для всего и вся он имел некоторые недостатки, он все еще был предназначен для ведения блогов, а создание текстового контента и выполнение любых других действий было мучением.

Технические идеи

Одна из целей, по общему мнению, заключается в том, чтобы сделать реквизиты компонентов источником истины для системы. Нет необходимости дублировать это определение для ввода формы, валидации, определения базы данных. Реквизиты управляют всем виджетом.

Мне нравится думать об отдельном Widget как о noun, thing. Реквизиты хранятся в базе данных и получают UUID. Компонент Component является визуализацией этого существительного.

Меня интересует способ сериализации компонента и передачи его от клиента к серверу в произвольном порядке. В идеале, имея UUID реквизита, можно визуализировать виджет непосредственно через permalink. Вы также должны иметь возможность расположить несколько виджетов на странице через компоненты Page и Column. Форма определяется через JSON с помощью react-jsonschema-form, я также попробовал сгенерировать ее из интерфейса typescript для самого Props. В идеальном мире реквизиты также определяют, что сохраняется в базе данных, будь то таблица для одного компонента или единая таблица для всех компонентов с использованием колонки jsonb props, и что отправляется обратно клиенту.

Вот пример страницы игровой площадки, которая позволяет мне протестировать виджет и реквизиты, переданные в него. Считайте, что это страница книги рассказов. Виджет справа состоит из двух компонентов, обертки Widget, которая обрабатывает метаданные, такие вещи как owner информация, и uuid, privacy и YoutubeEmbed — компонент внутри с одним свойством embed.

Когда вы начинаете думать в виджетах, каждый компонент, кажется, создает или взаимодействует с определенным существительным в базе данных, либо создавая, либо читая, либо редактируя его. В приведенном выше случае это создание YoutubeEmbed. Но в случае Signup или Login это взаимодействие с User noun. Само User noun также является компонентом, позволяющим кому-либо на платформе просматривать и, возможно, редактировать свое имя пользователя или настройки. Реквизит компонента User в некоторой степени отображает пользователя в базе данных, опуская серверные данные, такие как хэшированные пароли или личная информация.

Один из радикальных вариантов дизайна заключался в том, что бэкенд будет диктовать, какие компоненты будут отображаться на странице. Страница имела колонки, и взаимодействие с виджетом могло заставить новые виджеты появиться в пользовательском интерфейсе и расположить их в любом месте страницы. Ответ от отправленного виджета может сделать буквально все, что угодно с самой страницей, отправляя массив действий, таких как удаление / перемещение / редактирование исходного виджета или создание нового произвольного виджета в любом месте страницы (матрица столбцов).

Проблема с тем, что база данных и бэкенд будут диктовать, какие компоненты показывать, заключается в том, что неэффективно содержать во внешнем интерфейсе код для каждого виджета, если есть 100+ виджетов, то на каждой странице будет много лишнего, особенно когда не каждый виджет отображается. Next.js предоставляет возможность предоставлять карту и использовать динамический импорт.

import dynamic from 'next/dynamic';

export const FormDynamic = {
  SignupForm: dynamic<any>(() => import('modules/signup/SignupForm').then(m => m.SignupForm)),
  UserForm: dynamic<any>(() => import('modules/user/UserForm').then(m => m.UserForm)),
}

export default FormDynamic;
Вход в полноэкранный режим Выход из полноэкранного режима

Затем вы можете сериализовать компонент через ключ здесь, и его реквизиты и передать это фронтенду, который может отрисовать его в реальном времени (очевидно, может быть также SSR для загрузки страницы). Но общая идея заключается в том, что нет кодовой базы фронтенда. База данных содержит страницы -> столбцы -> виджеты, все они используют UUID для описания того, какие виджеты отображаются на той или иной странице.

Другие идеи / особенности & трудности

Deno

Меня очень вдохновляют deno и deno deploy, и хотя моя первая итерация этой системы была написана на Next.js, я хотел бы продвигать использование deno, чтобы людям в конечном итоге не нужно было использовать NPM для использования этой системы.

Astro

Меня также очень вдохновляет Astro, который позволяет смешивать любые библиотеки компонентов. Мне нравится идея не быть привязанным к использованию react навсегда и позволить виджетам быть независимыми от фреймворка.

Легкий дизайн системы

Главный вопрос заключается в том, как спроектировать систему, которая была бы агностичной и в то же время взаимосвязанной?

Мне нравится идея, что кто-то может настроить виджет youtube таким образом, чтобы при нажатии кнопки submit, вместе с обновлением справа от него появлялся виджет Youtube Profile. Как сохранить YoutubeEmbed и YoutubeProfile отдельно, но при этом скоординировать их так, чтобы они могли ссылаться друг на друга?

Персонализация (CSS)

Настройка внешнего вида и настроек. Я немного помешан на tailwind, а react-form-ui не предоставляет схему tailwind. Мне также было бы интересно позволить потребителям редактировать классы этих компонентов. Это тоже трудно решаемая проблема.

Предоставить централизованный вариант?

Модель wordpress? Возможно, платформа позволяет людям зарегистрироваться на .com, где вы можете создать аккаунт и попробовать его, а также позволяет создать свой собственный вариант?

Федерация?

Федерация, фактически позволяющая перекрестное общение между отдельными серверами, вход в систему, pubsub, cookies, лайки и обмен вещами, взаимодействие с пользовательскими данными, все это немного перегружено, но было бы здорово.

IPFS 👀

Мне нравится идея, что виджет может принимать json src из любого места. Теоретически это позволит вам хранить JSON реквизиты на IPFS и предоставлять запись в блог, используя модуль deno для виджета и конечную точку ipfs для данных.

import { BlogPost } https://deno.land/x/reggi@1.0.0/mod.ts

export default BlogPost({
   src: "https://ipfs.io/ipfs/QmT5NvUstoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCx"
});
Вход в полноэкранный режим Выход из полноэкранного режима

Редактирование содержимого «в сети» в сравнении с редактированием «в коде»

Я немного не понимаю, насколько «в коде» мне это нужно. Например, нужна ли мне возможность создавать и редактировать через веб? Это включает в себя разрешения, роли, права собственности, возможно, эта функция появится позже?

Например, вы можете попросить сервер отобразить статью, подобную этой, где сам контент находится в коде:

import { Article } from 'https://deno.land/x/reggi@1.0.0/widgets/Article.ts'
import { server } from 'https://deno.land/x/reggi@1.0.0/server.ts'

export default server({
  widgets: [Article],
  pages: {
    _: Article({
      title: 'Hello World',
      body: `Hi there!`
    })
  }
});
Вход в полноэкранный режим Выход из полноэкранного режима

Или вы можете предоставить ключ ссылки, который будет действовать как апсерт. Если пост существует, он будет извлечен и доступен для редактирования из браузера, если нет, вы можете создать его из Интернета.

import { Page } from 'https://deno.land/x/reggi@1.0.0/widgets/Page.ts'
import { Article } from 'https://deno.land/x/reggi@1.0.0/widgets/Article.ts'
import { server } from 'https://deno.land/x/reggi@1.0.0/server.ts'
import { Postgres } from 'https://deno.land/x/reggi@1.0.0/store/postgres.ts'
import { Google, Login, Logout } from 'https://deno.land/x/reggi@1.0.0/iam/google.ts'

export default server({
  widgets: [Article],
  store: Postgres(),
  iam: Google(),
  widgets: [ Login, Logout ],
  pages: {
    login: Page(Login)
    _: Page(Article({ ref: 'reference-editable-from-browser' }))
  }
});
Вход в полноэкранный режим Выход из полноэкранного режима

Модульное хранилище данных, модульный логин

Это возможная спецификация.

import { Create } from 'https://deno.land/x/reggi@1.0.0/widgets/Create.ts'
import { Page } from 'https://deno.land/x/reggi@1.0.0/widgets/Page.ts'
import { Article } from 'https://deno.land/x/reggi@1.0.0/widgets/Article.ts'
import { YoutubeEmbed } from 'https://deno.land/x/reggi@1.0.0/widgets/YoutubeWidget.ts'
import { CalendarScheduler, CalendarSchedulerId } from 'https://deno.land/x/reggi@1.0.0/widgets/CalendarScheduler.ts'
import { Postgres, WidgetByUuid } from 'https://deno.land/x/reggi@1.0.0/store/postgres.ts'
import { Google, Login, Logout } from 'https://deno.land/x/reggi@1.0.0/iam/google.ts'
import { server } from 'https://deno.land/x/reggi@1.0.0/server.ts'

const creatableWidgets = [Article, YoutubeEmbed]
const CreateWidget = Create(widgets) 

export default server({
  store: Postgres(),
  iam: Google(),
  widgets: [Login, Logout, ...creatableWidgets, CreateWidget],
  pages: {
    login: Page(LoginWidget),
    logout: Page(LogoutWidget),
    new: {
        _: Page(CreateWidget),
        '[widget]': Page(CreateWidget),
    },
    widget: {
        '[uuid]': WidgetByUuid,
    },
    calendar: Page(CalendarScheduler({ ref: CalendarSchedulerId })),
  }
});
Вход в полноэкранный режим Выход из полноэкранного режима

Нет API?

Сейчас я понимаю, что при такой архитектуре нет реального API. Очевидно, что конечная точка с некоторым пользовательским кодом будет существовать для регистрации / выхода из системы, но основная часть модулей, связанных с контентом, будет просто автогенерироваться. Цель может заключаться в том, чтобы спрятать api, сгенерировав большинство из них за вас в большинстве случаев.

Некоторые смежные мысли

thomas 🌻
@thomasreggi
Пытаюсь придумать новую парадигму кодирования / фреймворка / компонентов. Мне нужен импорт компонентов в стиле @deno_land esque. Очень люблю #nocode и интерактивность внешнего интерфейса. Я хочу сайт с компонентами контента, похожими на winamp. 🔥
22:45 PM — 18 Aug 2022

Заключение

Мне нравится идея предоставления компонентов фронтенда и конечных точек бэкенда в одном модуле. Один кусок инкапсулированного программного обеспечения, который служит одной цели.

Это очень полузадуманная идея, и она не до конца проработана. Я был бы рад поговорить об этом подробнее и провести мозговой штурм идей. Не стесняйтесь, обращайтесь!

Томас Реджи

Full-stack веб-разработчик. Безумно влюблен в #javascript.

Оцените статью
devanswers.ru
Добавить комментарий