O que o compilador angular “compila”?

87

Perguntaram-me isso hoje e não consegui dar uma resposta adequada.

Transpila o texto datilografado para JS. Em seguida, há agitação de árvore, "menos" (opcional) e o que mais no processo de fazer uma implantação. Mas nada disso (afaik) tem algo a ver com "compilar". Tudo é agrupado e altamente otimizado, mas não é realmente compilado, certo?

Existe até um compilador "adiantado", que realmente faz um trabalho notável. O que eu sinto falta?

O próprio Javascript ainda é interpretado, certo?

codepleb
fonte
6
Eu concordo com o "não estou compilando". Essencialmente, é uma questão de definição de compilação . Alguns preferem usar a palavra transpilação para marcar a transformação de TypeScript em JavaScript. Mas sim, em essência, o papel do compilador Typescript é apenas gerar Javascript a partir do Typescript.
Pac0 de
6
@ Pac0 Posso estar entendendo mal alguma coisa aqui, mas se TypeScript para JavaScript é transpilação, o GCC não seria um transpilador de código de C para máquina? Como você definiria a diferença entre um transpiler e um compilador?
11684 de
24
transpiladores são compiladores
user253751
5
Veja o que as pessoas querem dizer quando falam "transpiler"? (e o seguimento “Meus primeiros quinze compiladores” ) (de alguém que trabalha com compilador), que argumenta que “compilador” é uma boa palavra para usar coisas como esta.
ShreevatsaR
2
O próprio Javascript ainda é interpretado, certo? - não mais, ele é compilado em código de máquina em tempo real pelo motor V8
Max Koretskyi

Respostas:

92

Você está presumindo que compilar significa pegar o código-fonte e produzir código de máquina, códigos de baixo nível, etc. Mas compilar na verdade significa apenas pegar um código-fonte e transformá-lo em outro. Portanto, parece razoável dizer que pegar o Typescript e produzir JavaScript é uma forma de compilar. Não é muito diferente do que (por exemplo) c # faz quando é compilado na linguagem IL.

Dito isso, eu diria que uma palavra melhor para isso é Transpilar . Eu sugeriria que o compilador Typescript é melhor descrito como um Transpiler.

A diferença é sutil e um transpiler pode ser considerado um tipo de compilador; mas uma linguagem compilada (pura) está (normalmente) transformando uma linguagem de alto nível em uma linguagem de baixo (mais) nível (mais próxima do código de máquina), como o exemplo C #. Um transpiler transforma uma linguagem de alto nível em uma linguagem de nível semelhante (de abstração) (também de alto nível). *

O resultado do código compilado normalmente não é uma linguagem que você mesmo escreveria . O resultado de um transpiler é outra linguagem de alto nível. Em teoria, você poderia escrever IL (como um exemplo), mas ele é realmente projetado para ser produzido por um compilador e não há ferramentas ou suporte para fazer isso, você produz IL compilando C # / vb.net, apenas. Considerando que Javascript é uma linguagem de programação utilizável (e usada) por si só.

* Muitas advertências, pois as definições dessas palavras e seu uso são muito vagas

Liam
fonte
12
O JavaScript não é um nível estritamente inferior ao do TypeScript?
Bergi,
3
Embora tudo nesta resposta seja correto e útil, especialmente porque a definição de compilar é sempre uma questão de confusão, ela não responde à pergunta do título. Esta resposta fala apenas sobre TypeScript, enquanto a pergunta é sobre Angular. A diferença é enorme. É totalmente possível usar Angular mesmo sem saber que TS é uma coisa. Estou surpreso que essa resposta tenha sido aceita.
Pedro A
3
Um compilador precisa essencialmente entender todo o programa para gerar outro programa (que geralmente faz a mesma coisa, mas em outra linguagem - isso inclui código de máquina).
Thorbjørn Ravn Andersen,
8
Acabei de ler isso duas vezes e não consegui encontrar a resposta para a pergunta aqui. A resposta está logo abaixo.
kuncevic.dev
5
A pergunta implícita que o OP estava fazendo, e é por isso que eles aceitaram isso, era "é correto chamar o compilador Angular de compilador?" - e é isso que esta resposta responde. Então, +1 de mim. Veja também O que as pessoas querem dizer quando falam "transpiler"? e o seguimento “Meus primeiros quinze compiladores” .
ShreevatsaR
70

