
De alguma forma, eu queria tentar implementar um pequeno aplicativo cliente-servidor. A implementação da idéia foi a seguinte: no lado do cliente, desenhamos janelas usando algum tipo de estrutura JS, no lado do servidor processamos chamadas do cliente usando um aplicativo compilado escrito, por exemplo, em Go.
Comecei a pegar uma estrutura que fornece uma interface declarativa. Na minha opinião, ele deve receber a descrição do conteúdo do formulário o mais simples possível (por exemplo, no formato YAML, JSON, BEMJSON , XML ou mesmo INF) e, na saída, desenhe um belo formulário no navegador com controles de trabalho.
Profissionalmente, não estou envolvido no desenvolvimento da Web e, portanto, não esperava ficar parado por muito tempo nesta fase.
E eu não ia escrever um artigo, mas pensei que uma nova visão externa das modernas tecnologias da Web, mesmo iniciante, poderia ser interessante para a comunidade. Uma oportunidade de receber feedback novamente ...
Modelos HTML e CSS
Tudo o que encontrei não funcionou como eu queria. Não quero saber nada sobre layout e estilos. Também não quero preencher o HTML, como é feito ao aplicar estruturas como Bootstrap , Skeleton , MDL , etc.
Exemplo de código usando o 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>
Tudo o que eu quero aplicar à entrada deve ser algo como isto:
{ "main": { "prop":{}, "elements": [ { "type":"checkbox", "name":" -", "style":"classic", "checked": true }, { "type":"button", "name":"", "style":"outline", "onclick":"btnsave_onclick" } } }
Bem, para que seja possível combinar elementos em grupos e indicar como os elementos devem ser localizados dentro do grupo: vertical ou horizontalmente. Qual será o design lá, não é especialmente importante para mim. Eu esperava encontrar algum tipo de editor de janela visual, mas não.
Montagem de tecnologia
Então tentei procurar por alguns conjuntos de tecnologia - alguém deve ter percorrido um longo caminho por muito tempo e mais de uma vez.
E encontrei algo semelhante ao que eu preciso: um site do zero em uma pilha completa de tecnologias BEM .
Exemplo BEMJSON:
({ block: 'page', title: 'Hello, World!', styles: [ { elem: 'css', url: 'index.min.css' } ], scripts: [ { elem: 'js', url: 'index.min.js' } ], content: [ 'Hello, World!' ] })
Quando rolei a tela 20 do texto, e o controle deslizante ainda estava no topo, pensei que esse caminho curto fosse longo. Não vai dar certo
A propósito, eu li sobre esse BEM - gostei da essência, e ela é descrita muito bem. Existem várias dicas, por exemplo, gostei dessa . Também procurei informações e descobri que nem todo mundo gosta da tecnologia (por exemplo, aqui e aqui ). E aqui, na minha opinião, a essência dos pontos controversos é afirmada.
O interessante é que, usando a pesquisa, além do BEM, por muito tempo não consegui encontrar mais tecnologias alternativas. No entanto, eles são: OOCS (mais ou menos como o mesmo BEM, apenas mais simples), SMACSS , AtomicCSS , CSSinJS (encontrado aqui ).
Node.js
Então pensei, ok, você pode abandonar a ideia original e implementar a parte do servidor em uma linguagem de script, ou seja, simplesmente use o nodejs. Não é apenas moda, estilo, juventude, é também uma oportunidade de escrever em todas as camadas em um idioma. Muitos artigos novamente (gostei deste aqui sobre o início rápido). Se bem entendi, inúmeros pacotes NPM foram criados para ele, para praticamente qualquer tarefa. Ainda há uma coisa tão séria como a Electron nesse negócio.
Exemplo de código de página usando o 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>
Os únicos nós de nó menos que é possível escrever algo mais produtivo, usando Go.
Suponha que eu queira usar o nodejs. Há um catálogo de pacotes NPM para que você possa escolher algo adequado.
Há um pacote chamado forms . Aqui está um código de exemplo:
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() });
Isso é montado no formulário pelo comando reg_form.toHTML();
. Uma opção interessante, mas não é isso.
Há também Element , Riot , TotalJS e iView . Isso pode ser adicionado à lista a partir do Bootstrap, MDL etc.
Exemplo de código de página usando o Element:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <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> <script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/element-ui/lib/index.js"></script> <script> new Vue({ el: '#app', data: function() { return { visible: false } } }) </script> </html>
Há também Blueprintsjs . Talvez seja o mais parecido com o que eu estava procurando. É possível configurar os controles separadamente um do outro.
O código se parece com isso:
Muito código usando blueprints 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> ); } }
O resultado fica assim:

Mesmo se levarmos em conta apenas a última parte: mesmo assim, de alguma forma, não é muito conciso.
Eu também achei uma coisa interessante na Web: metadatajs . Um início rápido está aqui . Essa biblioteca tem funcionalidade redundante e, no artigo, na minha opinião, a coisa mais importante não é - a descrição da própria biblioteca. Está aqui .
Somos oferecidos a descrever o formulário da seguinte maneira:
Descrição do formulário usando metadata.js { "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": {} }
Isso é muito semelhante ao que você precisa. No entanto, surgem perguntas: o conjunto de botões parece estar definido por padrão? Posso mudar isso? Onde está a descrição da sintaxe (o que é "enm", "cat" etc.)?
Pode-se ver que muito esforço foi colocado no projeto, mas a biblioteca ainda está úmida.
Conclusão
Vamos especular. Os formulários podem ser pré-desenhados no servidor, compilados e enviados para o cliente, prontos para html / css / js-code. Nesse caso, você precisa procurar algo completamente diferente. Mas se quisermos que o usuário trabalhe conosco em uma janela do navegador e nessa janela veja as janelas filho do aplicativo Web, não seria lógico armazenar em cache o código css / js no cliente, que receberá comandos curtos do servidor com uma descrição do próximo formulário e irá atraí-los à custa dos recursos do cliente?
Colegas, onde você oculta a estrutura da interface declarativa? )
Ele deve ser! Por que não consigo encontrá-lo?