Que «compile» le compilateur angulaire?

88

On m'a posé la question aujourd'hui et je n'ai pas été en mesure de donner une réponse correcte.

Transpiles dactylographiés vers JS. Ensuite, il y a la secousse d'arbre, "moins" (facultatif) et quoi d'autre dans le processus de déploiement. Mais rien de tout cela (afaik) n'a rien à voir avec la "compilation". Tout est regroupé et fortement optimisé, mais ce n'est pas vraiment compilé, non?

Il existe même un compilateur «à l'avance», qui fait vraiment un travail remarquable. Qu'est-ce que je manque?

Javascript lui-même est toujours interprété, non?

codepleb
la source
6
Je suis d'accord avec le "pas vraiment de compilation". Il s'agit essentiellement de définition de la compilation . Certains préfèrent utiliser le mot transpilation pour marquer la transformation de TypeScript en JavaScript. Mais oui, en substance, le rôle du compilateur Typescript est simplement de générer du Javascript à partir de Typescript.
Pac0
6
@ Pac0 Je ne comprends peut-être pas quelque chose ici, mais si TypeScript en JavaScript est une transpilation, GCC ne serait-il pas un transpilateur de code C en machine? Comment définiriez-vous la différence entre un transpilateur et un compilateur?
11684
24
les transpilers sont des compilateurs
user253751
5
Voir Que veulent dire les gens quand ils disent "transpiler"? (et le suivi «Mes quinze premiers compilateurs» ) (de quelqu'un qui travaille sur le compilateur), qui soutient que «compilateur» est un bon mot à utiliser pour des choses comme celle-ci.
ShreevatsaR
2
Javascript lui-même est toujours interprété, non? - plus maintenant, il est compilé en code machine à la volée par le moteur V8
Max Koretskyi

Réponses:

91

Vous supposez que compiler signifie prendre le code source et produire du code machine, des codes de bas niveau, etc. Mais compiler signifie en fait simplement prendre un code source et le transformer en un autre. Il semble donc raisonnable de dire que prendre Typescript et produire du JavaScript est une forme de compilation. Ce n'est pas différent de ce que fait (par exemple) c # lorsqu'il est compilé en langage IL.

Cela dit, je dirais qu'un meilleur mot pour cela est Transpiling . Je suggérerais que le compilateur Typescript soit mieux décrit comme un transpilateur.

La différence est subtile et un transpilateur peut être considéré comme un type de compilateur; mais un langage compilé (pur) transforme (généralement) un langage de haut niveau en un langage de bas (er) niveau (plus proche du code machine), comme l'exemple C #. Un transpilateur transforme un langage de haut niveau en un langage de niveau similaire (d'abstraction) (également de haut niveau). *