Você parece estar fazendo três perguntas em uma:

  • Qual é a diferença entre um compilador e um transpiler?
  • Angular e TypeScript implementam compiladores ou transpiladores?
  • Existe um compilador Angular separado? O que ele compila?

Qual é a diferença entre um compilador e um transpilador?

@ JörgWMittag forneceu uma resposta muito boa a essa pergunta.

Angular e TypeScript implementam compiladores ou transpiladores?

Tanto o TS quanto o Angular implementam compiladores reais . Eles seguem os mesmos estágios de análise lexical, análise sintática, análise semântica e geração de código que os compiladores C / C ++ que produzem código assembly (exceto provavelmente para otimização). Você pode ver que a classe / pasta são denominadas "compilador" em Angular e TS .

O compilador angular não está realmente relacionado ao compilador TypeScript. Esses são compiladores muito diferentes.

Existe um compilador Angular separado? O que ele compila?

O Angular tem dois compiladores:

  • Ver compilador
  • Módulo Compilador

O trabalho do compilador de visualização é transformar o modelo que você especifica para o modelo de componente na representação interna de um componente que é uma fábrica de visualização que é então usada para instanciar uma instância de visualização .

Além de transformar o modelo, o compilador de visualização também compila várias informações de metadados na forma de decoradores @HostBinding, @ViewChildetc.

Suponha que você defina um componente e seu modelo assim:

@Component({
  selector: 'a-comp',
  template: '<span>A Component</span>'
})
class AComponent {}

Usando esses dados, o compilador gera a seguinte fábrica de componentes ligeiramente simplificada:

