Что «компилирует» компилятор angular?

88

Меня спросили об этом сегодня, и я не смог дать должного ответа.

Машинопись преобразуется в JS. Затем идет тряска дерева, «меньше» (необязательно) и что еще в процессе развертывания. Но ничего подобного (afaik) не имеет ничего общего с "компиляцией". Все объединяется и сильно оптимизируется, но на самом деле не компилируется, верно?

Есть даже компилятор «впереди времени», который действительно делает заметную работу. Что мне не хватает?

Сам Javascript все еще интерпретируется, верно?

Codepleb
источник
6
Я согласен с "не совсем компилироваться". По сути, это вопрос определения компиляции . Некоторые предпочитают использовать слово « транспиляция» для обозначения преобразования TypeScript в JavaScript. Но да, по сути, роль компилятора Typescript - просто генерировать Javascript из Typescript.
Pac0
6
@ Pac0 Я могу что-то неправильно понять, но если TypeScript to JavaScript - это транспиляция, не будет ли GCC транспилятором C в машинный код? Как бы вы определили разницу между транспилятором и компилятором?
11684,
24
транспиляторы - это компиляторы
user253751
5
Посмотрите, что люди имеют в виду, когда говорят «транспилятор»? (и продолжение «Мои первые пятнадцать компиляторов» ) (от кого-то, кто работает над компилятором), в котором утверждается, что «компилятор» - хорошее слово для подобных вещей.
ShreevatsaR
2
Сам Javascript все еще используется, не так ли? - больше нет, он компилируется в машинный код на лету двигателем V8
Макс Корецкий

Ответы:

91

Вы предполагаете, что компиляция означает взятие исходного кода и создание машинного кода, низкоуровневых кодов и т.д. Но на самом деле компиляция означает просто взять один исходный код и превратить его в другой. Поэтому кажется разумным сказать, что использование Typescript и создание JavaScript - это форма компиляции. Это не отличается от того, что (например) делает C #, когда он скомпилирован в язык IL.

Тем не менее, я бы сказал более подходящее слово для этого - Транспилинг . Я бы посоветовал лучше описать компилятор Typescript как Transpiler.

Разница невелика, и транспилятор можно рассматривать как тип компилятора; но (чистый) скомпилированный язык (обычно) превращает язык высокого уровня в язык низкого (er) уровня (ближе к машинному коду), как в примере C #. Транспилер превращает язык высокого уровня в язык аналогичного уровня (абстракции) (также высокого уровня). *

Результат скомпилированного кода обычно не является языком, который вы бы написали сами . Результатом транспилятора является еще один язык высокого уровня. Теоретически вы можете написать IL (в качестве примера), но на самом деле он разработан для создания компилятором, и для этого нет инструментов или поддержки, вы создаете IL путем компиляции только C # / vb.net. В то время как Javascript - это полезный (и используемый) язык программирования сам по себе.

* Множество предостережений, поскольку определения этих слов и их использования довольно расплывчаты.

Лиам
источник
12
Разве JavaScript не ниже уровня TypeScript?
Берги
3
Хотя все в этом ответе правильно и полезно, особенно с учетом того, что определение компиляции всегда вызывает путаницу, оно не отвечает на вопрос в заголовке. В этом ответе говорится только о TypeScript, а вопрос касается Angular. Разница огромная. Вполне возможно использовать Angular, даже не зная, что TS - это вещь. Я удивлен, что этот ответ был принят.
Pedro A
3
Компилятору необходимо понимать всю программу, чтобы сгенерировать другую программу (которая обычно делает то же самое, но на другом языке, включая машинный код).
Торбьёрн Равн Андерсен
8
Я просто прочитал это дважды и не смог найти здесь ответа на вопрос. Ответ чуть ниже.
kuncevic.dev
5
Неявный вопрос, который задавал ОП, поэтому они приняли это, был: «правильно ли называть компилятор Angular компилятором?» - и вот на что отвечает этот ответ. Итак, +1 от меня. См. Также Что люди имеют в виду, когда говорят «транспилятор»? и продолжение «Мои первые пятнадцать компиляторов» .
ShreevatsaR
70

