Compilador angular de 200 linhas

Oi Meu nome é romano e não sou o inventor das bicicletas. Gosto da estrutura Angular e do ecossistema em torno dela e desenvolvo meus aplicativos da Web com ela. Do meu ponto de vista, a principal vantagem do Angular a longo prazo se baseia na separação de código entre HTML e TypeScript, que foi descrita em detalhes por um de seus desenvolvedores por que-angular-renders-components-with.html Essa vantagem tem uma desvantagem: a necessidade de compilação em princípio e a complexidade de compilar componentes dinamicamente em tempo de execução. Então, eu quero usar a familiar sintaxe de modelo Angular para dar ao usuário seus aplicativos a capacidade de personalizar modelos de cartas, gerar relatórios e planilhas para impressão ou definir o formato de exportação para arquivos xml! Para descobrir como fazer isso, seja bem-vindo ao gato!

Desafio


Em geral, o uso de modelos angulares pelo usuário pode ser assim: temos um determinado conjunto de dados:

const data = { project: 'MySuperProject', userName: 'Roman', role: 'admin', projectLink: 'https://example.com/my-super-projectproject' } 

É necessário dar a oportunidade de personalizar o texto da carta, que será enviada ao usuário após a edição do projeto. Usando um modelo Angular, pode ficar assim:

  <body>  !  {{project}}    <a href="{{projectLink}}">3D   </a> <div *ngIf="role == 'admin'">       <a href="{{projectLink}}?mode=edit"></a> </div> </body> 

Biblioteca de modelos Ng


Esse problema pode ser resolvido usando o compilador Angular no cliente (ou mesmo no lado do servidor), mas consome muito tempo e requer a arrastação de muitos megabytes de código para o cliente. Por que o compilador Angular é tão grande? Isso se deve ao fato de que ele suporta um mar de diversas funcionalidades para compor componentes e módulos e também contém seu próprio analisador de HTML! Então, decidi escrever um conversor angular de modelo mínimo que usará o analisador de HTML incorporado ao navegador. Foi possível fazer isso em apenas 200 com algumas linhas de código em algumas horas. Decidi compartilhar o resultado com o público no GitHub

Usar a biblioteca ng-template é bastante simples:

Instalar dependência do npm

 npm install --save @quanterion/ng-template 

ou através de fios

 yarn add @quanterion/ng-template 

E use-o da seguinte maneira:

 import { compileTemplate, htmlToElement } from '@quanterion/ng-template'; async test() { let data = { name: 'Roman' }; let element = htmlToElement(`<div>{{name}}</div>`); await compileTemplate(element, data); alert(element.outerHTML); } 

Sintaxe suportada


  1. Expressões {{expression}} com capacidade de acessar variáveis ​​e chamar funções
  2. Ng-templates
  3. Recipiente Ng
  4. Condições * ngIf + * ngIf as
  5. Ciclos * ngFor
  6. Estilos [style.xxx] = "valor" e [style.xxx.px] = "valor"
  7. Classes condicionais [class.xxx] = "value"
  8. Observáveis ​​{{name $}} com assinatura automática de um valor (como um canal assíncrono)

Veja os testes ng-template.spec.ts para mais detalhes.

Usando Eval


Para avaliar expressões em modelos, eval é usado com preferência e cortesãs. O fato é que, nos modelos Angular, o acesso às variáveis ​​é usado sem o prefixo JavaScript usual, isso. Portanto, você precisa chamar eval (), que possui todas as variáveis ​​do objeto de dados no escopo. Não consegui gerar esse código para eval (), porque ver código

 const data = { a: 1, b: () => 4 }; const expression = 'a+b()'; eval('a =1; b = ??;' + expression); 

não permite a passagem de funções

A solução foi encontrada criando uma função cujos parâmetros possuem os nomes de campo do objeto com dados:

 const data = { a: 1, b: () => 4 }; let entries = [] for (let property in data ) { entries.push([property, data[property]]) } const params = entries.map(e => e[0]); const fun = new Function('code', ...params, `return eval(code)`); const args = entries.map(e => e[1]); const expression = 'a+b()'; const result = fun.call(undefined, expression , ...args); 

PS: Espero que, no futuro, quando a API do novo compilador Ivy se estabilizar, seja possível gerar um conjunto de operadores para o Ivy e criar componentes completos em dinâmica!

Link para fonte

Source: https://habr.com/ru/post/pt448022/


All Articles