function View_AComponent {
  return jit_viewDef1(0,[
      elementDef2(0,null,null,1,'span',...),
      jit_textDef3(null,['My name is ',...])
    ]

Ele descreve a estrutura de uma visualização de componente e é usado ao instanciar o componente. O primeiro nó é a definição do elemento e o segundo é a definição do texto. Você pode ver que cada nó obtém as informações de que precisa ao ser instanciado por meio da lista de parâmetros. É função de um compilador resolver todas as dependências necessárias e fornecê-las no tempo de execução.

Recomendo fortemente a leitura destes artigos:

Além disso, consulte a resposta para Qual é a diferença entre o Angular AOT e o compilador JIT.

O trabalho do compilador de módulo é criar uma fábrica de módulo que basicamente contém as definições mescladas dos provedores.

Para mais informações, leia:

Max Koretskyi
fonte
1
@codepleb, veja esta resposta por Bergi
Max Koretskyi
1
@codepleb Observe que o GCC e muitos outros compiladores não produzem código de máquina. Na prática, o GCC chama automaticamente os sistemas para produzir código de máquina, mas o código que ele produz sem ajuda externa é meramente assembly, que é então entregue a um montador externo.
prosfilaes
7
@codepleb Esta resposta é muito superior e realmente responde à sua pergunta. Ainda há tempo para reconsiderar seu julgamento original.
assíncrono de
3
@codepleb não há uma boa razão para o termo "transpiler" existir ou ter existido, tudo o que ele faz é enganoso.
Leushenko,
2
@stom, desculpe, essa questão é muito ampla. A resposta mais votada é muito boa
Max Koretskyi
54

O texto digitado transpira para JS. Em seguida, há agitação de árvore, "menos" (opcional) e o que mais no processo de fazer uma implantação. Mas nada disso (afaik) tem algo a ver com "compilar". Tudo é agrupado e altamente otimizado, mas não é realmente compilado, certo?

Compilação significa transformar um programa escrito em uma linguagem A em um programa semanticamente equivalente escrito na linguagem B, de modo que avaliar o programa compilado de acordo com as regras da linguagem B (por exemplo, interpretá-lo com um intérprete para B ) produz o mesmo resultado e tem o mesmos efeitos colaterais que avaliar o programa original de acordo com as regras da linguagem A (por exemplo, interpretá-lo com um intérprete para A ).

Compilação simplesmente significa traduzir um programa de idioma A para a linguagem B . Isso é tudo que significa. (Observe também que é perfeitamente possível que A e B sejam o mesmo idioma.)

Em alguns casos, temos nomes mais especializados para certos tipos de compiladores, dependendo do que são A e B e do que o compilador faz:

  • se A é percebido como linguagem assembly e B é percebido como linguagem de máquina, então o chamamos de assembler ,
  • se A é percebido como linguagem de máquina e B é percebido como linguagem assembly, então o chamamos de desmontador ,
  • se A é percebido como de nível inferior a B , então o chamamos de descompilador ,
  • se A e B são a mesma linguagem, e o programa resultante é de alguma forma mais rápido ou mais leve, então o chamamos de otimizador ,
  • se A e B são as mesmas linguagens e o programa resultante é menor, então o chamamos de minificador ,
  • se A e B são as mesmas linguagens e o programa resultante é menos legível, então o chamamos de ofuscador ,
  • se A e B são percebidos como estando aproximadamente no mesmo nível de abstração, então o chamamos de transpiler , e
  • se A e B são percebidos como estando aproximadamente no mesmo nível de abstração e o programa resultante preserva a formatação, os comentários e a intenção do programador de forma que seja possível manter o programa resultante da mesma maneira que o programa original, então chamamos é uma ferramenta de reengenharia .

Além disso, observe que fontes mais antigas podem usar os termos "tradução" e "tradutor" em vez de "compilação" e "compilador". Por exemplo, C fala sobre "unidades de tradução".

Você também pode encontrar o termo "processador de linguagem". Isso pode significar um compilador, um interpretador ou ambos os compiladores e interpretadores, dependendo da definição.

O próprio Javascript ainda é interpretado, certo?

JavaScript é uma linguagem. Os idiomas são um conjunto de regras e restrições lógicas. As linguagens não são interpretadas ou compiladas. As línguas simplesmente são .

Compilação e interpretação são características de um compilador ou interpretador (duh!). Cada linguagem pode ser implementada com um compilador e cada linguagem pode ser implementada com um interpretador. Muitas linguagens possuem compiladores e interpretadores. Muitos mecanismos modernos de execução de alto desempenho têm pelo menos um compilador e pelo menos um interpretador.

Esses dois termos pertencem a diferentes camadas de abstração. Se o inglês fosse um idioma digitado, "idioma interpretado" seria um erro de tipo.

Observe também que algumas linguagens não têm intérprete nem compilador. Existem linguagens que não têm implementação nenhuma. Ainda assim, são linguagens e você pode escrever programas nelas. Você simplesmente não pode executá-los.

Além disso, observe que tudo é interpretado em algum momento : se você deseja executar algo, deve interpretá-lo. A compilação apenas traduz o código de um idioma para outro. Não o executa. Interpretação executa. (Às vezes, quando um interpretador é implementado em hardware, chamamos de "CPU", mas ainda é um interpretador.)

Caso em questão: cada implementação de JavaScript mainstream existente atualmente tem um compilador.

O V8 começou como um compilador puro: compilou JavaScript direto para código de máquina nativo moderadamente otimizado. Mais tarde, um segundo compilador foi adicionado. Agora, existem dois compiladores: um compilador leve que produz código moderadamente otimizado, mas o próprio compilador é muito rápido e usa pouca RAM. Este compilador também injeta código de criação de perfil no código compilado. O segundo compilador é um compilador mais pesado, mais lento e mais caro, que, no entanto, produz um código muito mais restrito e muito mais rápido. Ele também usa os resultados do código de criação de perfil injetado pelo primeiro compilador para tomar decisões de otimização dinâmica. Além disso, a decisão de qual código recompilar usando o segundo compilador é feita com base nessas informações de perfil. Observe que em nenhum momento há um intérprete envolvido. O V8 nunca interpreta, sempre compila. Não faz nem contém um intérprete. (Na verdade, acredito que hoje em dia sim, estou descrevendo as duas primeiras iterações.)

SpiderMonkey compila JavaScript para bytecode SpiderMonkey, que então interpreta. O interpretador também faz o perfil do código e, então, o código que é executado com mais freqüência é compilado por um compilador para o código de máquina nativo. Portanto, SpiderMonkey contém dois compiladores: um de JavaScript para o bytecode SpiderMonkey e outro de bytecode SpiderMonkey para o código de máquina nativo.

Quase todos os mecanismos de execução de JavaScript (com exceção do V8) seguem este modelo de um compilador AOT que compila JavaScript para bytecode e um mecanismo de modo misto que alterna entre interpretar e compilar esse bytecode.

Você escreveu em um comentário:

Eu realmente estava pensando que o código de máquina está envolvido em algum lugar.

O que significa "código de máquina"?

O que é a linguagem de máquina de um homem é a linguagem intermediária de outro homem e vice-versa? Por exemplo, existem CPUs que podem executar nativamente o bytecode JVM, em tal CPU, o bytecode JVM é o código de máquina nativo. E há interpretadores para o código de máquina x86, quando você executa o código de máquina x86 é interpretado por bytecode.

Existe um interpretador x86 chamado JPC escrito em Java. Se eu executar o código de máquina x86 em JPC rodando em uma CPU JVM nativa ... qual é o bytecode e qual é o código nativo? Se eu compilar o código de máquina x86 para JavaScript (sim, existem ferramentas que podem fazer isso) e executá-lo em um navegador no meu telefone (que tem uma CPU ARM), qual é o bytecode e qual é o código de máquina nativo? E se o programa que estou compilando for um emulador SPARC e eu o usar para executar o código SPARC?

Observe que toda linguagem induz uma máquina abstrata e é uma linguagem de máquina para essa máquina. Portanto, cada linguagem (incluindo linguagens de alto nível) é um código de máquina nativo. Além disso, você pode escrever um intérprete para cada idioma. Portanto, todas as linguagens (incluindo o código de máquina x86) não são nativas.

Jörg W Mittag
fonte
4
1 para a explicação profunda do conceito de compilação e, se pudesse, outro +1 para esses pontos. Muito útil.
Pedro A
1
Embora, devo dizer, tecnicamente isso não responda à pergunta do título ... Ainda um merecido +1 de mim!
Pedro A
Concordo que está implícito, mas a resposta à pergunta do título é "tudo o que o OP lista como não sendo uma compilação é o que a compilação angular é".
Jörg W Mittag
Explicação realmente boa de como isso é realmente mais sobre convenções de nomenclatura do que diferenças substantivas. Talvez pudesse ser melhorado mencionando o microcódigo - para apontar que, mesmo no nível do código de máquina, você não está 'no metal' ...
AakashM
1
De alguma forma, lembro-me de aprender o que é um compilador. Se alguém tivesse me dito naquela época que "compilador" é sinônimo de "tradutor para código", teria sido muito mais fácil saber para que ele serve ou por que precisamos dele. Claro, isso parece ridículo do ponto de vista de hoje, mas isso só me diz mais uma vez o quanto alguém pode se beneficiar apenas por ter a pessoa certa para lhe ensinar algo. Obrigado. :)
codepleb
18

Obter o código que você escreveu para ser executado em um navegador envolve duas coisas:

1) Transpilando o Typescript para JavaScript . Este é um tipo de problema resolvido. Acho que eles usam apenas o webpack.