Кажется, вы задаете три вопроса в одном:

  • В чем разница между компилятором и транспилятором?
  • Реализуют ли Angular и TypeScript компиляторы или транспиляторы?
  • Есть ли отдельный компилятор Angular? Что он компилирует?

В чем разница между компилятором и транспилятором?

@ JörgWMittag дал очень хороший ответ на этот вопрос.

Реализуют ли Angular и TypeScript компиляторы или транспиляторы?

И TS, и Angular реализуют настоящие компиляторы. Они проходят те же этапы лексического анализа, синтаксического анализа, семантического анализа и генерации кода, что и компиляторы C / C ++, которые производят ассемблерный код (за исключением, вероятно, оптимизации). Вы можете видеть, что класс / папка названы «компилятор» как в Angular, так и в TS .

Компилятор angular на самом деле не имеет отношения к компилятору TypeScript. Это очень разные компиляторы.

Есть ли отдельный компилятор Angular? Что он компилирует?

В Angular есть два компилятора:

  • Просмотреть компилятор
  • Компилятор модуля

Задача компилятора представления состоит в том, чтобы преобразовать шаблон, который вы указываете для шаблона компонента, во внутреннее представление компонента, которое является фабрикой представлений, которая затем используется для создания экземпляра представления .

Помимо преобразования шаблона, компилятор представления также компилирует различную информацию метаданных в виде декораторов, таких как @HostBindingи @ViewChildт. Д.

Предположим, вы определяете компонент и его шаблон следующим образом:

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

Используя эти данные, компилятор генерирует следующую несколько упрощенную фабрику компонентов:

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

Он описывает структуру представления компонента и используется при создании экземпляра компонента. Первый узел - это определение элемента, а второй - текстовое определение. Вы можете видеть, что каждый узел получает необходимую информацию при создании экземпляра через список параметров. Задача компилятора - разрешить все необходимые зависимости и предоставить их во время выполнения.

Я настоятельно рекомендую прочитать эти статьи:

Также см. Ответ на вопрос, в чем разница между компилятором Angular AOT и JIT.

Задача компилятора модуля - создать фабрику модулей, которая в основном содержит объединенные определения поставщиков.

Для получения дополнительной информации прочтите:

Макс Корецкий
источник
1
@codepleb, см. этот ответ Берги
Макс Корецкий
1
@codepleb Обратите внимание, что GCC и многие другие компиляторы вообще не создают машинный код. На практике GCC автоматически вызывает системы для создания машинного кода, но код, который он создает без внешней помощи, представляет собой просто сборку, которая затем передается внешнему ассемблеру.
prosfilaes
7
@codepleb Этот ответ намного лучше и фактически отвечает на ваш вопрос. Еще есть время пересмотреть свое первоначальное суждение.
async
3
@codepleb нет никаких веских причин для существования или когда-либо существования термина «транспилятор», все, что он делает, вводит в заблуждение.
Леушенко
2
@stom, извините, это слишком общий вопрос. Тем не менее, самый популярный ответ - довольно хороший
Макс Корецкий
54

Машинопись преобразуется в JS. Затем идет встряска дерева, «меньше» (необязательно) и что еще в процессе развертывания. Но ничего подобного (afaik) не имеет ничего общего с "компиляцией". Все объединяется и сильно оптимизируется, но на самом деле не компилируется, верно?

Компиляция означает преобразование программы, написанной на языке A, в семантически эквивалентную программу, написанную на языке B, таким образом, что оценка скомпилированной программы в соответствии с правилами языка B (например, интерпретация ее с помощью интерпретатора для B ) дает тот же результат и имеет те же побочные эффекты, что и при оценке исходной программы в соответствии с правилами языка A (например, при ее интерпретации с помощью интерпретатора для A ).

