Olá pessoal!
Este artigo recente me
levou a escrever esta publicação (eu a vi ontem).
Recontar os principais recursos do Headless / conteúdo primeiro / API primeiro, etc. Não serei CMS, o material está cheio e provavelmente muitos já estão familiarizados com essa tendência. E quero lhe dizer por que e como escrevo meu sistema, por que não pude escolher entre os existentes, o que penso sobre outros sistemas que já encontrei antes e quais são as perspectivas para tudo isso. A ficção será volumosa (para o material em dois anos), mas tentarei escrever mais interessante e útil. Quem se importa, por favor, debaixo do gato.
Em geral, a história é realmente longa e tentarei contar primeiro. Para deixar mais claro quais são as verdadeiras razões para a criação de seu próprio mecanismo, ou simplesmente porque sem isso será difícil explicar por que estou fazendo dessa maneira, e não de alguma maneira.
Mas, para começar, vou escrever brevemente os principais critérios de seleção para o CMS moderno sem cabeça para mim pessoalmente, por que ainda não consegui escolher uma solução pronta para mim.
Só para que as pessoas não parem de ler muitas faias, sem entender o que será dito.Resumidamente: queria que tudo estivesse em um só lugar: na parte de trás e na frente (e não isso ou aquilo), e a API do GraphQL, e que o banco de dados fosse gerenciado e muito mais, incluindo o botão "Make Beautiful". Eu não encontrei isso. Também eu também não fiz isso, mas, no geral, ficou bastante e, o mais importante, me permite fazer projetos reais.
E assim, minha abordagem dificilmente pode ser chamada de científica e justificada. O fato é que geralmente geralmente escrevo algo próprio. Eu gosto de programar aqui. E dois anos atrás (e antes disso outros 8 anos), sentei-me no MODX CMF (no qual também inventei muitas das minhas muletas). Por três anos, iniciamos um projeto de grande escala, no qual, ao que me parecia, eu poderia usar o MODX. Mas, como se viu, não pude ... O principal motivo foi que era uma startup sem requisitos técnicos, com um monte de idéias que mudavam e eram complementadas todos os dias (e várias vezes ao dia). E agora, toda vez que, sob uma nova idéia, era necessário adicionar uma nova entidade, registrar / alterar campos para os existentes, criar / excluir / alterar relacionamentos entre essas entidades (respectivamente, com uma alteração na estrutura do banco de dados), eu tenho em algum momento Começou a demorar várias horas para mudar essas entidades. De fato, além de ser necessário registrar essas alterações no esquema, era necessário alterar o banco de dados (quase manualmente), atualizar a API, reescrever o código do programa etc. etc. Consequentemente, a frente teve que ser atualizada sob tudo isso. Como resultado, decidi que deveríamos procurar algo novo, mais conveniente, que de alguma forma simplificasse tudo isso. Esclareço mais uma vez que naquela época eu era um back-end php, então não se surpreenda ou ria que comecei a descobrir vários construtores de front-end, menos processadores, npm etc. etc. Mas de qualquer maneira, gradualmente em nosso projeto, uma frente apareceu em react + less, uma API no GraphQL e um servidor no express.
Mas nem tudo estava tão róseo quanto parece para muitos agora. Deixe-me lembrá-lo, isso foi há mais de dois anos atrás. Se você está na web JS moderna há menos de dois anos, recomendo a leitura deste artigo:
N razões para usar o aplicativo Create React (habr). Muito preguiçoso, brevemente: com o advento dos scripts de reação, você não pode se preocupar em configurar o webpack, etc. Tudo isso entra em segundo plano. Caras já configuraram o webpack para garantir que quase todos os projetos de reação trabalhem nele, e o desenvolvedor final se concentrou diretamente na programação do produto final, em vez de configurar várias dependências, carregadores etc. Mas isso é mais tarde. E antes disso, eu apenas tinha que configurar este webpack, seguir a atualização de um monte de tudo o que voava com ele para alcançá-lo, etc. etc. Mas isso é apenas parte do trabalho, apenas essencialmente a frente. E você também precisa de um servidor. E você também precisa de uma API. E você também precisa de SSR (renderização do lado do servidor), que, a propósito, o react-script ainda não fornece, tanto quanto eu sei. Em geral, tudo estava muito mais complicado do que agora, não havia muito e todo mundo se agachava da melhor maneira possível. E como eu muleta então ...
Imaginem:
- Configuração nativa do webpack separadamente para front e server.
- Implementação própria do SSR, para que o assíncrono funcione normalmente com o servidor de reação, e os estilos imediatamente prontos cheguem e sejam indexados normalmente, e os status do servidor para as páginas não encontradas foram fornecidos.
- Sem redux. Bem, eu não gostei do redux imediatamente. Gostei da ideia de usar meu fluxo de reação nativo (embora eu tenha que reescrevê-lo um pouco para mim).
- Esquemas e resolvedores GraphQL prescritos manualmente, sem implantação automática do banco de dados (o servidor API foi usado como meio para um site MODX).
- Não reage-apollo / apollo-client, etc. Tudo é escrito de forma independente com solicitações através de busca, repositórios em um navegador baseado no fluxo personalizado.
Como resultado: até agora, uma das primeiras versões possui um projeto com mais de 500 participantes e, na temporada (inverno), mil a mil e mil e mil alunos por dia. Uptime 2 meses. Isso ocorre porque eu reiniciei o servidor manualmente após uma atualização de software preventiva. E antes dessa reinicialização, o tempo de atividade era de mais de 6 meses. Mas o mais interessante é o consumo de memória. Atualmente, existem quase 700 megabytes de processo js. Sim, sim, eu também estou rindo com você aqui :) Claro, isso é muito. E antes disso eu fiz um pouco de prevenção e aprimorei esse indicador. Anteriormente, havia um total de 1000M + por processo ... No entanto, funcionava e era bastante tolerável. E antes que o
Google alterasse os algoritmos do PageSpeed Insights em novembro, o site tinha uma métrica de desempenho 97/100.
ProvaUma conclusão intermediária baseada neste projeto, baseada em um sistema que se desenvolveu mais sem esse projeto (o projeto foi deixado para trás):
Prós- A API do projeto tornou-se mais flexível com o uso do GraphQL, e o número de solicitações do servidor foi reduzido significativamente.
- O projeto tem acesso a um grande número de componentes no npm.
- O gerenciamento de projetos se tornou mais transparente através do uso de dependências, git, etc.
- Os scripts e estilos criados são certamente mais agradáveis do que vários scripts separados em sites antigos, quando você não sabe o que pode remover deste zoológico sem consequências (e muitas vezes vê várias versões de um bug em um site).
- O site tornou-se mais interativo, as páginas funcionam sem reinicializar. O retorno às páginas visualizadas anteriormente não requer repetidas chamadas para o servidor.
- A edição de dados ocorre diretamente na página, com o princípio de "editar o que você vê e onde vê", sem nenhum painel de administração separado.
Contras (principalmente para o desenvolvedor)- Tudo é muito complicado. Sério. É simplesmente irreal conectar um desenvolvedor de terceiros ao projeto. Eu mesmo mal conseguia descobrir o que e como funciona e de onde minhas pernas crescem. Se você olhar para a página 3 das vantagens, onde se diz sobre transparência, a transparência é apenas uma vez que, se você conectar algo a algum lugar, poderá ver imediatamente o que está quebrado (scripts não são construídos etc.), mas por commit e diffs Você pode encontrar onde isso viciado. Bem, se você conseguiu adicionar algo novo e funciona, pelo menos você entende claramente que, sim, tudo correu bem. Mas no geral ainda é um inferno infernal.
- Dificuldades com o cache. Mais tarde, descobri o apollo-client para mim. E antes disso, como eu disse, escrevi meus armazenamentos baseados em fluxo. Devido a esses armazenamentos, foi possível obter os dados necessários para renderização de diferentes componentes, mas o volume do cache no lado do cliente era muito grande (cada conjunto de entidades típicas tinha seu próprio repositório). Como resultado, foi difícil verificar se o objeto foi solicitado anteriormente ou não (ou seja, vale a pena fazer uma solicitação ao servidor para encontrá-lo), se todos os dados relacionados estão disponíveis etc.
- Dificuldades com esquemas, estrutura de banco de dados e resolvedores (funções de API para recebimento / modificação de dados). Como eu disse, escrevi esquemas manualmente e resolvedores também. Em que resolvedores, tentei fornecer armazenamento em cache e processamento de solicitações aninhadas e outras sutilezas. Naquele momento, tive que me aprofundar na essência e no código do programa GraphQL. A vantagem é que geralmente entendo muito bem como o GraphQL funciona, quais são seus prós e contras e como prepará-lo melhor. A desvantagem é que, é claro, você não pode escrever todas essas comodidades e pães escritos por comandos como o Apollo em um. Como resultado, quando descobri a Apollo, é claro, comecei a usar seus componentes com muito prazer (mas principalmente na frente, vou lhe dizer o porquê abaixo).
Em geral, esse projeto usando tecnologias desatualizadas é pessoalmente meu em 100%, para que eu possa abandoná-lo até tempos melhores. Mas existem outros projetos para os quais eu tive que ir além e desenvolver a plataforma. E várias vezes tive que reescrever tudo do zero. Além disso, falarei com mais detalhes sobre as tarefas individuais que encontrei e quais soluções desenvolvi e apliquei como resultado.
Esquema primeiro. Primeiro o circuito, e depois todo o restoUm site (interface da web, thin client, etc.) é toda a exibição de informações (bem, gerenciamento de informações, se permitido e funcionalidade permitida). Mas primeiro, mesmo assim, um banco de dados (tabelas, colunas, etc.). Tendo encontrado várias abordagens diferentes para trabalhar com o banco de dados no meu caminho, gostei mais da abordagem Schema-first. Ou seja, você descreve o esquema de entidades e tipos de dados (manualmente ou por meio da interface), implanta o esquema e imediatamente possui as alterações descritas no banco de dados (tabelas / colunas são criadas / excluídas, bem como os relacionamentos entre elas). Dependendo da implementação, você também gerará todas as funções de resolução necessárias para gerenciar esses dados. Acima de tudo, nessa direção, gostei do projeto
prisma.io .
Com sua permissão, já que mesmo no hub eu não vi um único artigo sobre o prisma, chamarei a atenção um pouco, pois o projeto é realmente muito interessante e, sem eles, não teria agora uma plataforma que me deixou tão feliz . Na verdade, foi por isso que chamei minha plataforma de prisma-cms, porque o prisma.io desempenha um papel muito importante nela.
Na verdade, o prisma.io é um projeto SaaS, mas com uma grande ressalva: eles colocam quase tudo o que fazem no github. Ou seja, você pode usar os servidores deles por uma taxa bastante razoável (e configurar seu próprio banco de dados e API em questão de minutos) ou pode implantar totalmente tudo em casa. Nesse caso, o prisma deve ser logicamente dividido em duas partes separadas importantes:
- Prisma-server, ou seja, o servidor em que o banco de dados também está girando.
- Prisma-cliente. É essencialmente também um servidor, mas em relação à fonte de dados (prisma-server) é um cliente.
Agora vou tentar explicar essa situação confusa. Em geral, a essência do prisma é que, usando um único terminal de API, você pode trabalhar com diferentes fontes de dados. Sim, aqui alguém dirá que todos criaram o GraphQL e o prisma não é necessário aqui. Em geral, todos estarão certos, mas há um ponto sério: o GraphQL define apenas os princípios e o trabalho geral, mas, por si só, ele não fornece trabalho com as fontes de dados finais prontas para uso. Ele diz: "Você pode criar uma API para descrever quais solicitações os usuários podem enviar, mas como você lida com essas solicitações é seu trabalho". E o prisma também, é claro, usa o GraphQL (a propósito, e muitas outras coisas, incluindo vários produtos Apollo). Mas o prisma mais a isso apenas fornece trabalho com o banco de dados. Ou seja, descrevendo o esquema e sua implantação, as tabelas e colunas necessárias (bem como os relacionamentos entre elas) serão criadas imediatamente no banco de dados especificado e geram imediatamente todas as funções CRUD necessárias. Ou seja, com um prisma, você não apenas obtém um servidor GraphQL, mas uma API de trabalho completa que imediatamente permite que você trabalhe com o banco de dados. Portanto, o Prisma-server fornece um banco de dados e a interação com ele, e o prisma-client permite que você escreva seus resolvedores e envie solicitações ao prisma-server (ou a algum outro lugar, mesmo para alguns servidores prisma). Acontece que você só pode implantar o prisma-client por conta própria (e o SaaS prisma.io será usado como prisma-server), e você pode implantar o prisma-server por conta própria e geralmente não depende de um prisma de forma alguma, isso é tudo seu.
Aqui eu escolhi um prisma para mim, como base para minha plataforma. Mas então eu tive que girar para mim, a fim de obter uma plataforma completa.
1. Esquemas de mesclagem
Naquela época, o prisma não era capaz de combinar circuitos. Ou seja, a tarefa é a seguinte:
Você tem um modelo de usuário descrito em um módulo
type User { id: ID! @unique username: String! @unique email: String @unique }
e em outro módulo
type User { id: ID! @unique username: String! @unique firstname: String lastname: String }
Como parte de um projeto, você deseja combinar esses dois esquemas automaticamente para obter a saída
type User { id: ID! @unique username: String! @unique email: String @unique firstname: String lastname: String }
Mas então esse prisma não poderia funcionar. Acabou implementando isso usando a
biblioteca merge-graphql-schemas .
Trabalhe com um servidor prisma arbitrário.
No prisma, a configuração é gravada em um arquivo de configuração especial. Se você deseja alterar o endereço do servidor prisma usado, você deve editar o arquivo. Um pouco, não é agradável. Eu queria tornar possível o URL especificar no comando, por exemplo, endpoint = http: // endpoint-end yarn deploy (início do fio). Isso foi morto por vários dias ... Mas agora você pode usar um projeto de prisma para qualquer número de terminais. A propósito, até agora o prisma-cms funciona facilmente mesmo com um banco de dados local, mesmo com servidores Prism SaaS.
Módulos / Plugins
Isso geralmente não era suficiente. Como eu disse, a principal tarefa do prisma é fornecer trabalho com vários bancos de dados. E eles fazem um excelente trabalho nisso. Eles já suportam trabalhar com MySQL, PostgreSQL, Amazon RDS e MongoDB, vários outros tipos de fontes no caminho. Mas eles não fornecem nenhuma infraestrutura modular. Até o momento, não existe mercado ou algo do tipo. Existem apenas alguns espaços em branco típicos. Mas você não pode escolher dois ou três de vários espaços em branco e instalar em um projeto. Nós vamos ter que escolher um. Eu queria que fosse possível instalar um número diferente de módulos no projeto final e que, ao implantar os circuitos e os resolvedores, se divertissem e obtivessem um projeto único com a funcionalidade total. E, embora ainda não exista uma interface gráfica, já existem mais de duas dúzias de módulos e componentes em funcionamento que podem ser combinados no projeto final. Aqui, decidirei imediatamente um pouco sobre as definições pessoais: um módulo é o que é instalado na parte traseira (expandindo o banco de dados e a API) e um componente é o que é instalado na frente (para adicionar vários elementos da interface). Até o momento, não há interface gráfica para conectar módulos, mas não é difícil escrever dessa maneira (isso geralmente não é feito):
constructor(options = {}) { super(options); this.mergeModules([ LogModule, MailModule, UploadModule, SocietyModule, EthereumModule, WebrtcModule, UserModule, RouterModule, ]); }
Depois de adicionar novos módulos, basta executar uma implantação com um comando novamente e é isso, aqui já temos novas tabelas / colunas e funcionalidade aumentada.
5 frente, sensível às mudanças no back-end
Isso não foi suficiente. Isto será seguido por uma digressão. O fato é que todo o CMS da primeira API que eu vi diz "Nós somos incríveis para fornecer a API, e você estraga a frente que quiser". Esse é o "parafuso que você quiser" de fato significa "incomodar o quanto quiser". Exatamente o mesmo que os frameworks de interface do usuário dizem: “veja como botões legais somos e faça tudo isso, e confunda-se com o back-end”. Isso sempre matava. Eu só queria encontrar um CMS abrangente escrito em javascript, usando o GraphQL e fornecendo tanto a parte traseira quanto a frontal. Mas não encontrei um assim. Eu realmente queria que as alterações na API fossem percebidas imediatamente na frente. E para isso, várias subetapas foram concluídas:
5.1 Gerando fragmentos de API
Na frente, fragmentos do arquivo de esquema são registrados nas solicitações. Quando a API é reconstruída no servidor, um novo arquivo JS com fragmentos da API também é gerado. E nos pedidos está escrito assim:
const { UserNoNestingFragment, EthAccountNoNestingFragment, NotificationTypeNoNestingFragment, BatchPayloadNoNestingFragment, } = queryFragments; const userFragment = ` fragment user on User { ...UserNoNesting EthAccounts{ ...EthAccountNoNesting } NotificationTypes{ ...NotificationTypeNoNesting } } ${UserNoNestingFragment} ${EthAccountNoNestingFragment} ${NotificationTypeNoNestingFragment} `; const usersConnection = ` query usersConnection ( $where: UserWhereInput $orderBy: UserOrderByInput $skip: Int $after: String $before: String $first: Int $last: Int ){ objectsConnection: usersConnection ( where: $where orderBy: $orderBy skip: $skip after: $after before: $before first: $first last: $last ){ aggregate{ count } edges{ node{ ...user } } } } ${userFragment} `;
5.2 Um contexto para todos os componentes
O React 16.3 apresenta uma
nova API de contexto . Eu fiz isso para que, nos componentes filhos de qualquer nível, você pudesse acessar um único contexto sem listar os tipos pré-desejados do contexto, mas simplesmente especificando contextType = PrismaCmsContext estático e obtendo todos os encantos através deste-> contexto (incluindo o cliente da API, o esquema , solicitações etc.).
5.3 filtros dinâmicos
Eu também realmente queria. O GraphQL permite criar consultas complexas com uma estrutura aninhada. Eu também queria que os filtros fossem dinâmicos, formados a partir do esquema da API e nos permitissem criar condições aninhadas. Aqui está o que aconteceu:
5.4 Construtor de sites
E, finalmente, o que me faltava era um editor de site externo, ou seja, um designer. Eu queria que o servidor tivesse apenas um mínimo de ações a serem executadas e todo o design final deveria ser feito na frente (incluindo a configuração de roteamento, a geração de seleções etc.). Este é um tópico para um artigo separado, porque, entre outras coisas, eu também escrevi meu editor crysy wysiwyg para ele em puro contentEditable, e há muitas sutilezas. Se me restabelecerem os meus direitos e quem estiver interessado, escreverei um artigo separado.
Bem, finalmente, um pequeno vídeo de demonstração do designer em ação. Ainda bastante cru, mas eu gosto.
Eu vou terminar com isso. Ainda não escrevi muito, o que gostaria de escrever, mas muita coisa aconteceu. Ficarei feliz em comentar.
PS: todos os códigos-fonte, incluindo os códigos-fonte do próprio site,
estão aqui .