2) Compilar as abstrações angulares em JavaScript . Quero dizer coisas como componentes, canais, diretivas, modelos, etc. É nisso que a equipe principal do angular trabalha.

Caso você esteja realmente interessado naquele segundo bit, o compilador angular, assista ao autor do compilador Tobias Bosch explicar o compilador Angular na AngularConnect 2016 .

Eu acho que há um pouco de confusão acontecendo aqui entre transpilar e compilar. Não importa e é uma questão de gosto pessoal, os dois são apenas transformações entre representações de código. Mas a definição que eu pessoalmente uso é que a transpilação é entre duas linguagens diferentes em um nível de abstração semelhante (por exemplo, texto digitado para javascript), enquanto a compilação requer uma redução no nível de abstração. Acho que desde modelos, componentes, canais, diretivas, etc. até apenas javascript, é um passo abaixo na escada de abstração, e é por isso que é chamado de compilador.

Nathan Cooper
fonte
1

Compilador Angular

Uma das mudanças mais importantes do Angular 4 para o 5 é que o compilador foi reescrito para ser mais rápido e completo. No passado, os aplicativos Angular usavam o que chamamos de compilação Just-in-Time (JIT), em que o aplicativo era compilado em tempo de execução no navegador antes de ser executado. As atualizações do compilador no Angular 5 avançaram a mudança para AOT, o que fez o aplicativo rodar mais rápido, pois executa menos compilação ao rodar o aplicativo. AOT é ativado por padrão em qualquer construção de produção desde a versão 1.5 do Angular CLI.