Le résultat du code compilé n'est généralement pas un langage que vous écririez vous-même . Le résultat d'un transpilateur est un autre langage de haut niveau. En théorie, vous pourriez écrire IL (à titre d'exemple) mais il est vraiment conçu pour être produit par un compilateur et il n'y a pas d'outils ou de support pour faire cela, vous produisez IL en compilant C # / vb.net, uniquement. Alors que Javascript est un langage de programmation utilisable (et utilisé) à part entière.

* Beaucoup de mises en garde car les définitions de ces mots et leur utilisation sont assez vagues

Liam
la source
12
JavaScript n'est-il pas strictement inférieur à TypeScript?
Bergi
3
Bien que tout dans cette réponse soit correct et utile, d'autant plus que la définition de la compilation est toujours une question de confusion, elle ne répond pas à la question du titre. Cette réponse ne parle que de TypeScript, tandis que la question concerne Angular. La différence est énorme. Il est tout à fait possible d'utiliser Angular sans même savoir que TS est une chose. Je suis surpris que cette réponse ait été acceptée.
Pedro A
3
Un compilateur doit essentiellement comprendre l'ensemble du programme afin de générer un autre programme (qui fait généralement la même chose mais dans un autre langage - cela inclut le code machine).
Thorbjørn Ravn Andersen
8
Je viens de lire cela deux fois et je n'ai pas trouvé la réponse à la question ici. La réponse est juste en dessous.
kuncevic.dev
5
La question implicite que l'OP se posait, c'est pourquoi ils l'ont accepté, était «est-il correct d'appeler le compilateur Angular un compilateur?» - et c'est ce que répond cette réponse. Donc +1 de moi. Voir aussi Que veulent dire les gens quand ils disent "transpiler"? et le suivi «Mes quinze premiers compilateurs» .
ShreevatsaR
70

Vous semblez poser trois questions en une:

  • Quelle est la différence entre un compilateur et un transpilateur?
  • Angular et TypeScript implémentent-ils des compilateurs ou des transpileurs?
  • Existe-t-il un compilateur angulaire séparé? Que compile-t-il?

Quelle est la différence entre un compilateur et un transpilateur?

@ JörgWMittag a fourni une très bonne réponse à cette question.

Angular et TypeScript implémentent-ils des compilateurs ou des transpileurs?

TS et Angular implémentent de vrais compilateurs. Ils suivent les mêmes étapes d'analyse lexicale, d'analyse, d'analyse sémantique et de génération de code que les compilateurs C / C ++ qui produisent du code d'assemblage (sauf probablement pour l'optimisation). Vous pouvez voir que la classe / le dossier sont nommés "compilateur" dans Angular et TS .

Le compilateur angulaire n'est pas vraiment lié au compilateur TypeScript. Ce sont des compilateurs très différents.

Existe-t-il un compilateur angulaire séparé? Que compile-t-il?

Angular a deux compilateurs:

  • Voir le compilateur
  • Compilateur de modules

Le travail du compilateur de vues consiste à transformer le modèle que vous spécifiez pour le modèle de composant en représentation interne d'un composant qui est une fabrique de vues qui est ensuite utilisée pour instancier une occurrence de vue .

En plus de transformer le modèle, le compilateur de vues compile également diverses informations de métadonnées sous la forme de décorateurs comme @HostBinding, @ViewChildetc.

Supposons que vous définissiez un composant et son modèle comme ceci:

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

En utilisant ces données, le compilateur génère la fabrique de composants légèrement simplifiée suivante:

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

Il décrit la structure d'une vue de composant et est utilisé lors de l'instanciation du composant. Le premier nœud est la définition d'élément et le second est la définition de texte. Vous pouvez voir que chaque nœud obtient les informations dont il a besoin lorsqu'il est instancié via la liste des paramètres. C'est le travail d'un compilateur de résoudre toutes les dépendances requises et de les fournir au moment de l'exécution.

Je recommande fortement de lire ces articles:

Voir également la réponse à Quelle est la différence entre le compilateur Angular AOT et JIT.

Le travail du compilateur de modules est de créer une fabrique de modules qui contient essentiellement des définitions fusionnées des fournisseurs.

Pour plus d'informations, lisez:

Max Koretskyi
la source
1
@codepleb, voir cette réponse de Bergi
Max Koretskyi
1
@codepleb Notez que GCC et de nombreux autres compilateurs ne produisent pas du tout de code machine. En pratique, GCC appelle automatiquement les systèmes pour produire du code machine, mais le code qu'il produit sans aide externe n'est qu'un assemblage, qui est ensuite remis à un assembleur externe.
prosfilaes
7
@codepleb Cette réponse est de loin supérieure et répond en fait à votre question. Il est encore temps de reconsidérer votre jugement initial.
async
3
@codepleb il n'y a aucune bonne raison pour que le terme «transpilateur» existe ou ait jamais existé, tout ce qu'il fait est trompeur.
Leushenko
2
@stom, désolé, cette question est trop large. La réponse la plus votée est plutôt bonne
Max Koretskyi
54

Le typographie transpire vers JS. Ensuite, il y a la secousse d'arbre, "moins" (facultatif) et quoi d'autre dans le processus de déploiement. Mais rien de tout cela (afaik) n'a rien à voir avec la "compilation". Tout est regroupé et fortement optimisé, mais ce n'est pas vraiment compilé, non?

La compilation consiste à transformer un programme écrit dans un langage A en un programme sémantiquement équivalent écrit en langage B tel qu'évaluer le programme compilé selon les règles du langage B (par exemple l'interpréter avec un interpréteur pour B ) donne le même résultat et a le mêmes effets secondaires que l'évaluation du programme original selon les règles du langage A (par exemple l'interpréter avec un interprète pour A ).

