Много рассказывать о том, что такое TypeScript, не буду. На мой взгляд, это уже устоявшаяся и хорошо зарекомендовавшая технология, которая предоставляет возможности программирования, которых не хватало раньше в JavaScript. Самыми основными возможностями языка, на мой взгляд, стало более четкое ООП и строгая типизация. И за эти качества я этот язык полюбил и он гармонично вписался в мои проекты.
Все начиналось с того, что я в командной строке вызывал компилятор после каждого изменения проекта и пересобирал проект. Это было жутко не удобно и очень сильно замедляло разработку. Для grunt было расширение grunt-ts которое решало мои задачи и я им какое-то время пользовался. У компилятора TypeScript есть одна особенность (не бага и не фитча, политкорректность), которую во всех расширениях, которые я перепробовал, не учитывалась. Это жутко мешало и заставило писать свой код. grunt-tsc — расширение для grunt, позволяющее собирать проекты на TypeScript, о нем я и хочу рассказать.
Особенность компилятора заключается в том, что при компилировании одного файла с зависимостями в выходной файл попадает код самого компилируемого файла, а также всех файлов указанных в зависимостях. Это очень сильно удивило меня, потому, что нормальный кейс для grunt это компилировать файлы «один к одному». И получается, что при компилировании проекта, когда необходимо иметь большую гору *.js файлов (скомпилированных аналогов *.ts, с общими зависимостями) получается очень много мусора в выходных файлах (очень много дублированного кода, который по сути не нужен). На тот момент, когда я начал писать свое решение, я не смог найти готового кода с фиксом такой особенности компилятора, возможно сейчас это не так. Я подглядел хак (возможно, это где-то задокументированно, не нашел) у watcher'ов idea, он оказался очень простой — запускать компилятор в той директории, в которой располагается *.ts файл и при указании файла не использовать путь, а только название файла, а также не работать с опцией «--out».
Из примера сразу станет все понятно:
tsc --out ./utils/deferred/Deferred.js ./utils/deferred/Deferred.ts
Такое использование приводит к тому, что в файлик Deferred.js содержит все зависимости, которые по сути я хотел компилировать отдельно и содержать в других файла.
cd ./utils/deferred && tsc Deferred.ts
Но, например, такое использование устраняет эту проблему и в выходной файл Deferred.js содержит скомпилированный код только Deferred.ts, при этом проверка зависимостей остается.
Это оказалось тем, что нужно и я написал свое решение. Выдающихся способностей у решения нет, оно просто правильно решает задачу компиляции. Также к grunt модулю добавлена возможность выбора версии компилятора, устранена зависимость от глобальной установки tsc, а также добавлен более гибкий способ указания зависимостей *.d.ts.
Устранение глобальных зависимостей и выбор версии компилятора
Само расширение, по умолчанию, не имеет зависимости от глобальной установки tsc. Компилятор находится внутри модуля и кроме установки модуля больше ничего не требуется. У модуля есть опция options.version при помощи которой можно указать версию компилятора. Можно задавать следующие значения (момент написания статьи): «1.0», «1.1», «1.3», «1.4», «default»(1.3), «latest»(1.4). Поддержка разных версий мне показалась очень полезной и она была реализована, например, если в старых проектах есть зависимость от старых версий компилятора.
Кроме того, компилятор можно указать явно, задав путь к нему при помощи опции options.compiler. При таком использовании опция options.version будет проигнорирована. Например, если все таки хочется использовать системно установленных компилятор, то опция должна иметь значение «/usr/local/lib/node_modules/typescript/bin/tsc.js». Да, тут есть очень важный момент, опция должна указывать на *.js файл.
Указание зависимостей
За зависимости отвечает 3 опции:
- options.references — эта опция задается в виде строки или массива строк и является маской (расширение glob) поиска файлов деклараций *.d.ts.
- options.libray — это булева опция, которая указывает на то, что должен быть подключен файл lib.d.ts текущего компилятора, даже если он задан через опцию options.compiler.
- options.system — эта опция очень похожа на опцию options.references, за тем исключением, что поиск зависимостей осуществляется в папке текущего компилятора (для последних версий *.d.ts стало очень много), даже если он задан через опцию options.compiler.
Остальные опции расширения повторяют опции компилятора и в них легко можно разобраться, я их описывать не стану. Общее количество опций настройки очень большое, но это не должно пугать, это все опционально и компиляция заводится на дефолтных значениях.
Мне кажется, что расширение правильно выполняет свою задачу и дополнять его новыми возможностями не стоит. Единственное, что хочу добавить — это предпроцессинговые инструкции, но они могут повлиять на sourcemap'ы, вот думаю как аккуратнее это сделать. А также TypeScript развивается и мной будут поддерживаться свежие версии компилятор. Буду очень рад, если расширение кому либо пригодится, а также буду рад отзывам.
Официальный сайт TypeScript
Расширение glob
Расширение grunt-tsc
Автор: rodzewich_oleg