Как-то я захотел попробовать реализовать одно маленькое клиент-серверное приложение. Реализация в задумке была такая: на клиентской стороне рисуем с помощью какого-нибуть JS-фреймворка окошки, на серверной стороне обрабатываем вызовы с клиента с помощью скомпилированного приложения, написанного например на Go.
Я начал подбирать фреймворк, предоставляющий декларативный интерфейс. В моём представлении он на входе должен получать в максимально упрощённом виде описание содержимого формы (например в формате YAML, JSON, BEMJSON, XML, или даже INF), а на выходе рисовать в браузере красивую форму с работающими элементами управления.
Профессионально я веб-разработкой не занимаюсь и поэтому не ожидал, что надолго застряну на данном этапе.
И статью писать не собирался, но потом подумал, что свежий взгляд со стороны на современные веб-технологии, пусть даже новичка, может быть интересен сообществу. Возможность получить обратную связь опять же…
HTML- и CSS-шаблоны
Всё, что я находил, работало не так как мне хотелось. Я не хочу ничего знать про вёрстку и стили. Я так же не хочу заполнять HTML, как это делается при применении фреймворков типа Bootstrap, Skeleton, MDL и т. д.
Пример кода с использованием Bootstrap:
<div class="input-group mb-3">
<div class="input-group-prepend">
<div class="input-group-text">
<input type="checkbox" aria-label="Checkbox for following text input">
</div>
</div>
<input type="text" class="form-control" aria-label="Text input with checkbox">
</div>
<button type="button" class="btn btn-primary btn-lg btn-block">Block level button</button>
Всё, что я хочу подать на вход, должно быть примерно такого вида:
{
"main": {
"prop":{},
"elements": [
{
"type":"checkbox",
"name":"Использовать что-то",
"style":"classic",
"checked": true
},
{
"type":"button",
"name":"Сохранить",
"style":"outline",
"onclick":"btnsave_onclick"
}
}
}
Ну и чтобы можно было элементы в группы объединять и указывать как должны быть расположены элементы внутри группы: вертикально или горизонтально. Какое там будет оформление, мне не особо важно. Я ожидал найти даже какой-нибудь визуальный редактор окошек, однако — нет.
Сборки технологий
Тогда я попробовал поискать какие-то сборки технологий — кто-то наверняка проложил давно короткий путь и не раз.
И я нашёл что-то похожее на то, что мне нужно: Сайт с нуля на полном стеке БЭМ-технологий.
Пример BEMJSON:
({
block: 'page',
title: 'Hello, World!',
styles: [
{ elem: 'css', url: 'index.min.css' }
],
scripts: [
{ elem: 'js', url: 'index.min.js' }
],
content: [
'Hello, World!'
]
})
Когда я прокрутил примерно 20-й экран текста, а ползунок находился всё ещё вверху, я подумал, что этот короткий путь какой-то длинный. Не пойдёт.
Почитал я кстати про этот БЭМ — суть мне понравилась, да ещё хорошо и доступно описано. Есть разные шпаргалки, например мне понравилась вот эта. Поискал ещё информацию и обнаружил, что не всем нравится технология (например тут и тут). А здесь на мой взгляд изложена суть спорных моментов.
Интересно то, что используя поиск, я кроме БЭМ-а, долго не мог обнаружить более никаких альтернативных технологий. Однако они есть: OOCS (вроде как тот же БЭМ, только попроще), SMACSS, AtomicCSS, CSSinJS (найдено тут).
Node.js
Я тогда подумал, ок, можно отказаться от первоначальной идеи и реализовать серверную часть на скриптовом языке, т. е. попросту использовать nodejs. Это не только модно, стильно, молодёжно, это ещё возможность писать на всех слоях на одном языке. Масса статей опять же (про быстрый старт мне понравилась эта). Если я правильно понял, под него написано бесчисленное количество NPM-пакетов, практически под любые задачи. Есть ещё под это дело такая серьёзная штука, как Electron.
Пример кода страницы с использованием Electron:
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="assets/css/variables.css">
<link rel="import" href="sections/about.html">
</head>
<body>
<nav class="nav js-nav">
<header class="nav-header">
<h1 class="nav-title">Electron <strong>API Demos</strong></h1>
</header>
<div class="nav-item u-category-windows">
</div>
<footer class="nav-footer">
<button type="button" id="button-about" data-modal="about" class="nav-footer-button">About</button>
</footer>
</nav>
<main class="content js-content"></main>
<script>
require('./assets/normalize-shortcuts')
</script>
</body>
</html>
Единственный минус nodejs, что можно написать более производительную вещь, используя Go.
Допустим я хочу использовать nodejs. Есть каталог NPM-пакетов, чтобы можно было выбрать себе что-то подходящее.
Есть пакет, который так и называется forms. Вот пример кода:
var forms = require('forms');
var fields = forms.fields;
var validators = forms.validators;
var reg_form = forms.create({
username: fields.string({ required: true }),
password: fields.password({ required: validators.required('You definitely want a password') }),
confirm: fields.password({
required: validators.required('don\'t you know your own password?'),
validators: [validators.matchField('password')]
}),
email: fields.email()
});
В саму форму это собирается командой reg_form.toHTML();
. Интересный вариант, но не то.
Есть ещё Element, Riot, TotalJS и iView. Это можно добавить к списку из Bootstrap-а, MDL-а и т. д.
Пример кода страницы с использованием Element:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- import CSS -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
<div id="app">
<el-button @click="visible = true">Button</el-button>
<el-dialog :visible.sync="visible" title="Hello world">
<p>Try Element</p>
</el-dialog>
</div>
</body>
<!-- import Vue before Element -->
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<!-- import JavaScript -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script>
new Vue({
el: '#app',
data: function() {
return { visible: false }
}
})
</script>
</html>
Есть ещё Blueprintsjs. Это пожалуй максимально похоже на то, что я искал. Есть возможность настраивать элементы управления по отдельности друг от друга.
Код выглядит как-то так:
/*
* Copyright 2018 Palantir Technologies, Inc. All rights reserved.
*
* Licensed under the terms of the LICENSE file distributed with this project.
*/
import * as React from "react";
import { FormGroup, H5, InputGroup, Intent, Switch } from "@blueprintjs/core";
import { Example, handleBooleanChange, handleStringChange, IExampleProps } from "@blueprintjs/docs-theme";
import { IntentSelect } from "./common/intentSelect";
export interface IFormGroupExampleState {
disabled: boolean;
helperText: boolean;
inline: boolean;
intent: Intent;
label: boolean;
requiredLabel: boolean;
}
export class FormGroupExample extends React.PureComponent<IExampleProps, IFormGroupExampleState> {
public state: IFormGroupExampleState = {
disabled: false,
helperText: false,
inline: false,
intent: Intent.NONE,
label: true,
requiredLabel: true,
};
private handleDisabledChange = handleBooleanChange(disabled => this.setState({ disabled }));
private handleHelperTextChange = handleBooleanChange(helperText => this.setState({ helperText }));
private handleInlineChange = handleBooleanChange(inline => this.setState({ inline }));
private handleLabelChange = handleBooleanChange(label => this.setState({ label }));
private handleRequiredLabelChange = handleBooleanChange(requiredLabel => this.setState({ requiredLabel
}));
private handleIntentChange = handleStringChange((intent: Intent) => this.setState({ intent }));
public render() {
const { disabled, helperText, inline, intent, label, requiredLabel } = this.state;
const options = (
<>
<H5>Props</H5>
<Switch label="Disabled" checked={disabled} onChange={this.handleDisabledChange} />
<Switch label="Inline" checked={inline} onChange={this.handleInlineChange} />
<Switch label="Show helper text" checked={helperText} onChange=
{this.handleHelperTextChange} />
<Switch label="Show label" checked={label} onChange={this.handleLabelChange} />
<Switch label="Show label info" checked={requiredLabel} onChange=
{this.handleRequiredLabelChange} />
<IntentSelect intent={intent} onChange={this.handleIntentChange} />
</>
);
return (
<Example options={options} {...this.props}>
<FormGroup
disabled={disabled}
helperText={helperText && "Helper text with details..."}
inline={inline}
intent={intent}
label={label && "Label"}
labelFor="text-input"
labelInfo={requiredLabel && "(required)"}
>
<InputGroup id="text-input" placeholder="Placeholder text" disabled={disabled}
intent={intent} />
</FormGroup>
<FormGroup
disabled={disabled}
helperText={helperText && "Helper text with details..."}
inline={inline}
intent={intent}
label={label && "Label"}
labelFor="text-input"
labelInfo={requiredLabel && "(required)"}
>
<Switch id="text-input" label="Engage the hyperdrive" disabled={disabled} />
<Switch id="text-input" label="Initiate thrusters" disabled={disabled} />
</FormGroup>
</Example>
);
}
}
Результат выглядит так:
Даже если учесть только последнюю часть: всё-равно как-то не очень лаконично.
metadata.js
Вот ещё нашёл на просторах Сети интересную вещь — metadatajs. Быстрый старт — тут. Данная библиотека обладает избыточным функционалом, а в статье нет на мой взгляд самого главного — описания самой библиотеки. Это есть здесь.
Форму описывать нам предлагают так:
{
"enm": {},
"cat": {
"Номенклатура": {
"form": {
"selection": {
"fields": [
"is_folder",
"id",
"Артикул",
"_t_.name as presentation",
"`cat_КлассификаторЕдиницИзмерения`.name as `ЕдиницаИзмерения`",
"`cat_НоменклатурныеГруппы`.name as `НоменклатурнаяГруппа`"
],
"cols": [
{"id": "id", "width": "120", "type": "ro", "align": "left", "sort": "server", "caption": "Код"},
{"id": "Артикул", "width": "150", "type": "ro", "align": "left", "sort": "server", "caption": "Артикул"},
{"id": "presentation", "width": "*", "type": "ro", "align": "left", "sort": "server", "caption": "Наименование"},
{"id": "ЕдиницаИзмерения", "width": "70", "type": "ro", "align": "left", "sort": "server", "caption": "Ед"},
{"id": "НоменклатурнаяГруппа", "width": "170", "type": "ro", "align": "left", "sort": "server", "caption": "Номенклатурная группа"}
]
}
}
},
"ДоговорыКонтрагентов": {
"form": {
"selection": {
"fields": [
"is_folder",
"id",
"_t_.name as presentation",
"`enm_ВидыДоговоров`.synonym as `ВидДоговора`",
"`cat_Организации`.name as `Организация`"
],
"cols": [
{"id": "presentation", "width": "*", "type": "ro", "align": "left", "sort": "server", "caption": "Наименование"},
{"id": "ВидДоговора", "width": "150", "type": "ro", "align": "left", "sort": "server", "caption": "Вид договора"},
{"id": "Организация", "width": "150", "type": "ro", "align": "left", "sort": "server", "caption": "Организация"}
]
}
}
}
},
"doc": {
"ЗаказПокупателя": {
"form": {
"selection": {
"fields": [
"date",
"number_doc",
"Контрагент",
"СуммаДокумента",
"posted",
"СостояниеЗаказа",
"Комментарий"
],
"cols": [
{"id": "date", "width": "120", "type": "ro", "align": "left", "sort": "server", "caption": "Дата"},
{"id": "number_doc", "width": "120", "type": "ro", "align": "left", "sort": "server", "caption": "Номер"},
{"id": "Контрагент", "width": "170", "type": "ro", "align": "left", "sort": "server", "caption": "Контрагент"},
{"id": "СуммаДокумента", "width": "120", "type": "ron", "align": "right", "sort": "server", "caption": "Сумма"},
{"id": "СостояниеЗаказа", "width": "100", "type": "ro", "align": "left", "sort": "server", "caption": "Состояние"},
{"id": "Комментарий", "width": "*", "type": "ro", "align": "left", "sort": "server", "caption": "Комментарий"}
]
},
"obj": {
"head": {
" ": ["number_doc", "date", "ВидОперации", "Организация", "Контрагент", "Договор"],
"Планирование": ["СостояниеЗаказа", "Старт", "ДатаОтгрузки"],
"Дополнительно": ["Проект", "Касса", "Событие", "НалогообложениеНДС", "СуммаВключаетНДС", "Ответственный", "Комментарий",
{"id": "СуммаДокумента", "path": "o.СуммаДокумента", "synonym": "Сумма документа", "type": "ro"}
]
},
"tabular_sections": {
"Запасы": {
"fields": ["row","Номенклатура","Характеристика","Количество","ЕдиницаИзмерения","Цена","ПроцентСкидкиНаценки","Сумма","СтавкаНДС","СуммаНДС","Всего","ДатаОтгрузки","Спецификация","Содержание"],
"headers": "№,Номенклатура,Характеристика,Колич.,Ед,Цена,% Скидки,Сумма,% НДС,НДС,Всего,Отгруз.,Спецификация,Содержание",
"widths": "40,*,*,70,50,70,70,70,70,70,70,70,70,80",
"min_widths": "40,200,140,70,50,70,70,70,70,70,70,70,70,80",
"aligns": "",
"sortings": "na,na,na,na,na,na,na,na,na,na,na,na,na,na",
"types": "cntr,ref,ref,calck,refc,calck,calck,ron,refc,ron,ron,dhxCalendar,ref,txt"
}
}
}
}
}
},
"ireg": {},
"areg": {},
"dp": {},
"rep": {},
"cch": {},
"cacc": {}
}
Это очень похоже на то, что нужно. Однако возникают вопросы: набор кнопок похоже задан по умолчанию? Можно ли его менять? Где описание синтаксиса (что такое "enm", "cat" и т. д.)?
Видно, что на проект много усилий вложено, но библиотека пока сыровата.
Заключение
Давайте порассуждаем. Формочки можно заранее нарисовать на сервере, скомпилировать и отдавать на сторону клиента готовый html/css/js-код. В этом случае нужно искать совсем другое. Но если мы хотим, чтобы пользователь работал у нас в одном окне браузера, и в этом окне видел дочерние окна веб-приложения, не было бы логичным закешировать css/js-код на клиенте, который будет получать от сервера короткие команды с описанием очередной формочки и будет рисовать их за счёт ресурсов клиента?
Коллеги, где вы прячете фреймворк с декларативным интерфейсом? )
Он должен быть! Почему я не могу его найти?
Комментарии (83)
alemiks
04.04.2019 19:22вот это от mozilla посмотрите github.com/mozilla-services/react-jsonschema-form
centerv
04.04.2019 19:26+1Долгие поиски решения задачи подобной вашей, что успешно завершились Ruby on Rails + EmberJS (ember-paper). Это просто супер кайф от разработки и производительность, после VueJS, ReactJS и тем более Angular. Минимум пишешь, максимум получаешь. Сорян если, кто не пробовал… я все перепробовал… увы...
JustDont
04.04.2019 19:55+2Такого фреймворка нет, и он не появится. В подобных вещах появляется смысл только на более узком пространстве задач (я сейчас по долгу службы как раз один такой пишу, именно для узкого пространства, с получением профита через стандартизацию отдельных мест).
«Фреймворк для генерации UI» — именно в таком, максимально широком виде — это всё те самые HTML+CSS+JS. Генерируй себе по самое нехочу. Когда появляется желание на чем-то сэкономить и уменьшить сложность — нужно очень четко представлять, что именно вы хотите сэкономить, и где конкретно уменьшить сложность; потому что каждое уменьшение сложности — это еще и сокращение функционала, уменьшите не там — получите прикольную бесполезную штуку, с помощью которой попросту нельзя сделать то, что вам хочется.
Вам нужно генерировать формочки? Это задача типичного кровавого энтерпрайза, которую на голом энтузиазме вряд ли кто-то кинется решать. Вам остаётся либо написать это самому, либо заплатить тому, кто напишет. Вон, вы уже нашли 1Сников, которые для 1С формочки генерят, заинтересуйте их — и, думаю, они вам и в общем виде напишут, без привязки к 1С.gbatrak
05.04.2019 09:22Согласен, что универсальнгого решения нет.
Но есть современные инструменты которые помогут бысторо построить решение для «узкого пространства задач».
Koneru
04.04.2019 20:08+1Для некрофилов есть ExtJS
shsmad
04.04.2019 20:22Всё еще живет и процветает в энтерпрайз среде RIA приложений
Koneru
04.04.2019 20:42Надеюсь они уже подвезли что-то новое. Т.к. полтора года назад ситуация была печальная: он платный + ES5.
dos
05.04.2019 11:45Уже есть GPL и ES6 :)
aleksandy
06.04.2019 21:07GPL был сначала для всех версий, потом только для мажорных, а сейчас дикая Community Edition.
Cadog
04.04.2019 20:49Мне понравился webix.
Есть редактор форм.kurumpa
05.04.2019 19:22Удваиваю вебикс. Часто он «просто работает». Конечно, если нужно что-то сильно кастомное — никаких фреймворков.
dplsoft
05.04.2019 19:56+1все же помнят что он НЕ бесплатный?)))
а то у нас тут один разработчик воткнул вебикс «просто потому что он работает», и очень сильно обижался что я его заставил выпилить это изделие из проекта. или заплатить за него из своего кармана. потому что мы не можем установить клиенту не лицензионное ПО, а 2500-4000 американских денег в бюджете проекта на вебикс у нас на тот момент не было.
хотя да, выглядит он не плохо.
questor
04.04.2019 22:00Автор нашел множество готовых фреймворков (и наверняка их гораздо больше), но они ему чем-то не понравились. В такой ситуации надо продолжать искать дальше, отрабраковывать ещё и ещё, чтобы потом понять, как именно самому нравится и начать велосипедить свой собственный фреймворк. С аутлайнами и фрейлинами.
megahertz
05.04.2019 01:37Давным давно, когда я был молодой и неопытный и за доширак клепал сайты визитки, меня тоже посещала мысль о волшебном фреймворке для всяких crud операций — скармливаем ему метаданные а он нам всякие формочки рисует и данные обрабатывает. Был и свой велосипед, и даже сданные пректы на нем. Вот только чем сложнее были проекты, тем страшнее разрастался велосипед, и все-равно он не мог решать задачи оптимальным образом. И я забросил эту затею.
Чем универсальнее и функциональнее решение, тем выше порог входа и сложнее кастомизировать некоторые чамти. Поэтому надо выбирать, что-то среднее.
По вашему описанию не до конца понятно что именно требуется. Если вам действительно окошки — то это скорее к extjs, несмотря на то что это уже позавчерашний день. Если по большей части crud — присмотритесь к react admin. Ну и раз прошли такой большой путь в поисках присмотритесь к классике проверенной временем — django. Не совсем то что вы ищите, но это та самая золотая середина.
Brightori
05.04.2019 01:59Чем универсальнее и функциональнее решение, тем выше порог входа и сложнее кастомизировать некоторые чамти. Поэтому надо выбирать, что-то среднее.
очень согласен с этой частью )vintage
05.04.2019 05:51И тем не менее это не так. Да, высокоуровневая, но кастомизируемая система — редкая птица. Но не невозможная.
epishman
05.04.2019 04:10Метаданные не удается описать декларативно, потому что нужно учесть поведение. Раньше считали, что можно отделить описание интерфейса и поведение (HTML/JS), теперь понимают, что это неотделимо, и возникли всякие реакты с дартами, где вся разметка перекочевала в скрипт. Проще описать структуру классов на том же JS, чем всякий валежник типа XML/JSON. Программизм не умрет.
vintage
05.04.2019 05:55Всё прекрасно отделимо. Просто фейсбук написан на пхп, поэтому они нанимают пхпшников, у которых, за что ни возьмутся, получается пхп.)
epishman
05.04.2019 11:10Dart тоже писали PHP-шники? Я сам честно пробовал, но не получается отделить в нормальном динамическом SPA, где поведение определяет интерфейс, а не наоборот.
vintage
05.04.2019 13:27Dart тоже писали PHP-шники?
Вы наверно имели ввиду Flutter? Они просто следуют за трендами в этом вопросе.
Я сам честно пробовал, но не получается отделить в нормальном динамическом SPA
Гляньте $mol. Там всё отделено. И есть так желанное вами наследование и переопределение чего угодно.
Alexufo
05.04.2019 16:01дарты возникли потому что в js есть тьма нюансов, которые надо помнить.А дарт попытался сделать язык с понятным поведением где не будет столько свободы воли в реализации тех же классов, которые в разработке либ каждый городит как ему кажется правильнее.
babylon
06.04.2019 17:50дарты возникли потому что в js есть тьма нюансов, которые надо помнить
До этого понятное поведение было у ActionScript. Но была зависимость от песочницы. Поэтому возник dart
dplsoft
05.04.2019 05:59имхо, автор вопрос ставит не верно.
без полновесной системы метаданных, увязывающей как бд так и шаблонизатор — не выйдет, имхо.
а это задача куда больше чем «фреймворк для генерации формочек».
что бы генерировать типовую форму ввода/просмотра вам надо держать в синхронизации и структуры данных с типами, и описания того как вам это отображать (тупо какой контролс использовать для какого типа и когда), и еще иметь механизм не только построения форм, но и наполнения этих форм данными и получения данных обратно. не говоря про валидацию.
при этом этот «механизм построения формочек» должен еще уметь расширять бизнес логику работы этой самой формы — под различные варианты алгоритмов валидации.
и это еще не обсуждены вопросы реструктуризации бд и гуи, когда у вас изменятся структуры данных.
силами js -фреймворка это все не решить. это должна быть единая связка между серверной системой с метаданными, орм, механизмом генерации и управления гуи, механизмами действующими на клиенте для отображения этой формы.
создать такое «в популярном подходе», когда у тебя есть некий бек с рест-ушками и есть толстый js — принципиально невозможно или крайне затруднительно как по затратам так и идеологически — просто потому бек и фронт в современных «модно-молодежных подходах» к разработке разделяются или даже, по сути, противопоставляются — у вас практически нет производителя который бы все связал в единое целое.
есть плагины гуи-фреймворков для ноды, но это, имхо, больно уж походит на франкенштейна, взаимодействие все равно остается ращорванным рест-сервисами, а генерации гуи по метаданным нет.
из того что связывает «воедино фронт и бек» вспоминается только 1с и qt (которые могут собрать приложение и в виде сервера с веб формой управляемой через вебсокет. но у qt нет метаданных связанных с орм и генерацией гуи. собственно, и орм то в свое время для qt я писал сам)
не стоит этого ждать решений такого рода от массовых фреймворков заточеных под массовый веб-js-девелопмент «бложеков и вконтактиков» и потому, что эта область просто не содержит задач такой сложности — требующей генерации интерфейса работы с данными. потому не ищите js-фреймворков.
не под автоматизацию бизнес-процессов они все заточены.
т.е. все они «муссируют» идею массового веба, простых процессов и максимальной разгрузки сервера с выносом бизнес процессов на клиента. именно в этой области работают большая часть тех, кто голосует «фреймворк не нужен, учитесь пользоваться тем что дают»)) и не стоит удивляться что таковых в пересчете на число душ — большинство.
но помимо массового веб, есть корпоративный веб. который по сути вебом не является. это бизнес системы, а веб-интерфейс у них только как дань моде и доступен он в интранете и только.
и вам, имхо, надо искать решение в этой области, когда у вас нет массового доступа к системе, сложные бизнес процессы со сложной валидацией данных.
именно тут вам часто нужно генерить многие формы автоматически, потому что они типовые: когда у тебя 20 справочников различающихся только атрибутами — рисовать под них формы просмотра, редактирования и т.п. руками — часто тупо геморройно.
теперь что есть: из схожего — есть изделия «кровавого интерпрайза» от hp / ibm / etc, но с этими монстрами встречаться не хочется. костылей там много, и это что ни на есть тот самый кровавый интерпрайз который тянется из ранних эпох становления веб-интерфейсов и даже самих идей работы с метаданными.
из менее крового и достаточно функционального — идейно смотрите на систему метаданных 1С, аналогов которой имхо, все таки ни у кого нет. даже той системы метаданных какая была в 7.7.
к достоинствам 1С скажу что часто вознкают учетные задачи и вот чего точно не хватает в java-фреймворках — это не только их системы метаданных, но и их учетных механизмов — тех-же регистров.
я бы очень хотел видеть такое например в java но увы, ничего кроме собственных наработок нет, а публиковать наши фрейворки мы не будем как минимум еще полгода, тем более бесплатно.
и до 1С мы во многом не дотягиваем, хотя нам пока вроде хватает — мы освоили метаданные, орм, основы автогенерации форм, шаблонизацию, работу с клиентом и с генеренными формами и тп.
но т.к. это не будет публично еще какое то время — потому, увы — «пилите сами», тем более если на go. смотрите как работает механизм метаданных в 1С и думайте как это увязать в классическую клиент серверную архитектуру. у меня на то что бы получить более-менее стройный вариант для веб — ушло несколько попыток. и несколько лет )
ну вот как-то так.)
VolCh
05.04.2019 09:54Не согласен, что системах, которые ищет автор, должен быть ОРМ и вообще они что-то должны знать о хранилище. Если и должна быть какая-то генерация кода для сервера из общих с фронтом метаданных, то она должна остановиться на генерации DTO и возможности его провалидировать. Как обрабатывать валидные DTO — полная ответственность бэка.
PaulMaly
05.04.2019 10:28Вы это все к чему?
VolCh
05.04.2019 10:32без полновесной системы метаданных, увязывающей как бд так и шаблонизатор — не выйдет, имхо.
PaulMaly
05.04.2019 11:30Сорян, это у меня в мобильном приложении высветилось будто вы ответ дали на мой коммент где об этом вообще речи не было. В прилаге Хабра комменты часто бажут. (((
dplsoft
05.04.2019 11:50вот вы тоже противопоставляете фронт и бек))
и я не говорил что классический фронт должен что то знать о том как классический бек хранит информацию или наоборот. они по прежнему могут делать это без оглядки друг на друга, но что бы синхронизировать и сработаться — им нужна третья сторона. в обычном программировании роль синхронизатора выступает архитектор/разработчик с его «высшим пониманием», в системах с метаданными — записи метаданных (а архитектор/разработчик в идеале изменяет уже только метаданные)
сервер по прежнему отвечает за корректность обработки. а фронт за корректность отображения.
но откуда им обоим, если не из метаданных, взять информацию об объекте, что бы
1) фронт мог иметь систему генерации форм, способную автомтически сгенерировать форму для отображения любого ифн.объекта в системе?
2) а бек мог корректно это отработать?
я не говорил что фронт должен знать о том, как я говорю про то что универсальные механизмы и бека и фронта должны уметь обработать объект о котором они буквально секунду назад ничего не знали.
если вы делаете только генерацию форм по метаданным, но не делаете орм в беке, который по метаданным умеет сохранить объект в бд — то вы замучаетесь руками подтягивать одно к другому.
кроме того, идея о том, что объект должен сам уметь себы хранить в бд — она валидна только для отдельных архитектур (простите не помню названия этого подхода).
например — скажите — откуда объект должен знать как ему собирать или размещать себя в хранилище типа datavault? это ответственность хранилища, точнее орм, который знает правила «трансляции» записей метаданных на «физику» хранилища.
VolCh
05.04.2019 13:30Я к тому, прежде всего, что форма — самодостаточный инф. объект в системе, особо от других объектов независящий и чаще всего не требующий хранения в базе или ещё где. Отправка формы на бэк — это не создание или изменение каких-то связанных объектов, а создание на бэке временного объекта «форма» и её дальнейшая обработка. UserForm ничего не знает об User, а он о форме. Об обоих знает какой-то UserFormHandler, который может тупо 1:1 копировать данные формы в «настоящий» объект и с помощью ORM сохранять его, а может делать что-то совершенно другое. Но фронта это никак не касается, он от объекта User изолирован полностью.
dplsoft
05.04.2019 15:23Давайте ещё раз проговорим)
мы же, в контексте топика не о «классических подходах», а говорим в первую очередь о _генерации_ форм?
т.е.продолжая термины вашего примера — у вас не будет никакого UserForm.
У вас будет AutoGeneratedForm. один на всех.
AutoGeneratedForm — универсальный механизм. угловатый но предоставляющий приемлемый минимальный уровень работы со всеми сущностями.
механизм который умеет динамически себя перестраивать под тот объект который ей передали.
Хотите — передавайте ей User, хотите — AccountingYearReport, хотите — OperationLogElement — она сама перестроится и отобразит это на экране.
Т.е. идея такая: вы один раз написали такую универсальную форму, и после этого практически забыли о типовых CRUD-механизмах работы с сущностями в GUI (просмотр списка, просмjтр карточки, сортировка, выборка, редактирование).
Теперь к вам вопрос: каким образом реализовать такую систему?
т.е. я с вами согласен что непосредственно связывать их — это глупая идея.
и правильный, имхо, ответ на поставленную задачу такой:
И над сущностями User/AccountingYearReport/OperationLogElement и над AutoGeneratedForm висит «домокловым мечом» система метаданных, которая по мере необходимости дает и той и другой стороне (и фронту и беку) необхоимую информацию о том, как работать с передаваемой сущностью.
детали реализации — будет у вас хендлер или что то ещё, будут у вас метаданные храниться в объекте или централизованно — это уже не важно. Важно что и информационная сущность, и форма синхронизируются (или сопоставлены если хотите) через третью сущность — метаданные.
VolCh
05.04.2019 16:34Генерация бывает разной. У нас может быть UserForm.yaml с метаданными и автоматически сгенерированные UserForm.js, UserForm.go и т. п. Обычно что-подобное имеют в виду, когда говорят об генерации.
То есть идея такая: есть файл с метаданными и есть утилита, которая генерирует код для конкретных форм по метаданным, и для фронта, и для бэка. Не универсальная форма, которой в рантайме скармливаются разные метаданные, а утилита.
Ну и пока до этого я говорил исключительно о формах, то есть об карточке в ваших терминах, если правильно их понимаю.dplsoft
05.04.2019 20:08+1кодогенерация — это изменение процесса сборки, или доп. ручной труд по поддержке скриптов пересборки объектов при расширении структур данных и их запуску. это не всегда приемлемо.
также это потребует пересборки всех компонент проекта при любом изменении структур данных.
хотя это тоже вариант. работаем же с «wsdl-вебсервисами» в джаве аналогичным образом ?))) работаем.
но лично я предпочитаю рантайм решения для генерации интерфейса.
ну и это расширяет области применения такихьмеханизмов. это позволит например создать конфигуриемый на лету механизм пользовательских карточек, что иногда нужно в Ынтерпраз.
так же, мне не нравится сама идея «форм собираемый в компайл тайм», хотя бы потому, что много с этим наелись в jsf. не самый элегантный, имхо подход, но для своего времени и многих областей — пригодно.
vintage
05.04.2019 13:31не делаете орм в беке, который по метаданным умеет сохранить объект в бд
Если использовать не реляционную, а объектную субд, то и Объектно-Реляционный Маппинг и не потребуется.
dplsoft
05.04.2019 15:41+1с объектно ориентирвоанными БД тоже много засад. правильная объектная БД должна уметь валидировать объекты которые ей подсовывают.
т.е. в идеальном варианте — например поддерживать механизм типа XSD или хотя бы на крайний случай JSON Schema или им подобным.
Если она не делает этого, то эти вопросы потребуется решать вам, в вашей сситеме.
и хорошо если вы их решаете, и при переходе с версии на версию успешно решаете проблемы конвертации старых обхектов в новые форматы и структуры или поддерживаете все механизмы отображения данных в вашей обхектной бд начиная с начала времен.
но если у вас объхектная СУБД не умеет валидировать данные (как например очень популярная легковесная MongoDB), а пишут в эту БД несколько систем, особенно если они от разных команд или производителей — то вы рано или поздно получите проблему когда вы с вашими коллегами ассинхронизируетесь в понимании как разбирать структуры в вашей бд.
т.е. объекты у вас будут, но понять что они означают вы не сможете. потому что давно потеряли информацию о том что записано и как трактовать эти json-структуры.
Если вам интересны примеры — сошлюсь на проект разработки первой версии ЕГРН для Росреестра давностью года 3 назад. Тамошние/тогдашние подрядчики создали именно такую ситуацию — в могно-дб лежали настолько разношерстные данные, что написать бота, который бы вытащил из этой БД хоть какие-то полезные данные было совершенно невозможно. и произошло это, по моей версии, как раз из за того что писали данные туда 2 системы, структуры данных развивались, а сама монго-дб не умела хоть как-то вализировать присылаеый ей мусор.
— ну так вот. я к тому, что метаданные для объектно ориентирвоанных БД или ОРМ которые скрывают работу с объектными БД — тоже нужны.
Только играют они иную роль и по другому выглядят, по другому называются.
XSD, Json-schema и тп — становятся неотъемлемой частью системы метаданных если вы используете объектныю бд на больших долгоживущих проектах.
epishman
05.04.2019 11:16Развитое ООП решает вопрос с метаданными, где сам класс является единицей метаданных, и сам умеет сохранять себя в БД. Это пока не очень популярно, после провала объектных БД, еще MVC рулит, но все к этому пониманию медленно возвращаются.
dplsoft
05.04.2019 11:35на один ооп язык не предоставляет вам информации о том, как надо отображать объект.
потому вам надо что то дополняющее те метаданные которые вы можете вытащить например через рефлекшен в java, через систему метаданных в Qt или другие механизмы в вашем языке.
например вам надо отображать поле с типом Integer. какой контролс следует использовать системе генерации «формы редактирования по умолчанию» — поле ввода с калькулятор-дроп-дауном, поле со стрелочками вверх-вниз как в хроме, или может быть скроллер для повышения визуальности? где указать допустимые для ввода границы что бы еще на этапе ввода отсечь нежелательные значения?
метаданные синхронизируют в этих вопросах поведение универсальных механизмов MVC. метаданные, если можно так сказать, выступают 4м элементом, которые позволяют в одном месте указать информацию которой будут пользоваться и «модель», и «контроллер», и «вид». они по прежнему отвечают каждый за свое как и надо в модели MVC, но универсальные механизмы имеющиеся в каждой из этих частей, используют информацию из метаданных для того, что бы работа была синхронизированна.
можедь знала что надо обработать поле с числом типа int, контроллер что надо позволять только отрицательные числа от 0 до -20, а вид — что надо использовать дропдаун с выбором значения.
epishman
05.04.2019 12:44-1Про «ни один ООП язык» — это вы зря, в дарте сделано, да и на JS можно. Смотрите на объект шире — это самостоятельная и живучая сущность, которая сама о себе заботится (CRUD), и сама себя презентует (генерируя HTML/CSS). Если у вас желудок и мозг в пределах одного тела, то почему вы объект пытаетесь разрезать на искусственные сущности контроллер и вью? Я знаю, что мнение непопулярно, но можем вернуться к спору через 10 лет, когда MVC умрет, а ООП будет переосмысленно (строго ИМХО).
dplsoft
05.04.2019 13:01вы говорите что «на js можно поместить в объект информацию о том как его отображать» — я же правил но вас понимаю?
тут 2 момента.
1) вы по сути подтверждаете мой тезис о том, что сам по себе ооп-язык не предоставляет механизмов и правил описания как отображать данные.
2) вы говорите про детали реализации, которые распределяют задачи функциональных подсистем на программные классы систем.
действительнь — почему бы не разместить в объекте его собственный кусочек метаданных, и отнаследовать откуда то кусочек для орм, который дает объекту самому сохраняться в хранилище — почему нет? это не более чем детали реализации тех же сущностей о которых я говорю: объект и метаданные.
только система метаданных у вас организована так, что каждый объект «знает о себе всё».
и я так делал. так был построен мой орм для qt.
но когда мне потребовалось реализовать вариативный орм который имел бы одинаковый н ерфейс и для 3nf бд и для datavault — я использовал другую идеологию.
epishman
05.04.2019 19:57Я понял проблему. Если нужна вариативность вывода HTML или интерфейса к БД, понятно, нужно применять что-то типа паттерна фасад, или там прокси. Стандартно это делают отдельным компонентом (собственно view или model), но есть и другой подход — если все ваши объекты унаследованы от одного предка — достаточно прокси реализовать в этом предке, и весь ваш фасад будет вызовом super(). Это извечный спор о том что лучше — композиция vs наследование, или там микросервисы vs монолит. Конечно, композиция гибче, но монолит предсказуемей и управляемей. И самое главное — в моем случае метаданные тоже могут наследоваться!
JustDont
05.04.2019 13:26У автора (по крайней мере из статьи вырисовывается) нет хорошего понимания о том, что ему нужно — а соответственно, объем работ тут точно так же очень неопределен. У автора есть запрос на «просто», но нет строгого описания (а значит и понимания, скорее всего), что в это «просто» должно входить.
Но это даже не обсуждается, что «фреймворку для генерации формочек» потребуется дополнительная информация — из чего же он эти формочки нагенерит иначе? И заострять внимание именно на этом — ну фиг знает, по-моему излишне. Это и так подразумевается, как например запрос «построить график» подразумевает, что есть данные, по которым его можно строить.
vagon333
05.04.2019 19:42Странно, почему минусуют этот комментарий.
На мой взгляд комментарий по делу:
1. просто фронт нарисовать — поверхностное решение. Желательна поддержка бэка.
В фронт должна идти масса информации от бэка и метаданных: типы данных, формат, валидации. Эта информация уже определена на бэке, так почему ее не транслировать на фронт?
2. аналогично с автором комментария, у меня на решение ушло в общей сложности 8+ лет и сейчас финальная, 4-я редакция, которая основана на метаданных и покрывает фронт и бэк.
Это охрененное количество работы и денег, с подключением экспертов из разных областей.epishman
06.04.2019 00:01+1Комент хороший, но все ж от задачи зависит, у меня например такая была — автономное PWA мобильно-десктопное приложение с локальной БД, и периодической синхронизацией с сервером. Бэка по сути нет вообще, вся валидация и первичное хранение на клиенте, при появлении интернета — простая JSON-репликация по сокету — и нафига мне тут фреймворк с метаданными? А те кто минусуют — может они просто энтерпрайза не видели, и воспринимают 1С как магию…
reb00ter
05.04.2019 06:55есть ещё devextreme — формочки, и вполне себе декларативно.
причем под кучу фреймворков сразу
правда есть два "но":
- платно
- полностью от написания html не избавят
PaulMaly
05.04.2019 08:23Если я все правильно понял, то более всего вашему подходу соответствует pureqml.com
Zam_dev
05.04.2019 10:25-1Пока web, будет выглядеть вот так
<...>
</...>
он не перестанет вызывать у меня изжогу, ничего отвратительнее не видел(
WPF по этой причине долго не мог поднять для себя. Но кодируя контролы в самом коде, как то переборол эти тэги, а потом и вовсе смирился с ними. Но к HTML отношение ни капли не поменялось.epishman
05.04.2019 12:49Предложите лучший вариант описания интерфейса. На SQL столько лет плевались, а все равно ничего лучше не придумали.
Zam_dev
05.04.2019 15:24Вариантов описания интерфейса куча, в частности, почему бы не быть ему как в Ammy
SQL читается как роман по сравнению с тегами:) А все что рябит в глазах, это зло.epishman
05.04.2019 20:20Я на эту тему как-то тут спорил, говорил что JSON лучше XML потому что рябит меньше, но товарищи верстальщики меня решительно поправили — закрывающие тэги удобнее, чем каскад закрывающихся скобок, так как видно что конкретно закрывается. Возможно, они даже правы, хотя конечно на JS удобнее описывать поведение, ибо лямбды внутри HTML смотрятся как-то чужеродно. Так что частично с Вами согласен, но браузеры как и страну не выбирают…
JustDont
05.04.2019 21:47</treeLevel> </treeLevel> </treeLevel> </treeLevel> </treeLevel>
Ну да. Прям видно. Прям нагляднейше. Ни за что бы не подумал, но раз эксперты говорят… ;)
gearbox
05.04.2019 12:50+1const response = { "main": { "prop":{}, "elements": [ { "type":"checkbox", "name":"Использовать что-то", "style":"classic", "checked": true }, { "type":"button", "name":"Сохранить", "style":"outline", "onclick":"btnsave_onclick" } } }; const domArray = response.main.elements.map(elInfo => { const domEl = document.createElement(elInfo.type); return Object.keys(elInfo).reduce((el, key) => { if (key === 'type') return el; el.setAttribute(key, elInfo[key]); return el; }, domEl); };
полученный массив вставляем куда надо. Фреймворка такого нет потому что никто не будет десять строк оформлять во фреймворк.JustDont
05.04.2019 13:18+1полученный массив вставляем куда надо
Лейаута нет, где должна быть логика (обработчики) — непонятно, и т.д.
Ваши 10 строк просто позволяют хранить HTML в JSON. Нужно это примерно никому (зачем хранить HTML где-то еще, если можно хранить его прямо так?), поэтому и не оформляют.gearbox
05.04.2019 20:07как задача поставлена — так она и решена. Безотносительно рациональности самой задачи.
epishman
06.04.2019 00:04У него же не JSON, а объект JS, там можно и функции хранить, и вставлять вызовы при генерации разметки, нормальный подход.
gearbox
07.04.2019 16:16предполагается что response пришел по сети, то есть все таки json, но функции так можно передавать, главное что бы они были автономными (то есть все используемые в них символы — либо глобальны для js либо приходят в параметрах). Прикручивается при помощи еще пары строк. + еще пара строк — и можно сделать elements рекурсивными, то есть отражать в них вложенные элементы. Не стал этого писать потому что смысла нет, так же как и (на мой взгляд) смысла в поставленной задаче. Есть html templates/jsx/tsx, есть custom elements/react/vue/angular, в общем куча инструментов работающих на уровне view, выбирай на любой вкус. И вопрос декларативности на любом выбранном инструменте решается таким же десятком строк что я привел.
epishman
07.04.2019 19:06Спасибо, понятно. Я не поклонник фреймворков по одной причине, о которой вчера как раз думал — а именно производительность. Вообще-то браузеры идеально оптимизированы для отображения HTML, но на каком-то этапе сообщество решило генерировать DOM из скриптов, причем по одному элементу, по сути перестав использовать нативный язык описания интерфейса — HTML. Хоть Дарт, хоть Реакт — везде компоненты добавляются прямо в DOM, и фреймворки сразу попали в ловушку низкой производительности, которую сами и создали. В результате пришлось изобретать виртуальный DOM, единое состояние redux и прочие костыли. Я провел эксперимент, и пришел к выводу, что возвращение к текстовому HTML (в частности insertAdjacentHTML) улучшает производительность в десятки раз. После этого я охладел к объектному подходу, и по прежнему генерирую большие куски HTML в виде текста. Эта ситуация очень похожа на судьбу объектных оберток поверх SQL, которые тоже тормозят, и в высоконагруженных системах не используются. Впрочем, об этом надо статью писать, но лень.
vintage
07.04.2019 22:36-1Попробуйте на чистом html вставить в каждую ячейку селект на сотню-другую опций.
epishman
07.04.2019 23:24Какая-то гипотетическая ситуация. Зачем в каждую-то, может только в активную, и то после набора первой буквы? В моем примере в дрилл выводиться до 50 тысяч строк таблицы, одним куском HTML, а для редактирования нужно просто кликнуть на ссылку. Если бы я все делал через DOM — ждал бы до утра.
JustDont
08.04.2019 01:53Вы только не забывайте, что с «гипотетической ситуации» вы сами начали.
В браузере в 99.8% случаев не надо выводить таблицы на десятки тысяч строк. Браузер, как чисто презентационный движок — работает с такими объемами информации, с которыми удобно работать человеку. За подавляющим большинством ситуаций а-ля «я фигачу в HTML таблицы на 100500 экранов размером и чёт они у меня тормозят» стоит банальное неумение построить UI с более адекватным охватом, или же в крайнем случае — организовать разбивку на части.
Да, есть и 0.2% случаев, где безумные объемы данных в браузере таки нужны одним куском. И да, в этих случаях вам действительно не стоит брать реакт, да и вообще по большей части и JS брать тоже не стоит. Но эти случаи мягко говоря нишевые.
vintage
08.04.2019 08:58Зачем в каждую-то, может только в активную, и то после набора первой буквы?
Затем, что нативный селект не умеет ни в ленивый рендеринг, ни в фильтрацию. И вот, нам уже нужен кастомный контрол и фигурная работа с DOM, чтобы при ререндере селекта он не закрывался.
epishman
08.04.2019 09:32Поэтому никто в автоподборе и не использует select, менюшка прекрасно на nav position absolute делается. Согласен, это отдельный custom element, и ни одного фреймворка.
vintage
08.04.2019 09:59Прекрасно ровно до тех пор пока вам не надо динамически менять содержимое менюшки, чтобы она могла выпадать за пределы окна браузера, чтобы она позиционировалась так, чтобы не вылезать за границы экрана. И куча других совсем не прекрасных вещей.
epishman
08.04.2019 10:59Я согласен, гемор, хотя сейчас с появлением viewport-единиц вычисление размеров и позиций стало проще, но кроссбраузерности по прежнему нет :(
gearbox
08.04.2019 19:25>Хоть Дарт, хоть Реакт — везде компоненты добавляются прямо в DOM, и фреймворки сразу попали в ловушку низкой производительности, которую сами и создали.
Я прикручивал биндинги к custom elements — получается тот же реакт только без головняков по оптимизации рендеринга, этим занимается броузер и не надо велосипедить. Небольшой проект по работе запустил — полет нормальный. Но средние и больше проекты не рискую переводить на эти рельсы — для народа выглядит непривычно, тим лидер смотрит на меня настороженно :)
ivahaev
05.04.2019 15:07Что-то похожее, только фулстек, мы с напарником делали года три-четыре назад для себя — getblank.net. Декларативно определяем схему, по которой строится и фронт и бэк.
Описание с докой не самые актуальные сейчас, т.к. никому кроме нас эта платформа оказалась не интересной, зато сами мы немалое количество проектов выполнили с её помощью.
В данный момент идёт переосмысление проекта, т.к. оказалось, что излишняя гибкость заложена, что привело к усложнению всего.epishman
05.04.2019 20:27Это судьба таких проектов — для себя только и используется. А другой пилит свою ферму, так как о вашей не знает, ведь трудозатраты написать самому vs разобраться в чужом — сопоставимы. И только фейсбук может нагнуть всех силой своего бренда.
vagon333
05.04.2019 17:37Любопытная статья.
Фреймворк не встречал, но последние 3 года разрабатываем командой похожее решение.
Результат более сложный, чем описанный в статье, но некоторые части аналогичны:
1. библиотека элементов (UI Elements), аналог бэмовых Element
2. из UI Elements строятся reusable Page Elements, аналог бэмовых Block
3. из блоков формируется веб-приложение
В добавок (малая толика из возможностей):
1. библиотека UI Elements расширяемая и хранится в базке с соблюдением нормальных форм
2. каждый UI Element описывается через набор: свойств, методов, событий
3. серверная часть также генерится на базе метаданных и позволяет начитывать и сохранять данные
4. на клиентской и серверной части возможны вставки custom code
5. безопасности уделено особое значение — все контролы, действия, кастомные коды контролируются role-based security system.
6. динамическая компиляция серверного custom code и подгрузка к приложению
7. динамическая компиляция daemons (windows services) и deployment на удаленные серверы
8. динамическое создание AWS Lambda и deployment на AWS
9. самое важное: веб-приложение позволяет создавать и модифицировать себя-же, не обращаясь к средам разработки. Звучит утопично, но это так.
10. 2-х уровневое кеширование серверной части (L1 на уровне запроса и L2 на уровне среды с учетом LB deployment)
11. ядро среды написано на .Net из VS и содержит крайне мало кода. В основном — метаданные для описания базки, таблиц, колонок, триггеров, индексов, SP, UI Elements, Page Elements, etc., хранящиеся в базке с соблюдением нормальных форм. Т.е. изменение таблицы, страницы, контрола, etc.
Крайне неловко писать о незаконченном проекте, но уже сейчас мы разрабатываем большую часть функционала из самой среды, не модифицируя ядро.
Может кого-нибудь такой подход заинтересует.
Пишите в личку, буду рад поделиться
Пример UI: ibb.co/hB8Vp2Gvintage
05.04.2019 17:44Выглядит интересно. Я смотрю вы тоже выбрали буклетный дизайн (горизонтальный стек панелей), чтобы приложение имело одинаковый ux что на десктопе, что на мобилке?
vagon333
05.04.2019 17:59Вроде того.
Текущая разметка — частный случай ( ibb.co/d6r8dX4 ) и может быть легко изменена.
Для мобильной версии проще нарисовать странички с функционалом, специфичным для возможностей и задач мобилки.
Diaskhan
05.04.2019 18:26
Lappintade
05.04.2019 21:52dhtmlx.com/docs/products/dhtmlxSuite
Позволяет писать декларативно описывая компоненты через json, xml.vagon333
06.04.2019 05:54Использовал в ранних редакциях. Много унаследованных проблем.
У XB есть новая версия — Webix.
Перешел на Webix и результат значительно лучше.
PolarRaspa
05.04.2019 21:52В свободное время писал такой фреймворк. На собеседованиях всегда просят показать примеры кода, вот и показываю.
www.youtube.com/watch?v=NYqVYc1du3Y
Потрогать можно тут
polarspa.coolpage.biz/demo.html
1div0 Автор
05.04.2019 21:57Ох ёпрст ) намолотили тут за день — не ожидал такого интереса.
Всем спасибо кто откликнулся! В комментах много интересного. Спасибо за ссылки!
По поводу моей нечёткой формулировки того, чего я искал — я имел ввиду, что на входе подаёшь вот такое:
{ "main": { "prop":{}, "elements": [ { "type":"checkbox", "id": "checkbox1", "label":"Использовать что-то", "style":"classic", "checked": true }, { "type":"button", "label":"Сохранить", "style":"outline", "onclick":"btnsave_onclick" } } }
а на выходе получаешь вот такое (страничку с таким содержимым):
Просто визуальщина, всё на простых типах, без бэкэнда. И хотелось OpenSource.
И чтоб можно было вот так:
{ "type":"input-int", "name":"Введите число", "min-val":"1", "max-val":"100", "style":"classic" }
Но повторюсь, в комментах накидали всякого, надо смотреть.
YAZART
06.04.2019 09:25Ну если исключительно для форм то есть такая штука как Formly, например для ангуляру это https://github.com/ngx-formly/ngx-formly удобный, настраиваемый.
evocatus
Если вы захотите эти автогенерируемые формы гибко настраивать (цвет там, шрифт, положение и пр.), то абстрагировать HTML+CSS, хотя это не даст уменьшения количества информации, я не вижу смысла.
Если не боитесь безликого типового внешнего вида, то это довольно несложно и самому сделать, даже на базе обычного Go'шного html/template.
А вообще рекомендую взглянуть на экосистему Clojure/Clojurescript и библиотеку re-frame.