Compilation signifie simplement la traduction d' un programme de langue A à la langue B . C'est tout ce que cela signifie. (Notez également qu'il est parfaitement possible que A et B soient la même langue.)

Dans certains cas, nous avons des noms plus spécialisés pour certains types de compilateurs, selon ce que sont A et B et ce que fait le compilateur:

  • si A est perçu comme un langage d'assemblage et B est perçu comme un langage machine, alors nous l'appelons un assembleur ,
  • si A est perçu comme un langage machine et B est perçu comme un langage d'assemblage, alors nous l'appelons un désassembleur ,
  • si A est perçu comme étant de niveau inférieur à B , alors nous l'appelons un décompilateur ,
  • si A et B sont le même langage et que le programme résultant est en quelque sorte plus rapide ou plus léger, nous l'appelons un optimiseur ,
  • si A et B sont les mêmes langages et que le programme résultant est plus petit, alors nous l'appelons un minifier ,
  • si A et B sont les mêmes langages et que le programme résultant est moins lisible, alors on l'appelle un obfuscator ,
  • si A et B sont perçus comme étant à peu près au même niveau d'abstraction, alors nous l'appelons un transpilateur , et
  • si A et B sont perçus comme étant à peu près au même niveau d'abstraction et que le programme résultant préserve le formatage, les commentaires et l'intention du programmeur de sorte qu'il soit possible de maintenir le programme résultant de la même manière que le programme d'origine, alors nous appelons c'est un outil de réingénierie .

Notez également que les sources plus anciennes peuvent utiliser les termes «traduction» et «traducteur» au lieu de «compilation» et «compilateur». Par exemple, C parle d '«unités de traduction».

Vous pouvez également tomber sur le terme «processeur de langage». Cela peut signifier soit un compilateur, un interpréteur, ou les deux compilateurs et interprètes selon la définition.

Javascript lui-même est toujours interprété, non?

JavaScript est un langage. Les langues sont un ensemble de règles logiques et de restrictions. Les langues ne sont ni interprétées ni compilées. Les langues sont juste .

La compilation et l'interprétation sont des traits d'un compilateur ou d'un interprète (duh!). Chaque langage peut être implémenté avec un compilateur et chaque langage peut être implémenté avec un interpréteur. De nombreux langages ont à la fois des compilateurs et des interprètes. De nombreux moteurs d'exécution modernes hautes performances ont à la fois au moins un compilateur et au moins un interpréteur.

Ces deux termes appartiennent à des couches d'abstraction différentes. Si l'anglais était une langue typée, «interprété-langue» serait une erreur de type.

Notez également que certains langages n'ont ni interpréteur ni compilateur. Il existe des langages qui n'ont pas du tout d'implémentation. Pourtant, ce sont des langages et vous pouvez y écrire des programmes. Vous ne pouvez tout simplement pas les exécuter.

Notez également que tout est interprété à un moment donné : si vous voulez exécuter quelque chose, vous devez l' interpréter. La compilation traduit simplement le code d'une langue à une autre. Il ne le fait pas fonctionner. L'interprétation le dirige. (Parfois, lorsqu'un interpréteur est implémenté dans le matériel, nous l'appelons un "CPU", mais c'est toujours un interpréteur.)

Exemple concret: chaque implémentation JavaScript grand public actuellement existante a un compilateur.

V8 a commencé comme un pur compilateur: il a compilé JavaScript directement en code machine natif modérément optimisé. Plus tard, un deuxième compilateur a été ajouté. Maintenant, il existe deux compilateurs: un compilateur léger qui produit du code moyennement optimisé mais le compilateur lui-même est très rapide et utilise peu de RAM. Ce compilateur injecte également du code de profilage dans le code compilé. Le deuxième compilateur est un compilateur plus lourd, plus lent et plus cher, qui, cependant, produit un code beaucoup plus serré et beaucoup plus rapide. Il utilise également les résultats du code de profilage injecté par le premier compilateur pour prendre des décisions d'optimisation dynamique. En outre, la décision du code à recompiler à l'aide du deuxième compilateur est prise en fonction de ces informations de profilage. Notez qu'à aucun moment il n'y a d'interprète impliqué. Le V8 n'interprète jamais, il compile toujours. C'est pas ca' t même contenir un interprète. (En fait, je crois que c'est le cas aujourd'hui, je décris les deux premières itérations.)

