Использование Bazel с TypeScript
Bazel — это проект с открытым исходным кодом, изначально созданный Google, доработанный и протестированный в течение многих лет для запуска ресурсоемких, критически важных сервисов и приложений. Это отличный выбор для создания и тестирования проектов. Расширенное выполнение распределенного кэширования Bazel создает быстрые инкрементные и настраиваемые сборки, перестраивая только то, что необходимо. Он работает на нескольких языках и платформах, таких как Java, Go и JavaScript, а также в операционных системах, таких как IOS, Android, Linux и Windows.
Bazel автоматизирует сборку и тестирование программного обеспечения для таких задач, как запуск компиляторов и компоновщиков для создания исполняемых программ и библиотек, таких как преобразование файла JAVA в исполняемый файл JAR. Bazel можно сравнить с такими инструментами, как Apache Maven, Apache Ant, GNU Make или Gradle, но он стоит выше всех благодаря многоязычной и многоплатформенной поддержке. Он поставляется с настраиваемым языком высокого уровня Starlark, который описывает, как должен быть построен проект. Масштабируемость Bazel позволяет ему расти вместе с вашей кодовой базой и организацией. Он может работать с кодовыми базами любого размера, будь то огромные монолитные репозитории или несколько репозиториев.
Сборки TypeScript с помощью Bazel выполняются намного быстрее при использовании функции удаленного выполнения Bazel, которая позволяет выполнять сборку и тестирование параллельно на нескольких компьютерах, например в центре обработки данных. Это означает, что вы можете масштабировать свои сборки по горизонтали. Bazel также поддерживает удаленное кэширование, которое может значительно улучшить процесс разработки, избегая различий между средами разработки, например, один пользователь использует macOS, а другой - Windows.
В этом руководстве рассматривается, как опытные разработчики могут добавить Bazel в проект TypeScript для запуска быстрых и настраиваемых сборок. Вы научитесь настраивать Bazel в соответствии со своими потребностями с помощью правил Bazel. Вы также научитесь добавлять тесты, запускать их с помощью Bazel, а затем публиковать в npm.
TypeScript и Bazel
TypeScript — это язык, построенный на основе JavaScript. Это надмножество JavaScript, что означает, что он наследует все возможные функции JavaScript. TypeScript имеет два преимущества. Во-первых, он преобразует TypeScript в JavaScript, так что все расширенные функции ECMAScript, недоступные во всех браузерах, могут быть реализованы с помощью полифилла. Во-вторых, он применяет статическую типизацию, чтобы обнаруживать потенциальные проблемы и ошибки на более ранних этапах жизненного цикла разработки программного обеспечения.
При использовании Bazel вы столкнетесь с несколькими правилами Bazel, созданными на основе компилятора TypeScript, которые можно использовать при настройке Bazel. Правила Bazel, которые обычно называют файлами BUILD, определяются как набор команд, которые работают с входными файлами для создания выходных данных, например, для преобразования файла TypeScript в файл JavaScript. Эти правила часто являются частью пакета Bazel; например, rules_nodejs
. Некоторые из этих правил заключаются в следующем:
tsc
: это встроенный компилятор TypeScript, разработанный командой Microsoft. После загрузки rules_nodejstsc
можно показать в файле BazelBUILD
, добавив в него оператор загрузкиload("@npm//typescript:index.bzl", "tsc")
. Вот пример использованияtsc
в конфигурационном файле Bazel.ts_config
: это правило используется для добавления файла конфигурации TypeScript в Bazel. С помощью этого правила вы можете передать ему файлtsconfig.json
или даже добавить к нему дополнительный файл конфигурации JSON с помощью параметраdeps
.ts_project
: это правило Bazel, которое может заменить правилоtsc
. Это позволяет использовать множество параметров, таких какsrcs
, исходные данные для переноса;out_dir
, каталог, куда должны помещаться выходные файлы;tsconfig
, используемый файл TSConfig; или объект JSON, содержащий правила транспиляции. Любое правило, которое работает сtsc
, должно работать и сts_project
.
Создайте приложение TypeScript с помощью Bazel
Для целей этого руководства вы создадите базовое приложение TypeScript, а затем создадите и протестируете его с помощью Bazel. Убедитесь, что у вас есть Node.js установлен на вашем компьютере.
Начните с создания каталога с именем demo_bzl_app
:
$ mkdir demo_bzl_app && cd demo_bzl_app
Запустите проект Node.js, выполнив следующую команду:
$ npm init
Затем установите TypeScript:
$ npm config set save-prefix=''
$ npm install typescript@4.9.5 --save-dev
Теперь в вашем каталоге должны быть файлы package.json
и package-lock.json
.
Далее вы создадите файл tsconfig.json
, в котором вы определите параметры компилятора TypeScript. Это можно сделать автоматически, выполнив следующее:
npx tsc --init --rootDir src --esModuleInterop --resolveJsonModule \
--lib 'es6, dom' --module commonjs --allowJs true --noImplicitAny true
Чтобы узнать больше о том, что означают эти параметры, см. документ Справочник по TSConfig. На этом этапе у вас должен быть файл tsconfig.json
в корневом каталоге.
Теперь создайте каталог src
, в котором будет жить код приложения. Внутри него создайте файл с именем index.ts
. Расширение .ts
указывает, что файл является файлом TypeScript:
$ mkdir src && touch readme.MD && touch src/index.ts
В файле index.ts
добавьте следующий код:
#!/usr/bin/env node
"use strict";
export function adder (one: number, two: number) {
return one + two
}
export function concatenate (one: string, two: string) {
return one + two
}
console.log("Hello! Welcome.");
Обычно файлы TypeScript .ts
должны быть скомпилированы в файлы .js
для выполнения. Обычно для компиляции кода используется npx tsc
. tsc
прочитает файл tsconfig.json
и применит конфигурации при компиляции кода JavaScript. Но в этом уроке вы увидите, как вместо этого использовать Bazel.
Чтобы начать использовать Bazel, установите его на свой компьютер. Bazel можно установить на Linux, macOS и Windows. Чтобы узнать, как установить его для вашей платформы, воспользуйтесь их руководством по установке. Подтвердите, что он у вас установлен, набрав bazel
в командной строке:
Чтобы определить проект Bazel, вам нужно превратить его в рабочую область. Рабочая область — это каталог, в котором хранится исходный код проекта и выходные данные сборки Bazel. Есть два важных файла, которые делают это возможным: файл WORKSPACE
и файл BUILD
.
Файл WORKSPACE
помогает Bazel идентифицировать каталог как проект Bazel, а файл BUILD
помогает Bazel идентифицировать каталог как пакет Bazel. Проект Bazel может иметь в себе один или несколько пакетов, а пакет может содержать подпакеты или подкаталоги, содержащие файлы BUILD
, таким образом образуя иерархию.
Создайте файл WORKSPACE
и файл BUILD
в корневом каталоге demo_bzl_app
:
touch WORKSPACE && touch BUILD
В будущих проектах вы можете назначить каталог рабочим пространством Bazel, создав в этом каталоге пустой файл с именем WORKSPACE
. Файл WORKSPACE
может быть пустым, но он также может содержать инструкции для Bazel по загрузке зависимостей, необходимых для проекта Bazel.
В файле WORKSPACE
добавьте следующий код:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "aspect_rules_ts",
sha256 = "7d964d57c6e9a54b0ce20f27e5ea84e5b42b6db2148ab7eb18d7110a082380de",
strip_prefix = "rules_ts-1.2.4",
url = "https://github.com/aspect-build/rules_ts/releases/download/v1.2.4/rules_ts-v1.2.4.tar.gz",
)
##################
# rules_ts setup #
##################
# Fetches the rules_ts dependencies.
# If you want to have a different version of some dependency,
# you should fetch it *before* calling this.
# Alternatively, you can skip calling this function, so long as you've
# already fetched all the dependencies.
load("@aspect_rules_ts//ts:repositories.bzl", "rules_ts_dependencies")
rules_ts_dependencies(
# This keeps the TypeScript version in-sync with the editor, \
which is typically best.
ts_version_from = "//:package.json",
# Alternatively, you could pick a specific version, or use
# load("@aspect_rules_ts//ts:repositories.bzl", "LATEST_VERSION")
# ts_version = LATEST_VERSION
)
# Fetch and register node, if you haven't already
load("@rules_nodejs//nodejs:repositories.bzl", "DEFAULT_NODE_VERSION", \
"nodejs_register_toolchains")
nodejs_register_toolchains(
name= "node",
node_version = DEFAULT_NODE_VERSION,
)
# Register aspect_bazel_lib toolchains;
# If you use npm_translate_lock or npm_import from aspect_rules_js \
you can omit this block.
load("@aspect_bazel_lib//lib:repositories.bzl", \
"register_copy_directory_toolchains", \
"register_copy_to_directory_toolchains")
register_copy_directory_toolchains()
register_copy_to_directory_toolchains()
Файл BUILD
содержит несколько инструкций для Bazel по сборке пакета; эти инструкции называются правилами. В файле BUILD
добавьте следующие правила для сборки файла TypeScript в src/index.ts
:
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")
ts_project(
name="transpile",
srcs = ["src/index.ts"],
tsconfig= "//:tsconfig.json",
allow_js=True,
resolve_json_module=True
)
Предыдущие правила в файле BUILD
сообщают Bazel следующее:
- Правило называется
transpile
. - Входные файлы, которые необходимо скомпилировать, находятся по пути
src/index.ts
. - Bazel должен извлечь конфигурацию компилятора из файла
tsconfig.json
в текущем каталоге, обозначаемом//
. allow_js
имеет значениеTrue
, что означает, что TypeScript должен разрешать импорт файлов JavaScript в файлы проекта.ts
.- Для параметра
resolve_json_module
задано значениеTrue
, что означает, что Bazel должен разрешать импорт файлов с расширением.json
в файлы проекта.ts
.
Чтобы собрать этот пакет, выполните следующую команду:
$ bazel build //:transpile
Это скомпилирует файл TypeScript в src/index.js
к файлам JavaScript. К настоящему времени у вас должны быть свежесозданные папки Bazel, такие как bazel-bin
и bazel-out
. Это папки, в которые Bazel помещает ваши выходные данные сборки. Если вам когда-нибудь понадобится избавиться от них, вы можете просто запустить bazel clean
, который удалит выходные данные из вашей сборки и сбросит внутренние кэши.
Результат предыдущей сборки можно найти в bazel-bin/src/index.js
, который является символической ссылкой на bazel-out/darwin-fastbuild/bin/src/index.js
. Это результат вашей сборки, который отражает каталог src
в корневой папке.
Запустите выходной файл, запустив bazel-out/darwin-fastbuild/bin/src/index.js
. Вы должны получить Hello! Welcome.
вывод в консоль.
Добавьте тесты с помощью Jest
В этом руководстве вы будете использовать Jest для добавления тестов в проект demo_bzl_app
. Начните с добавления Jest в npm:
npm install --save-dev jest ts-jest @types/jest
Затем вам нужно настроить Jest, выполнив следующее:
npx ts-jest config:init
Это создаст файл jest.config.js
, который сообщает Jest и ts-jest
, как обрабатывать файлы .ts
. Кроме того, в файле WORKSPACE
вы должны загрузить зависимость с именем rules_jest
. Это библиотека Bazel, которая упрощает использование Jest с Bazel. Добавьте в файл WORKSPACE
следующее:
http_archive(
name = "aspect_rules_jest",
sha256 = "9f327ea58950c88274ea7243419256c74ae29a55399d2f5964eb7686c7a5660d",
strip_prefix = "rules_jest-0.15.0",
url = "https://github.com/aspect-build/rules_jest/archive/refs/tags/v0.15.0.tar.gz",
)
####################
# rules_jest setup #
####################
# Fetches the rules_jest dependencies.
load("@aspect_rules_jest//jest:dependencies.bzl", "rules_jest_dependencies")
rules_jest_dependencies()
# Fetches the npm packages for jest-cli.
load("@aspect_rules_jest//jest:repositories.bzl", "jest_repositories")
jest_repositories(name = "jest")
load("@jest//:npm_repositories.bzl", jest_npm_repositories = \
"npm_repositories")
jest_npm_repositories()
Затем создайте тестовую папку и тестовый файл:
mkdir tests && touch tests/index.test.ts
В index.test.ts
добавьте следующее:
let { adder, concatenate } = require('../src/index.ts');
describe('adder module', () => {
test('test_adder', ()=> {
expect(adder(1,2)).toBe(3)
});
});
describe('concatenate module', () => {
test('test_concatenate', ()=> {
expect(concatenate('mary',' had a little lamb'))\
.toBe('mary had a little lamb')
});
});
Приведенный выше код добавляет тестовые примеры для функций в src/index.ts
.
Вам все еще нужно добавить способ, которым Bazel может вызывать Jest. В файле BUILD
добавьте следующее:
load("@aspect_rules_jest//jest:defs.bzl", "jest_test")
jest_test(
name = "test",
config = "jest.config.js",
data = [
"src/index.ts", # the test file below depends on this file
"tests/index.test.ts",
],
)
jest_test
— это функция правила, загруженная из зависимостей, ранее загруженных в ваш файл Bazel WORKSPACE
. Он называет правила test
и сообщает Bazel, где найти файл конфигурации Jest. В нем также перечислены тестовый файл index.tests.ts
и тестируемый файл index.ts
.
Теперь вы можете запустить свои тесты с помощью Bazel, используя следующий код:
$ bazel run //:test
Публикация в npm
Чтобы опубликовать этот пакет в npm, вы сначала внесете некоторые изменения в файл BUILD
, добавив новое правило. Добавьте в файл BUILD
следующее:
load("@aspect_rules_js//npm:defs.bzl", "npm_package")
npm_package(
name="demo_bzl_app",
srcs = [":transpile", "readme.md", "package.json"],
package="demo_bzl_app",
)
Здесь правило называется demo_bzl_app
. srcs
просит Bazel использовать выходные файлы из правила transpile
. Помните, что правило transpile
— это первое правило в файле BUILD
. Это гарантирует, что transpile преобразует файлы TypeScript в .js
до того, как пакету будет присвоено имя. Правило также требует от Bazel включения файлов readme.md
и package.json
, поскольку они потребуются для публикации в npm
.
Теперь все, что вам нужно сделать, это запустить следующую команду:
$ bazel build //:demo_bzl_app
Перейдите в папку bazel-out/darwin-fastbuild/bin/
. Вы должны увидеть папку с именем demo_bzl_app
, которая содержит скомпилированные исходные файлы библиотеки .js
, а также файлы readme.md
и package.json
. Это папка, которая будет опубликована в npm.
Затем создайте файл .gitignore
и добавьте в него следующее:
bazel-*
node_modules
Затем запустите git init
, git add
и git commit
, чтобы инициализировать репозиторий Git, добавить и зафиксировать все соответствующие файлы в Git соответственно.
Прежде чем вы сможете опубликовать свой пакет, вам необходимо создать учетную запись npm по адресу https://www.npmjs.com/signup. Войдите в свою учетную запись npm, используя npm login
.
Затем создайте файл с именем publish.sh
и добавьте следующее:
#!/bin/bash
echo "Removing old Bazel outputs"
bazel clean
echo "Running tests"
bazel run //:test
echo "Building package"
bazel build //:demo_bzl_app
echo "moving to output dir"
cd bazel-out/darwin-fastbuild/bin/demo_bzl_app
while true; do
read -p "Are you ready to publish to NPM? " yn
case $yn in
[Yy]* )
echo "Now publishing package to NPM";
npm publish; break;;
[Nn]* ) exit;;
* ) echo "Enter yes or no.";;
esac
done
echo "Done!"
Предыдущий скрипт удалит старые выходные данные Bazel, а затем запустит тесты и создаст выходные файлы перед публикацией в npm. В опубликованный пакет будет включена только папка demo_bzl_app
. (README.md
и package.json
включены по умолчанию.)
Теперь вы можете публиковать:
$ bash publish.sh
Вы можете просмотреть свой пакет на npm. URL-адрес: https://npmjs.com/package/<your-package-name>
. Для этого руководства это https://npmjs.com/package/demo_bzl_app. Обязательно увеличьте версию выпуска в package.json
при следующей попытке публикации, чтобы избежать ошибки.
Если вы хотите увидеть полный исходный код из этого руководства, посетите этот репозиторий GitHub.
Заключение
Теперь вы завершили базовую сборку приложения TypeScript с помощью Bazel. Вы узнали, как определить рабочее пространство, а также пакет. Вы также узнали, как загружать зависимости, добавлять правила, создавать и тестировать проект, а также публиковать в npm - и все это с помощью Bazel.
Bazel - это мощная и гибкая система сборки, которую можно использовать для управления проектами любого размера и сложности. Используя свои функции кэширования и распараллеливания, Bazel может значительно повысить скорость создания и тестирования крупных проектов. Чтобы еще больше углубить ваши знания о Bazel, рекомендуется углубленно изучить его документацию. Официальная документация Bazel содержит обширную коллекцию ресурсов, включая учебные пособия, руководства и справочные материалы, которые могут помочь вам стать экспертом в использовании Bazel для ваших проектов. Итак, если вы хотите узнать больше о Bazel и его возможностях, посетите документы Bazel для получения дополнительных ресурсов.