Составление просто означает перевод программы с языка А на язык Б . Это все, что это значит. (Также обратите внимание, что A и B могут быть одним и тем же языком.)

В некоторых случаях у нас есть более специализированные имена для определенных типов компиляторов, в зависимости от того, что такое A и B , и что делает компилятор:

  • если A воспринимается как язык ассемблера, а B - как машинный язык, то мы называем это ассемблером ,
  • если A воспринимается как машинный язык, а B воспринимается как язык ассемблера, то мы называем это дизассемблером ,
  • если A воспринимается как более низкий уровень, чем B , то мы называем это декомпилятором ,
  • если A и B - это один и тот же язык, и полученная программа в некотором роде быстрее или легче, то мы называем ее оптимизатором ,
  • если A и B - это одни и те же языки, и полученная программа меньше, то мы называем ее минификатором ,
  • если A и B являются одними и теми же языками, и полученная программа менее читабельна, то мы называем ее обфускатором ,
  • если воспринимается, что A и B находятся примерно на одном уровне абстракции, то мы называем это транспилятором и
  • если A и B воспринимаются как находящиеся примерно на одном уровне абстракции, а результирующая программа сохраняет форматирование, комментарии и намерения программиста, так что можно поддерживать полученную программу таким же образом, как и исходная программа, тогда мы вызываем это инструмент реинжиниринга .

Также обратите внимание, что старые источники могут использовать термины «перевод» и «переводчик» вместо «компиляция» и «компилятор». Например, C говорит о «единицах перевода».

Вы также можете встретить термин «языковой процессор». Это может означать либо компилятор, либо интерпретатор, либо оба компилятора и интерпретатора в зависимости от определения.

Сам Javascript все еще интерпретируется, верно?

JavaScript - это язык. Языки - это набор логических правил и ограничений. Языки не интерпретируются и не компилируются. Языки просто есть .

Компиляция и интерпретация - это особенности компилятора или интерпретатора (да!). Каждый язык может быть реализован с помощью компилятора, и каждый язык может быть реализован с помощью интерпретатора. Многие языки имеют как компиляторы, так и интерпретаторы. Многие современные высокопроизводительные механизмы выполнения имеют как минимум один компилятор и как минимум один интерпретатор.

Эти два термина относятся к разным уровням абстракции. Если бы английский был типизированным языком, «интерпретируемый язык» был бы ошибкой типа.

Также обратите внимание, что в некоторых языках нет ни интерпретатора, ни компилятора. Есть языки, у которых вообще нет реализации. Тем не менее, это языки, и на них можно писать программы. Вы просто не можете их запустить.

Также обратите внимание, что в какой-то момент все интерпретируется : если вы хотите что-то выполнить, вы должны это интерпретировать. Компиляция просто переводит код с одного языка на другой. Это не работает. Это управляет интерпретация . (Иногда, когда интерпретатор реализован на оборудовании, мы называем его «ЦП», но это все равно интерпретатор.)

Показательный пример: каждая существующая в настоящее время основная реализация JavaScript имеет компилятор.

V8 начинался как чистый компилятор: он компилировал JavaScript прямо в умеренно оптимизированный машинный код. Позже был добавлен второй компилятор. Теперь есть два компилятора: легкий компилятор, который производит умеренно оптимизированный код, но сам компилятор очень быстр и использует мало оперативной памяти. Этот компилятор также вставляет код профилирования в скомпилированный код. Второй компилятор - это более тяжелый, медленный и более дорогой компилятор, который, однако, создает гораздо более жесткий и более быстрый код. Он также использует результаты кода профилирования, введенного первым компилятором, для принятия решений по динамической оптимизации. Кроме того, решение, какой код перекомпилировать с использованием второго компилятора, принимается на основе этой информации о профилировании. Обратите внимание, что переводчик ни разу не задействован. V8 никогда не интерпретирует, он всегда компилируется. Это не t даже есть интерпретатор. (На самом деле, я считаю, что сейчас это так, я описываю первые две итерации.)