SpiderMonkey compile JavaScript en bytecode SpiderMonkey, qu'il interprète ensuite. L'interpréteur profile également le code, puis le code qui est exécuté le plus souvent est compilé par un compilateur en code machine natif. Ainsi, SpiderMonkey contient deux compilateurs: un de JavaScript au bytecode SpiderMonkey, et un autre du bytecode SpiderMonkey au code machine natif.

Presque tous les moteurs d'exécution JavaScript (à l'exception de V8) suivent ce modèle d'un compilateur AOT qui compile JavaScript en bytecode, et un moteur en mode mixte qui bascule entre l'interprétation et la compilation de ce bytecode.

Vous avez écrit dans un commentaire:

Je pensais vraiment que le code machine est quelque part impliqué.

Que signifie même «code machine»?

Qu'est-ce que le langage machine d'un homme est le langage intermédiaire d'un autre homme et vice versa? Par exemple, il existe des processeurs qui peuvent exécuter nativement le bytecode JVM, sur un tel processeur, le bytecode JVM est un code machine natif. Et il y a des interpréteurs pour le code machine x86, lorsque vous exécutez ces codes machine x86 est interprété bytecode.

Il existe un interpréteur x86 appelé JPC écrit en Java. Si j'exécute du code machine x86 sur JPC fonctionnant sur un processeur JVM natif… quel est le bytecode et quel est le code natif? Si je compile du code machine x86 en JavaScript (oui, il existe des outils qui peuvent le faire) et que je l'exécute dans un navigateur sur mon téléphone (qui dispose d'un processeur ARM), quel est le bytecode et quel est le code machine natif? Que faire si le programme que je compile est un émulateur SPARC et que je l'utilise pour exécuter du code SPARC?

Notez que chaque langage induit une machine abstraite, et est un langage machine pour cette machine. Ainsi, chaque langue (y compris les langues de très haut niveau) est un code machine natif. En outre, vous pouvez écrire un interprète pour chaque langue. Ainsi, chaque langue (y compris le code machine x86) n'est pas native.

Jörg W Mittag
la source
4
+1 pour l'explication approfondie du concept de compilation, et si je pouvais, un autre +1 pour ces puces. Très utile.
Pedro A
1
Bien que, je dois dire, techniquement cela ne répond pas à la question du titre ... Encore un +1 mérité de ma part, cependant!
Pedro A
Je suis d'accord que c'est implicite, mais la réponse à la question dans le titre est "tout ce que l'OP énumère comme non compilation est ce qu'est la compilation angulaire".
Jörg W Mittag
Vraiment bonne explication de la façon dont il s'agit en fait de conventions de dénomination plutôt que de différences de fond. Pourrait peut-être être amélioré en mentionnant le microcode - pour souligner que même au niveau du code machine, vous n'êtes pas `` au métal '' ...
AakashM
1
Je me souviens en quelque sorte d'avoir appris ce qu'est un compilateur. Si quelqu'un m'avait dit à l'époque, que «compilateur» est synonyme de «traducteur pour code», il aurait été tellement plus facile d'obtenir à quoi il sert ou pourquoi nous en avons besoin. Bien sûr, cela semble ridicule du point de vue de nos jours, mais cela me dit une fois de plus à quel point on peut bénéficier du simple fait d'avoir la bonne personne pour lui apprendre quelque chose. Merci. :)
codepleb
18

Obtenir le code que vous avez écrit pour l'exécuter sur un navigateur implique deux choses:

1) Transcription du typographie en JavaScript . C'est en quelque sorte un problème résolu. Je pense qu'ils utilisent juste webpack.

2) Compilation des abstractions angulaires en JavaScript . Je veux dire des choses comme des composants, des tuyaux, des directives, des modèles, etc. C'est sur quoi travaille l'équipe angulaire de base.

Si vous êtes vraiment intéressé par ce deuxième bit, le compilateur angulaire, regardez l'auteur du compilateur Tobias Bosch expliquer le compilateur angulaire à AngularConnect 2016 .

