предисловие
Я был в лаборатории языков программирования Huawei в марте.дипланг сообщество(сообщество языков программирования для студентов колледжей, поддерживающее язык программирования в сфере Интернета вещей под названием deeplang) поделились один раз"Комплект инструментов для перевода и упаковки в области пользовательского интерфейса". В то время ppt был сделан в спешке, позже я улучшил содержание и организовал его в статью, чтобы поделиться с вами.
Ниже приведен текст:
Компиляция и перевод
определение
Компиляция (компиляция) — это преобразование одного языка программирования в другой язык программирования, обычно относится к языку высокого уровня в язык низкого уровня.
Язык высокого уровня относится к языку, который легко читается и организуется, описывается символами и имеет такие функции, как условность, ветвление, цикл, объектно-ориентированный и т. д. Он не заботится о деталях выполнения и только используется для описания логики, такой как Javascript, C++ и т. д.
Язык низкого уровня относится к языку, который напрямую манипулирует регистрами и другим конкретным оборудованием.Он заботится о деталях выполнения, не имеет многих функций языков высокого уровня и, как правило, не описывается символами, такими как машинный язык и язык ассемблера. .
Transpile — это особый вид компиляции, то есть компиляция с языка высокого уровня на язык высокого уровня, например, с C++ на Java, с Typescript на Javascript, с Javascript на Javascript, с Css на Css и т. д.
Зачем нужен переводчик во front-end домене?
Поле внешнего интерфейса в основном состоит из HTML, CSS, JS:
HTML и css анализируются из исходного кода в dom и cssom, а затем генерируется дерево рендеринга и передается механизму рендеринга для рендеринга. Это объясняется из исходного кода.
js — это язык сценариев, который также анализирует исходный код в AST во время выполнения, а затем преобразует его в байт-код для интерпретации и выполнения. Также из исходного кода.
Продуктом цели является исходный код, поэтому во внешнем сценарии естественно использовать различные трансляторы исходного кода.
Какие переводчики нужны во front-end домене
Перевод заключается в создании исходного кода после изменения исходного кода, который является исходным кодом. Какие трансляторы нужны во front-end домене?
Javascript
- Версия es обновляется быстро.Целевая среда es 2015, es 2016, es 2017 и другие новые функции не поддерживаются, но если вы хотите использовать их в разработке, вам нужен переводчик для преобразования этих функций в поддерживаемые целевая среда, такая как babel и typescript.
- Javascript является динамически типизированным языком, нет концепции типа проверки типа во время компиляции, которую нельзя продвигать. Javascript хочет присоединиться к типу синтаксиса и семантики, но его нужно компилировать после того, как тип информации будет удален, что также требует транслятора, например, машинописного текста, потока.
-
Некоторые фреймы требуют некоторого грамматического сахара, такого как React.CreateElement, написанный React.CreateElement, я надеюсь использовать XML-подобный способ при разработке, компилятор, компилятор, компилятор для конкретных API, таких как JSX.
-
Код нужно сжимать и проводить различные оптимизации (удаление мертвого кода и т.д.) во время компиляции, а затем превращать в объектный код, например терсер.
- Некоторые ошибки спецификации кода, такие как eslint, необходимо проверять во время компиляции.
Css
- Некоторые возможности, такие как переменные, функции, циклы, вложенность и т. д., необходимо расширить, чтобы упростить управление CSS, например, DSL (предметно-ориентированный язык), например, scss, less и стилус или css next, которые проходит через scss, less и стилус соответственно. , postcss и другие транспиляторы для преобразования в целевой css.
- Необходимо обрабатывать префиксы совместимости (автопрефиксер), проверку спецификаций css (stylelint), модульность css (модули css) и т. д. Они поддерживаются транспилером postcss.
Html
- Как и css, некоторые возможности должны быть расширены, такие как наследование, композиция, переменные, циклы и т. д. Они поддерживаются шаблонизаторами, такими как pug и moustache, а также есть свои собственные трансляторы для преобразования исходного кода в объектный код во время компиляции. (это преобразование также может быть выполнено во время выполнения).
- Поддерживает различный контент для преобразования HTML, например, MarkDown в HTML и т. д., который можно перевести с помощью posthtml.
Короче говоря, внешний домен требует много транспиляторов.
Так много переводчиков, каковы их принципы?
Принцип переводчика
Процесс компиляции
На самом деле процесс компиляции у этих трансляторов схож, и всем им нужно три этапа: парсинг, трансформация и генерация.
(Хотя конкретные имена могут быть другими, например, postcss вызывает генерацию строки, а компилятор шаблона vue вызывает стадию трансформации, оптимизацию)
Зачем нужны эти 3 этапа?
До и после преобразования транслятор представляет собой строку исходного кода. Чтобы выполнить преобразование, вы должны сначала понять код. То, как компьютер понимает код, заключается в организации информации в исходном коде через определенную структуру данных. Эти данные структура抽象语法树
.
Он абстрактный, потому что такие разделители, как запятые, круглые скобки и т. д., игнорируются. Причина, по которой это дерево, заключается в том, что код обычно является вложенным, и для представления вложенных отношений исходного кода необходимо использовать отношение родитель-потомок дерева. Таким образом, абстрактные синтаксические деревья являются наиболее подходящими структурами данных для понимания кода компьютерами.
После понимания кода (генерация AST) необходимо выполнить различные преобразования, например, terser выполнит оптимизацию компиляции, такую как удаление мертвого кода, babel сделает es рядом с переносом целевой среды js, компилятор typescript выполнит проверку типов на AST , а postcss тоже сделает ряд обработок по AST и так далее. Это все анализы и добавления и удаления в AST.
Однако, хотя разные транспиляторы будут обрабатывать AST по-разному, их общий процесс компиляции схож, что является общим принципом транспиляторов.
sourcemap
У переводчиков есть особенность, что все они имеют исходные карты. sourcemap — это отношение сопоставления между сгенерированным кодом и исходным кодом, посредством которого его можно сопоставить с исходным кодом. Переводчики — это все исходники в исходники, и естественно будет исходная карта.
{
version : 3,
file: "out.js",
sourceRoot : "",
sources: ["foo.js", "bar.js"],
names: ["src", "maps", "are", "fun"],
mappings: "AAgBC,SAAQ,CAAEA"
}
Например, выше приведен файл исходной карты, и значения соответствующих полей следующие:
-
version: Версия исходной карты, в настоящее время 3.
-
файл: преобразованное имя файла.
-
sourceRoot: каталог, в котором находятся файлы до преобразования. Если он находится в том же каталоге, что и файл перед преобразованием, этот элемент пуст.
-
Исходники: файлы до конвертации. Этот элемент представляет собой массив, поскольку можно объединить несколько исходных файлов в один объектный файл.
-
имена: все имена переменных и имена атрибутов перед преобразованием, все имена переменных извлекаются, а следующие сопоставления напрямую ссылаются на индексы, что может уменьшить объем.
-
сопоставления: набор сопоставлений между кодом до преобразования и кодом после преобразования Для представления строки используется точка с запятой, а сопоставления каждой строки разделяются запятыми.
Рекомендуется конкретная информацияСтатья Руан Ифэн
Где используется исходная карта?
Обычно мы используем исходную карту для двух целей:
Найдите исходный код при отладке кода
Такие браузеры, как chrome и firefox, поддерживают добавление в конец файла.однострочный комментарий
//# sourceMappingURL=http://example.com/path/to/your/sourcemap.map
Может быть связан через URL SourceMap или передается в Base64 Inline Manse. Браузер автоматически анализирует SourceMap, связанный с источником. Эта точка перерыва, ошибка будет соответствовать соответствующему другому источнику стека.
Онлайн-ошибка находится в исходном коде
Sourcemap будет использоваться для отладки во время разработки, но не в продакшене, и будет большой аварией, если sourcemap будет передан в продакшн. Однако при сообщении об ошибках в Интернете необходимо найти исходный код.В этом случае исходная карта обычно загружается на платформу сбора ошибок отдельно.
Например, sentry предоставляет плагин веб-пакета sentry для автоматической загрузки исходной карты в фоновый режим sentry после упаковки, а затем удаления локальной исходной карты. Sentry-cli также позволяет пользователям загружать файлы вручную.
Конечно, не только sentry, аналогичные платформы анализа, такие как byte dynatrace, также поддерживают
Обычно мы используем исходную карту по крайней мере в этих двух сценариях (отладка исходного кода во время разработки и позиционирование ошибок во время производства).
Принцип исходной карты
Знаете роль исходной карты, как генерируется исходная карта?
Конкретная сгенерированная логика может быть сгенерирована с помощьюsource-mapЧтобы завершить этот пакет, предоставляемый Mozilla, нам нужно только предоставить каждое сопоставление, то есть номера строк и столбцов в исходном коде и номера строк и столбцов в целевом коде.
Когда исходный код анализируется в AST, его положение в исходном коде (строка, столбец) будет сохранено в AST.
Преобразование AST не изменяет номер этой строки и столбца.
При генерации объектного кода будет рассчитана новая позиция (строка, столбец).
Таким образом, комбинация двух позиций является отображением. Сопоставление всех узлов AST может создать полную исходную карту.
Вот как генерируется исходная карта.
Переводчики во внешнем домене
Представлены общий принцип транслятора и принцип исходной карты, рассмотрим конкретный транслятор.
babel
babel — это транспайлер, который преобразует es next, typescript, flow, jsx и другие синтаксисы в синтаксисы, поддерживаемые в целевой среде, и вводит полифиллы для отсутствующих API.
Его процесс компиляции также представляет собой стандартные 3 этапа разбора, преобразования и генерации.
Он обеспечивает использование API и командной строки.
API Бабеля
Babel 7 включает следующие пакеты:
@babel/parser преобразует код в ast и может использовать плагины, такие как машинописный текст, jsx, поток и т. д., для анализа соответствующей грамматики.
@babel/traverse проходит ast и вызывает функцию посетителя
@babel/generate печатает ast в целевой код и генерирует исходную карту
@babel/types создает и оценивает узлы ast
@babel/template Пакетно создает узлы ast на основе шаблонов кода.
@babel/core Полный процесс преобразования исходного кода в целевой код с применением внутреннего плагина преобразования Babel.
На основе API из этих пакетов могут быть завершены различные преобразования кода JS.
демонстрация API Babel
Мы используем вышеуказанный API для завершения функции, которая вставляет некоторые параметры в console.log и console.error.
Идея состоит в том, чтобы повторно вставить соответствующее содержимое в параметр arguments при обнаружении узла CallExpression, соответствующего console.*.
Давайте реализуем это с помощью кода:
Запустите, чтобы увидеть эффект:
Вы можете видеть, что соответствующие параметры вставляются в console.log и console.error, а также генерируется исходная карта.
Чтобы узнать больше о принципах и кейсах Babel, вы можете обратить внимание на мою готовящуюся к выпуску брошюру «Читы для очистки подключаемых модулей Babel».
typescript compiler
Typescript расширяет синтаксис и семантику типов на Javascript, сначала выполнит вывод типа, а затем проверит AST на основе типа, чтобы можно было найти какие-то ошибки при компиляции, а затем будет сгенерирован объектный код.
Компилятор typescript разделен на 5 частей:
-
Сканер: генерировать токен из исходного кода (лексический анализ)
-
Парсер: создание AST из токена (анализ синтаксиса)
-
Связующее: генерировать символ из AST (семантический анализ - генерировать область, выполнять разрешение ссылки (то есть, была ли объявлена ссылочная переменная))
-
Checker: Type Check (Семантический анализ -- Type Check)
-
Emitter: сгенерируйте окончательный файл JS (генерация объектного кода)
На самом деле эти этапы также могут соответствовать большим этапам синтаксического анализа, преобразования и генерации (babel также выполняет семантический анализ области действия, аналогично связующему tsc).
(Область действия обычно создается в процессе обхода, поэтому семантический анализ помещается на этап преобразования. Часть преобразования AST на рисунке не показана, но есть).
Процесс компиляции машинописного компилятора также может соответствовать трем этапам транслятора, но компилятор машинописного текста выполняет больше семантического анализа (проверки типов).
API компилятора машинописного текста
API компилятора машинописного текста не является стабильным, и документация отсутствует, но оно представлено в пакете машинописного текста и доступно.
Давайте посмотрим на API для синтаксического анализа, преобразования и генерации в машинописном тексте:
parse
Тип ts часто получается из нескольких файлов, нужно сначала создать Программу, а потом получить AST соответствующий определенному пути, то есть объект SourceFile. (Это отличается от babel, babel — это прямой анализ исходного кода в AST, здесь два шага)
transform
Обход AST с помощью ts.visitEachChild, создание AST с помощью ts.createXxx, замена AST с помощью ts.updateXxx Определите тип AST по ts.SyntaxKind.
В соответствии с некоторыми API пакетов @babel/traverse и @babel/types соответственно, вы обнаружите, что когда вы изучаете транспилятор, остальные транспиляторы похожи.
generate
Распечатайте AST в объектный код через принтер.
tsc vs babel
Мы знаем, что @babel/parser уже поддерживает синтаксический анализ синтаксиса машинописного текста после babel 7, поэтому должны ли мы использовать babel для компиляции ts или использовать официальный компилятор машинописного текста?
я думаюКомпилируется babel ts, выполняя отдельную проверку типов tsc --noEmitявляется лучшим решением.
Причины следующие:
-
babel может скомпилировать почти весь синтаксис ts, и есть несколько неподдерживаемых случаев, которые можно обойти.
-
Код, сгенерированный babel, преобразует синтаксис и вводит полифиллы по мере необходимости в соответствии с конфигурацией целей, что позволяет генерировать меньший целевой код. Однако typescript по-прежнему является грубой целью для указания es5 и es3 и не может быть преобразован по запросу.Введение полифиллов также вводится на входе, и объем генерируемого кода будет больше.
-
Babel богат плагинами, и мало кто знает о плагине преобразования машинописного текста, не говоря уже об экологии.
-
Babel компилирует ts-код без проверки типов, что быстрее.Если вы хотите выполнить проверку типов, вы можете выполнить tsc --noEmit отдельно.
Таким образом, использование tsc для проверки типов и babel для преобразования кода является лучшим выбором.
eslint
eslint может проверять спецификации кода в соответствии с настроенными правилами, а некоторые правила можно восстанавливать автоматически.
Пользователь настраивает некоторые правила, и eslint проверяет AST на основе этих правил.
Он также предоставляет два метода: API и командную строку, и метод API будет использоваться при разработке цепочки инструментов.
Демонстрация плагина eslint
Напишем правило eslint: сообщать об ошибке при обнаружении console.time, а также можно автоматически удалить --fix
На самом деле идея аналогична плагину babel, оба являются режимом посетителя, который объявляет, какой тип узла AST выполнять, но форма несколько отличается.
Объявите некоторую метаинформацию в meta, например, какая информация отображается в документе, можно ли это исправить, что такое сообщение об ошибке и т. д.
Вы можете получить некоторые api в посетителе, возвращаемом create.Например, при вызове api отчета будет сообщено об ошибке.Если указан метод исправления, он также может быть исправлен автоматически, когда пользователь указывает параметр --fix, например fixer.remove здесь, чтобы удалить AST.
terser
terser — это оптимизированный для компилятора транспилятор, который сжимает, запутывает и удаляет мертвый код для кода JS. По сути, это также обязательный инструмент в цепочке инструментов внешнего интерфейса.
Изначально это был uglifyjs, но поскольку он не поддерживает синтаксический анализ и оптимизацию кода выше es6, был написан терсер.
terser поддерживает различные параметры сжатия и обфускации, которые можно найти вДокументациядля деталей.
Он также поддерживает командную строку и использует API. апи следующим образом:
swc
swc — это JS-переводчик, написанный на rust, отличающийся высокой скоростью.
Каким бы быстрым ни был парсер, написанный на Javascript, это всего лишь недостаток интерпретируемого языка: во время выполнения он парсит из исходного кода, а затем интерпретирует и выполняет, что будет медленнее, чем компилируемый язык.
Его цель — заменить babel, а удастся ли его заменить — зависит от дальнейшего развития.
postcss
Транслятор css, похожий на babel, также поддерживает плагины, и экосистема плагинов очень процветающая.
Он предоставляет API-интерфейсы для обработки, обхода и преобразования в строки, соответствующие трем этапам анализа, преобразования и генерации соответственно.
Например, следующий код извлекает все зависимости (url(), @import) в css.
плагин для postcss
У Postcss есть мощная экология плагинов, как у Babel.
Его плагин имеет форму:
Плагины также являются дополнениями, удалениями и модификациями AST, но есть различия.Это не режим посетителя, как плагины eslint и babel, а необходимо самостоятельно пройти AST, найти целевой AST и затем преобразовать его. (То же самое касается API-интерфейса компилятора машинописного текста, например, его ts.forEachChild).
Мы можем сделать вывод, что у переводчика есть два способа работы с AST: режим посетителя и режим ручного поиска.
- Реализация шаблона посетителя включает в себя: babel, eslint
- Реализация режима ручного поиска включает в себя: компилятор typscript, postcss, posthtml
posthtml
Как видно из названия, posthtml переводит html и поддерживает плагины.
Например, пример плагина posthtml:
Метод обхода — это метод ручного поиска, аналогичный postcss.
prettier
prettier — это транспилятор для форматирования кода.В отличие от других транспиляторов, которые в основном работают на этапе преобразования, его основная логика заключается в поддержке более удобного формата на этапе генерации, например, поддержка автоматического переноса строк, когда код слишком длинный.
Он имеет некоторые перекрывающиеся части с eslint и stylelint.Как правило, правила, связанные с форматированием инструмента lint, отключены, и сохраняются только некоторые проверки ошибок.Например, плагины eslint-prettier и stylint-prettier делают это.
Prettier — это скорее подход командной строки, но API-интерфейсы также используются при разработке наборов инструментов.
Он может форматировать не только js, css, но и многие другие коды.
Использование переводчика в проекте
Выше мы представили серию трансляторов, каждый из которых выполняет разные функции, как эти трансляторы используются в нашем проекте?
Существует три способа применения переводчика в проекте:
-
Иде плагин. При написании кода выполняйте проверку кода, проверку типов, форматирование и т. д. в режиме реального времени, например, часто используемый плагин eslint vscode, плагин typescript vscode (он встроен) и т. д.
-
git хуки. Инициируйте выполнение с помощью хука git commit от Husky. Например, красивее, это нужно форматировать только при отправке кода.
-
Вызывается инструментом упаковки. Транслятор предназначен для одного файла, а инструмент упаковки для нескольких файлов.В процессе упаковки каждый файл будет обработан вызовом соответствующего транслятора, такого как загрузчик веб-пакета.
Суммировать
Сначала мы определили различия в компиляции и переводе, обсуждаем, почему полю во внешнем интерфейсе нужен переводчик, переводчик, что нужно сделать.
Затем я изучил общий процесс транслятора: парсинг, преобразование, генерация и узнал роль и принцип исходной карты.
После этого мы узнали о транспиляторах, таких как babel, typescript, eslint, terser, swc, postcss, posthtml и prettier, и узнали об их функциях и использовании, а также о том, как писать плагины.
Наконец, мы суммируем три способа использования транспилятора в проекте: плагин ide, git hooks и загрузчик инструмента упаковки.
Надеюсь, эта статья дала вам полное представление о транспиляторах.
(Это первая половина содержания «Цепочки инструментов перевода и упаковки в области внешнего интерфейса», которой я поделился с Huawei. В ней много контента, и она разделена на две статьи. Следующая статья — вторая половина «Схемы инструментов для перевода и упаковки в области клиентской части», в которой будет рассказано о модуляризации, инструментах упаковки, интерпретаторах и замкнутом цикле разработки клиентской части. )