SpiderMonkey компилирует JavaScript в байт-код SpiderMonkey, который затем интерпретирует. Интерпретатор также профилирует код, а затем код, который выполняется чаще всего, компилируется компилятором в собственный машинный код. Итак, SpiderMonkey содержит два компилятора: один из байт-кода JavaScript в SpiderMonkey, а другой из байт-кода SpiderMonkey в собственный машинный код.

Почти все механизмы выполнения JavaScript (за исключением V8) следуют этой модели компилятора AOT, который компилирует JavaScript в байт-код, и механизма смешанного режима, который переключается между интерпретацией и компиляцией этого байт-кода.

Вы написали в комментарии:

Я действительно думал, что здесь замешан машинный код.

Что вообще означает «машинный код»?

Что такое машинный язык одного человека, что является промежуточным языком другого человека, и наоборот? Например, есть процессоры, которые могут выполнять байт-код JVM изначально, на таком ЦП байт-код JVM является собственным машинным кодом. И есть интерпретаторы для машинного кода x86, когда вы запускаете этот машинный код x86 , интерпретируется байт-код.

Существует интерпретатор x86 под названием JPC, написанный на Java. Если я запускаю машинный код x86 на JPC, работающем на собственном процессоре JVM ... какой байт-код, а какой собственный? Если я скомпилирую машинный код x86 в JavaScript (да, есть инструменты, которые могут это сделать) и запустил его в браузере на моем телефоне (который имеет процессор ARM), какой будет байт-код, а какой - собственный машинный код? Что, если программа, которую я компилирую, представляет собой эмулятор SPARC, и я использую его для запуска кода SPARC?

Обратите внимание, что каждый язык порождает абстрактную машину и является машинным языком для этой машины. Итак, каждый язык (включая языки очень высокого уровня) - это собственный машинный код. Кроме того, вы можете написать переводчика для любого языка. Итак, каждый язык (включая машинный код x86) не является родным.

Йорг В. Миттаг
источник
4
+1 за подробное объяснение концепции компиляции, и, если можно, еще +1 за эти пункты. Очень полезно.
Pedro A
1
Хотя, я должен сказать, технически это не отвечает на вопрос в заголовке ... Тем не менее, я все же заслужил +1!
Pedro A
Я согласен, что это неявно, но ответ на вопрос в заголовке: «все, что OP перечисляет как не компиляцию, - это то, что такое угловая компиляция».
Jörg W Mittag
Действительно хорошее объяснение того, как это на самом деле связано с соглашениями об именах, а не с существенными различиями. Возможно, можно было бы улучшить, упомянув микрокод - чтобы указать, что даже на уровне машинного кода вы не «на металле» ...
AakashM
1
Я как-то помню, как узнал, что такое компилятор. Если бы кто-нибудь тогда сказал мне, что «компилятор» является синонимом «переводчика кода», было бы намного проще понять, для чего он нужен или зачем он нам нужен. Конечно, это звучит нелепо с современной точки зрения, но это еще раз говорит мне о том, сколько пользы можно получить, просто имея подходящего человека, который научит его чему-то. Спасибо. :)
codepleb
18

Получение написанного вами кода для запуска в браузере включает две вещи:

1) Транспортировка машинописного текста в JavaScript . Это своего рода решенная проблема. Я думаю, они просто используют webpack.

2) Компиляция угловых абстракций в JavaScript . Я имею в виду такие вещи, как компоненты, каналы, директивы, шаблоны и т. Д. Это то, над чем работает команда angular core.

Если вас действительно интересует второй бит, компилятор angular, посмотрите , как автор компилятора Тобиас Бош объясняет Angular Compiler на AngularConnect 2016 .