Je pense qu'il y a un peu de confusion entre la transpilation et la compilation. Cela n'a pas d'importance et c'est une question de goût personnel, ils ne sont tous les deux que des transformations entre les représentations du code. Mais la définition que j'utilise personnellement est que la transpilation se fait entre deux langages différents à un niveau d'abstraction similaire (par exemple dactylographié en javascript), alors que la compilation nécessite une descente dans le niveau d'abstraction. Je pense que des modèles, composants, tuyaux, directives, etc. au javascript, c'est un pas en bas de l'échelle d'abstraction, et c'est pourquoi on l'appelle un compilateur.

Nathan Cooper
la source
1

Compilateur angulaire

L'un des changements les plus importants de Angular 4 à 5 est que le compilateur a été réécrit pour être plus rapide et plus complet. Dans le passé, les applications Angular utilisaient ce que nous appelons la compilation Just-in-Time (JIT), où l'application était compilée au moment de l'exécution dans le navigateur avant de s'exécuter. Les mises à jour du compilateur dans Angular 5 ont avancé le passage à AOT, ce qui a rendu l'application plus rapide car elle effectue moins de compilation lors de l'exécution de l'application. AOT devient activé par défaut dans toute version de production depuis la version 1.5 de la CLI angulaire.

Disons que nous voulons créer une application pour le déploiement et exécuter la commande suivante:

ng build --prod

Quelques choses se produisent: version de production, minification, bunddles assets, hachage de nom de fichier, arborescence, AOT ... (nous pouvons activer / désactiver cela en utilisant des indicateurs, ex. Aot = false). En bref, l'indicateur prod crée un bundle optimisé de l'application en effectuant une compilation AOT à l'aide du ngc (le compilateur Angular) pour créer un code optimisé prêt pour le navigateur ( Oui, il pré-compile les modèles ).

Compilateur TypeScript

Le compilateur TypeScript, tsc , est responsable de la compilation des fichiers TypeScript. C'est le compilateur qui est responsable de l'implémentation des fonctionnalités TypeScript, telles que les types statiques, et le résultat est du JavaScript pur dont les mots-clés et expressions TypeScript ont été supprimés.

Le compilateur TypeScript a deux caractéristiques principales: c'est un transpilateur et un vérificateur de type. Le compilateur transpile TypeScript en JavaScript. Il effectue les transformations suivantes sur votre code source:

  • Supprimez toutes les annotations de type.
  • Compilez de nouvelles fonctionnalités JavaScript pour les anciennes versions de JavaScript.
  • Compilez les fonctionnalités TypeScript qui ne sont pas du JavaScript standard.

En l'invoquant, le compilateur recherche les configurations chargées dans tsconfig.json (une liste détaillée de toutes les options du compilateur, ainsi que les valeurs par défaut, peut être trouvée ici ).

À bien des égards, le compilateur TypeScript fonctionne comme n'importe quel compilateur. Mais il y a une différence qui peut surprendre les imprudents: par défaut, le compilateur continue à émettre du code JavaScript même lorsqu'il rencontre une erreur. Heureusement, ce comportement peut être désactivé en définissant le noEmitOnErrorparamètre de configuration sur true dans le fichier tsconfig.json.

A noter : tsc et ngc ont des objectifs différents et il ne s'agit pas de sélectionner l'un par rapport à l'autre. Cette réponse pourrait être intéressante .

Cette réponse a été conçue sur la base du contenu des livres suivants

  • Cloe, M. (2018). "Angular 5 Projects: Apprenez à créer des applications Web à page unique en utilisant plus de 70 projets".

  • Dewey, B., Grossnicklaus, K., Japikse, P. (2017). «Création d'applications Web avec Visual Studio 2017: Utilisation de .NET Core et de cadres JavaScript modernes».

  • Freeman, A. (2019). "TypeScript essentiel: du débutant au pro".

  • Ghiya, P. (2018). «Microservices TypeScript».

  • Iskandar, A., Chivukulu, S. (2019). "Développement Web avec Angular et Bootstrap - Troisième Edition".

  • Hennessy, K., Arora, C. (2018). "Angulaire 6 par exemple".

  • Jansen, R., Wolf, I., Vane, V. (2016). "TypeScript: Développement JavaScript moderne".

  • Mohammed, Z. (2019). "Projets angulaires".

  • Seshadri, S. (2018). "Angular: Up and Running".

  • Wilken, J. (2018). "Angulaire en action".

Tiago Martins Peres 李大仁
la source