Как использовать ссылки на проекты в TypeScript 3.0?
В TypeScript 3.0 появилась новая функция, которая называется Ссылки проекта. Это предполагает лучшее взаимодействие модулей *.ts
между собой. К сожалению, это все, что я мог получить из официальной документации, хотя она написана довольно четко и прямо.
Может ли кто-нибудь помочь мне точно понять, какие проблемы он решает, как он это делает и как я могу от этого выиграть? У меня есть проект с похожей структурой, поэтому он может (или не может) быть очень полезным для него. Заранее спасибо!
UPD: структура проекта примерно такая:
project/
lib/
index.ts # defines the original code
test/
index.spec.ts # requires lib/index.ts
package.json
tsconfig.json
Ответы
Ответ 1
Since the question gets more and more upvotes, I dug into it and managed to understand the feature.
Hope this answer is helpful.
TL; DR:
Эта функция позволяет определять части проекта как отдельные модули TypeScript. Помимо прочего, это позволяет по-разному настраивать эти модули, создавать их отдельно и т.д.
Перед
Изначально структура проекта в упрощенном виде выглядит следующим образом:
/
src/
entity.ts # exports an entity
test/
entity.spec.ts # imports an entity
tsconfig.json
Сущность определяется в модуле src/entity.ts
, а затем используется в файле test/entity.spec.ts
.
Обратите внимание, что здесь находится только один файл tsconfig.json
, расположенный в корневой папке. В основном это говорит о том, что эта папка содержит один большой твердый проект TypeScript. Этот проект включает в себя пару файлов, организованных в папки; некоторые из этих файлов используются для тестирования других.
Эта структура, однако, создает проблему: процесс компиляции проекта (а именно, tsc
) также компилирует тестовые файлы, создавая таким образом файлы dist/test/entity.spec.{js|d.ts}
в выходных данных. Этого не должно быть, поэтому файл tsconfig.json
слегка изменен и включает в себя только те файлы/папки, которые предназначены для внешнего использования:
{
"compilerOptions": {
// compiler options
},
"include": [
"./src"
]
}
Это решает проблему, но в моем случае это также привело к тому, что все файлы в папке /test
время от времени игнорируются компилятором TypeScript в процессе разработки. Кроме того, этот эксклюзивный подход может не подходить для всех.
После
После использования функции структура проекта изменилась на следующую:
/
src/
entity.ts # exports an entity
tsconfig.json
test/
entity.spec.ts # imports an entity
tsconfig.json
tsconfig-base.json
Отпустите изменения:
- Переименование
/tsconfig.json
в /tsconfig-base.json
само по себе является довольно важной вещью: корневая папка больше не является проектом TypeScript, так как tsc
требует наличия файла tsconfig.json
.
- С другой стороны, добавление файлов
src/tsconfig.json
и test/tsconfig.json
превращает и src
, и test
в два отдельных проекта TypeScript, независимых друг от друга.
Содержимое файлов /{src|test}/tsconfig.json
схоже, так как никаких изменений в конфигурации не ожидалось, то есть "строгость", папка вывода, а также другие подобные параметры должны быть сохранены. Чтобы сделать их похожими, не вставляя при этом копий, все конфигурации помещаются в произвольный файл, доступный из обоих мест; в этом случае для этого был выбран tsconfig-base.json
в корневой папке:
// the contents of /tsconfig-base.json
{
"compilerOptions": {
// compiler options, common to both projects
}
}
Этот файл "наследуется", затем файлами /{src|test}/tsconfig.json
, с добавлением любых других опций, если это необходимо:
// the contents of /{src|test}/tsconfig.json
{
"extends": "../tsconfig-base.json",
"compilerOptions": {
// additional compiler options, specific to a project
}
}
Обратите внимание, как этот шаблон похож на определение abstract class
с неполной реализацией, а затем расширение его двумя отдельными "конкретными" классами.
Теперь папки /src
и /test
в основном содержат два отдельных проекта TypeScript с похожей конфигурацией. Последнее, что нужно сделать, это указать связь между ними. Поскольку test
зависит от src
, test
должен каким-то образом "знать" о src
. Это делается в два довольно очевидных шага:
разрешить src
"ссылаться" на извне, объявив его "составным":
// in /src/tsconfig.json
{
"extends": "../tsconfig-base.json",
"compilerOptions": {
// compiler options
"composite": true
}
}
ссылка src
из test
:
// in /test/tsconfig.json
{
"extends": "../tsconfig-base.json",
"references": [
{ "path": "../src" }
]
}
Массив "include"
в /tsconfig-base.json
теперь не нужен, поскольку исключение из кода выполняется путем "рисования новых границ".
Теперь для проекта test
требуются файлы *.d.ts
для проекта src
. Это означает, что перед запуском тестов src
должен быть собран отдельно. Это делается с помощью нового режима tsc
, запускаемого опцией --build
:
tsc --build src
Эта команда создает проект src
и помещает выходные данные в указанную выходную папку (в данном случае /dist
), не прерывая работу test
и не теряя ошибок компиляции.
Ответ 2
это для машинописных библиотек, которые вы разрабатываете, которые используются другим приложением типов. Например, если вы используете некоторую библиотеку- lodash
как lodash
но активно ее разрабатываете вместе со своим зависимым приложением, references
в "tsconfig.json" позволяют ссылаться на исходный код и автоматически перестраивать зависимое приложение, когда изменения источника использования (IE: tsc обнаруживает изменения исходного кода в утилите ts lib)
В моем случае я использую references
в сочетании с npm link
и git submodules
и он работает намного лучше, чем в ts 2.x
Ответ 3
**** ОБНОВЛЕНИЕ **** (3 августа 2018 года)
Дайте кредит, где должен быть кредит.
На приведенный ниже контент ссылались на " Announcing TypeScript 3.0 " Даниэля Розенвассера из Microsoft.
Эта проблема
Его довольно распространенный способ иметь несколько разных этапов сборки для библиотеки или приложения. Возможно, ваша кодовая база имеет src
и test
каталог. Возможно, у вас есть свой интерфейсный код в папке с client
с вашим внутренним кодом Node.js в папке с именем server
и каждый импортирует код из shared
папки. И, может быть, вы используете так называемый "monorepo" и имеете много проектов, которые зависят друг от друга нетривиальными способами.
Ссылки на проекты
Ссылки на проекты направлены на облегчение работы с этими сценариями.
Ссылки на проект позволяют проектам TypeScript зависеть от других проектов типа TypeScript, в частности, позволяя файлам tsconfig.json
ссылаться на другие файлы tsconfig.json
. Задание этих зависимостей упрощает разделение вашего кода на более мелкие проекты, поскольку он дает TypeScript (и инструменты вокруг него) способ понять структуру упорядочения и вывода данных. Это означает, что такие вещи, как быстрые сборки, работают постепенно и поддерживают прозрачную навигацию, редактирование и рефакторинг по проектам.
На что это похоже?
В качестве краткого примера, как tsconfig.json
с проектами, выглядит так:
// ./src/bar/tsconfig.json
{
"compilerOptions": {
// Needed for project references.
"composite": true,
"declaration": true,
// Other options...
"outDir": "../../lib/bar",
"strict": true, "module": "esnext", "moduleResolution": "node",
},
"references": [
{ "path": "../foo" }
]
}
Здесь есть два новых поля: composite
и references
.
references
просто указывают другие файлы tsconfig.json
(или папки, содержащие их сразу). Каждая ссылка в настоящее время представляет собой только объект с полем path
и позволяет TypeScript знать, что для создания текущего проекта требуется сначала создать проект, на который ссылается проект.
Возможно, столь же важным является composite
поле. В composite
поле предусмотрены определенные опции, позволяющие ссылаться на этот проект и строить его поэтапно для любого проекта, который зависит от него. Важное значение имеет способность к разумной и постепенной перестройке, поскольку скорость сборки является одной из причин, по которой вы можете разбить проект в первую очередь. Например, если проект front-end
зависит от shared
, и shared
зависит от core
, наш API, вокруг ссылок проекта может быть использован для обнаружения изменений в core
, но только перестроение shared
, если типы (т.е..d.ts файлы) произведенные core
, изменились. Это означает, что изменение core
не полностью заставляет нас восстанавливать мир. По этой причине установка composite
сил также устанавливает флаг declaration
.
Режим сборки для TypeScript
TypeScript 3.0 предоставит набор API для ссылок на проекты, чтобы другие инструменты могли обеспечить это быстрое постепенное поведение. tsc
теперь поставляется с новым --build
флагом.
tsc --build
(или его псевдоним, tsc -b
) выполняет набор проектов и строит их и их зависимости.
Управление структурой вывода
Одно тонкое, но невероятно полезное преимущество ссылок на проекты логически способно отображать источник входных данных на его выходы.
Если вы когда-либо пытались разделить код TypeScript между клиентом и сервером приложения, возможно, вы столкнулись с проблемами управления структурой вывода.
Например, если client/index.ts
и server/index.ts
ссылаются на shared/index.ts
для следующих проектов:
src
├── client
│ ├── index.ts
│ └── tsconfig.json
├── server
│ ├── index.ts
│ └── tsconfig.json
└── shared
└── index.ts
... затем пытается создать client
и server
, ну в итоге...
lib
├── client
│ ├── client
│ │ └── index.js
│ └── shared
│ └── index.js
└── server
├── server
│ └── index.js
└── shared
└── index.js
скорее, чем
lib
├── client
│ └── index.js
├── shared
│ └── index.js
└── server
└── index.js
Обратите внимание, что мы закончили с копией shared
как на client
и на server
. Мы без лишних затрат потратили время на shared
дважды и внесли нежелательный уровень вложенности в lib/client/client
и lib/server/server
.
В идеале, TypeScript понимает, что эти файлы не нужно создавать в одной и той же компиляции, а вместо этого переходить к файлам .d.ts
для информации о типе.
Создание tsconfig.json
для shared
использования и использования ссылок на проекты делает именно это. Он сигнализирует TypeScript, что
-
shared
должны быть построены независимо, а - при импорте из
../shared
, мы должны искать файлы .d.ts
в его выходном каталоге.
Это позволяет избежать двойного -b uild, а также позволяет избежать случайного поглощения всего содержимого shared
.