Digamos que queremos construir um aplicativo para implantação e executar o seguinte comando:

ng build --prod

Algumas coisas acontecem: versão de produção, minificação, recursos de pacotes, hashing de nome de arquivo, agitação de árvore, AOT ... (podemos ativar / desativar isso usando sinalizadores, por exemplo, aot = false). Resumindo, o sinalizador prod cria um pacote otimizado do aplicativo fazendo compilação AOT usando o ngc (o compilador Angular) para criar código otimizado pronto para o navegador ( sim, ele pré-compila modelos ).

Compilador TypeScript

O compilador texto datilografado, tsc , é responsável pela compilação arquivos texto datilografado. É o compilador responsável pela implementação dos recursos do TypeScript, como tipos estáticos, e o resultado é JavaScript puro do qual as palavras-chave e expressões do TypeScript foram removidas.

O compilador TypeScript possui dois recursos principais: é um transpilador e um verificador de tipo. O compilador transpila TypeScript para JavaScript. Ele faz as seguintes transformações em seu código-fonte:

  • Remova todas as anotações de tipo.
  • Compile novos recursos de JavaScript para versões antigas de JavaScript.
  • Compile recursos do TypeScript que não sejam JavaScript padrão.

Ao invocá-lo, o compilador procura configurações carregadas em tsconfig.json (uma lista detalhada de todas as opções do compilador, junto com os valores padrão, pode ser encontrada aqui ).

Em muitos aspectos, o compilador TypeScript funciona como qualquer compilador. Mas há uma diferença que pode pegar os incautos: por padrão, o compilador continua a emitir código JavaScript mesmo quando encontra um erro. Felizmente, esse comportamento pode ser desativado definindo onoEmitOnError definição de configuração como true no arquivo tsconfig.json.

Observação : tsc e ngc têm propósitos diferentes e não se trata de selecionar um ou outro. Esta resposta pode ser do seu interesse .

Esta resposta foi elaborada com base no conteúdo dos seguintes livros

  • Cloe, M. (2018). "Angular 5 Projects: Aprenda a construir aplicativos da Web de página única usando mais de 70 projetos".

  • Dewey, B., Grossnicklaus, K., Japikse, P. (2017). "Construindo Aplicativos da Web com Visual Studio 2017: Usando .NET Core e Modern JavaScript Frameworks".

  • Freeman, A. (2019). "Essential TypeScript: From Beginner to Pro".

  • Ghiya, P. (2018). "Microserviços TypeScript".

  • Iskandar, A., Chivukulu, S. (2019). "Desenvolvimento Web com Angular e Bootstrap - Terceira Edição".

  • Hennessy, K., Arora, C. (2018). "Angular 6 por exemplo".

  • Jansen, R., Wolf, I., Vane, V. (2016). "TypeScript: Modern JavaScript Development".

  • Mohammed, Z. (2019). "Projetos angulares".

  • Seshadri, S. (2018). "Angular: em funcionamento".

  • Wilken, J. (2018). "Angular em ação".

Tiago Martins Peres 李大仁
fonte