Я думаю, здесь происходит некоторая путаница между транспиляцией и компиляцией. Это вроде как не имеет значения и зависит от личного вкуса, они оба просто трансформируют представления кода. Но определение, которое я использую лично, заключается в том, что транспиляция осуществляется между двумя разными языками на одинаковом уровне абстракции (например, машинописный текст в javascript), тогда как компиляция требует понижения уровня абстракции. Я думаю, что переход от шаблонов, компонентов, каналов, директив и т. Д. К простому javascript - это шаг вниз по лестнице абстракции, и поэтому он называется компилятором.

Натан Купер
источник
1

Угловой компилятор

Одно из самых важных изменений от Angular 4 к 5 - компилятор был переписан быстрее и тщательнее. В прошлом приложения Angular использовали то, что мы называем JIT-компиляцией, когда приложение компилировалось во время выполнения в браузере перед запуском. Обновления компилятора в Angular 5 продвинули переход к AOT, что сделало приложение быстрее, поскольку оно выполняет меньше компиляции при запуске приложения. AOT включается по умолчанию в любой производственной сборке, начиная с версии 1.5 Angular CLI.

Допустим, мы хотим создать приложение для развертывания и выполнить следующую команду:

ng build --prod

Происходит несколько вещей: производственная версия, минификация, объединяет ресурсы, хеширование имени файла, встряхивание дерева, AOT ... (мы можем включить / отключить это с помощью флагов, например, aot = false). Короче говоря, флаг prod создает оптимизированный пакет приложения, выполняя компиляцию AOT с использованием ngc (компилятор Angular) для создания оптимизированного кода, готового для браузера ( да, он предварительно компилирует шаблоны ).

Компилятор TypeScript

Компилятор TypeScript, tsc , отвечает за компиляцию файлов TypeScript. Именно компилятор отвечает за реализацию функций TypeScript, таких как статические типы, и в результате получается чистый JavaScript, из которого были удалены ключевые слова и выражения TypeScript.

Компилятор TypeScript имеет две основные функции: это транспилятор и средство проверки типов. Компилятор преобразует TypeScript в JavaScript. Он выполняет следующие преобразования вашего исходного кода:

  • Удалите все аннотации типов.
  • Компилировать новые функции JavaScript для старых версий JavaScript.
  • Скомпилируйте функции TypeScript, которые не являются стандартным JavaScript.

Вызывая его, компилятор ищет конфигурации, загруженные в tsconfig.json (подробный список всех параметров компилятора вместе со значениями по умолчанию можно найти здесь ).

Во многих отношениях компилятор TypeScript работает как любой компилятор. Но есть одно отличие, которое может уловить неосторожных: по умолчанию компилятор продолжает генерировать код JavaScript, даже если он обнаруживает ошибку. К счастью, это поведение можно отключить, установив noEmitOnErrorдля параметра конфигурации значение true в файле tsconfig.json.

Примечание : tsc и ngc имеют разные цели, и речь не идет о выборе одного из них над другим. Этот ответ может быть интересен .

Этот ответ был составлен на основе материалов следующих книг

  • Хлоя, М. (2018). «Проекты Angular 5: научитесь создавать одностраничные веб-приложения, используя более 70 проектов».

  • Дьюи, Б., Гроссниклаус, К., Япикс, П. (2017). «Создание веб-приложений с помощью Visual Studio 2017: использование .NET Core и современных платформ JavaScript».

  • Фриман, А. (2019). «Основной TypeScript: от новичка до профессионала».

  • Гия, П. (2018). «Микросервисы TypeScript».

  • Искандар А., Чивукулу С. (2019). «Веб-разработка с использованием Angular и Bootstrap - третье издание».

  • Хеннесси, К., Арора, К. (2018). «Угловой 6 на примере».

  • Янсен, Р., Вольф, И., Ване, В. (2016). «TypeScript: современная разработка на JavaScript».

  • Мохаммед, З. (2019). «Угловые проекты».

  • Сешадри, С. (2018). «Угловой: Вверх и работает».

  • Уилкен, Дж. (2018). «Угловой в действии».

Тьяго Мартинс Перес 李大仁
источник