Как иметь абсолютные пути импорта в проекте библиотеки?
У меня есть библиотека с рабочим пространством, содержащим два проекта, один для самой библиотеки и один для тестового приложения.
├── projects
├── midi-app
└── midi-lib
В рабочем пространстве tsconfig.json
файл я настроил некоторые @app
а также @lib
пути:
"paths": {
"@app/*": ["projects/midi-app/src/app/*"],
"@lib/*": ["projects/midi-lib/src/lib/*"],
"midi-lib": [
"dist/midi-lib"
],
"midi-lib/*": [
"dist/midi-lib/*"
]
}
Существует projects/midi-lib/tsconfig.lib.json
файл, который распространяется на выше tsconfig.json
файл:
"extends": "../../tsconfig.json",
Существует public-api.ts
файл, который содержит:
export * from './lib/midi-lib.module';
Я могу использовать эту библиотеку с тестовым приложением просто отлично.
Но когда я пытаюсь использовать его в другом клиентском приложении, в другом рабочем пространстве, импортированном как модуль узла, я получаю много ошибок по неизвестным путям Can't resolve '@lib/...'
Как выразить пути к библиотекам, чтобы они отображались в клиентском приложении? Или как перевести пути к библиотекам при упаковке библиотеки?
Как побочный вопрос, я удивляюсь, почему удлинения не выполняются наоборот. Почему это не tsconfig.json
файл, который распространяется на projects/midi-lib/tsconfig.lib.json
файл?
Вот как я упаковываю, а затем использую библиотеку:
Чтобы упаковать библиотеку, добавьте следующие сценарии в массив сценариев родительского элемента. package.json
файл
"copy-license": "cp ./LICENSE.md ./dist/midi-lib",
"copy-readme": "cp ./README.md ./dist/midi-lib",
"copy-files": "npm run copy-license && npm run copy-readme",
"build-lib": "ng build midi-lib",
"npm-pack": "cd dist/midi-lib && npm pack",
"package": "npm run build-lib && npm run copy-files && npm run npm-pack",
и запустите команду: npm run package
затем установите зависимость
npm install ../midi-lib/dist/midi-lib/midi-lib-0.0.1.tgz
и импортировать модуль в модуль приложения. app.module.ts
файл имеет:
import { MidiLibModule } from 'midi-lib';
@NgModule({
imports: [
MidiLibModule
наконец, вставьте компонент в шаблон
<midi-midi-lib></midi-midi-lib>
Когда библиотека установлена в клиентском приложении, она имеет много .d.ts
файлы в node_modules/midi-lib
справочники:
├── bundles
├── esm2015
│ └── lib
│ ├── device
│ ├── keyboard
│ ├── model
│ │ ├── measure
│ │ └── note
│ │ ├── duration
│ │ └── pitch
│ ├── service
│ ├── sheet
│ ├── soundtrack
│ ├── store
│ ├── synth
│ └── upload
├── esm5
│ └── lib
│ ├── device
│ ├── keyboard
│ ├── model
│ │ ├── measure
│ │ └── note
│ │ ├── duration
│ │ └── pitch
│ ├── service
│ ├── sheet
│ ├── soundtrack
│ ├── store
│ ├── synth
│ └── upload
├── fesm2015
├── fesm5
└── lib
├── device
├── keyboard
├── model
│ ├── measure
│ └── note
│ ├── duration
│ └── pitch
├── service
├── sheet
├── soundtrack
├── store
├── synth
└── upload
Как этот lib/service/melody.service.d.ts
файл
import { SoundtrackStore } from '@lib/store/soundtrack-store';
import { ParseService } from '@lib/service/parse.service';
import { CommonService } from './common.service';
export declare class MelodyService {
private soundtrackStore;
private parseService;
private commonService;
constructor(soundtrackStore: SoundtrackStore, parseService: ParseService, commonService: CommonService);
addSomeMelodies(): void;
private addSoundtrack;
private generateNotes;
}
Как видно, он содержит ссылки на @lib
отображение пути, которое не известно в клиентском приложении.
Я также пытался использовать baseUrl
свойство как обходной путь, но это тоже не помогло, так как при установке библиотеки это baseUrl
значение не было указано.
Почему пакет библиотеки с помощью команды npm run package
не разрешая paths
сопоставления?
2 ответа
paths
картирование вы устанавливаете в своем tsconfig.json
это чисто отображение времени компиляции. Это не влияет на код, сгенерированный компилятором TypeScript. Вот почему у вас сбой во время выполнения. Это то, что было сообщено в проект TypeScript, предполагая, что tsc
должен автоматически переводить пути модулей в переданном коде, чтобы соответствовать отображению, установленному paths
, Разработчики TS ответили tsc
работает так, как задумано, и решение состоит в том, чтобы настроить загрузчик модулей, который выполняет во время выполнения отображение, аналогичное установленному paths
,
Вот что, я думаю, вы должны сделать, основываясь на том, как вы описали свой случай.
Я предполагаю что midi-app
это тестовое приложение, которое не предназначено для распространения. Вы должны быть в состоянии продолжать использовать paths
картирование у вас без проблем. (Вы не упомянули ни одной проблемы с запуском этого приложения. Похоже, ваш инструментарий уже позаботился о проблеме времени выполнения.)
За midi-lib
Я бы перестал полагаться на сопоставления, установленные paths
и просто используйте относительные пути. Это библиотека, предназначенная для использования другими. Из-за этого любая конфигурация, которая исправит сопоставление имен модулей во время выполнения (или во время объединения), должна обрабатываться потребителями вашей библиотеки. Потребители, использующие Webpack, должны будут добавить конфигурацию в свою конфигурацию Webpack, чтобы обеспечить правильное сопоставление. Потребители, использующие Rollup, должны будут сделать то же самое с Rollup. Потребители, использующие SystemJS, должны будут сделать то же самое с SystemJS и т. Д.
Более того, требуемая конфигурация может быть сложной в зависимости от контекста, в котором используется ваша библиотека. Пока ваша библиотека - единственная, которой нужно сопоставить @lib
по некоторому пути отображение, которое должно быть добавлено в Webpack (или SystemJS и т. д.), может быть глобальным. Модуль-модуль или модуль-загрузчик всегда заменят @lib
с вашим путем, что хорошо, потому что ваш пакет является единственным, который нуждается @lib
заменены. Однако предположим, что другой автор библиотеки делает именно то, что вы сделали, и потребитель вашей библиотеки также использует эту другую библиотеку. Теперь у вас есть ситуация, когда @lib
должен быть сопоставлен с одним путем в некоторых случаях, и должен быть сопоставлен с другим путем в других случаях. Это можно настроить, но это требует более сложной конфигурации.
Я сосредоточился на проблеме разрешения модулей во время связывания или при загрузке их во время выполнения, но есть еще одна проблема. Потребители также должны настроить свои tsc
сборник со специальной конфигурацией, потому что .d.ts
файлы
Если вы просто используете относительные пути в своем коде, тогда пользователям вашей библиотеки не придется беспокоиться о добавлении специальных конфигураций для удовлетворения особых потребностей вашей библиотеки.
Есть специальный случай, который может соответствовать вашему случаю. Если ваша библиотека будет опубликована как midi-lib
тогда вы можете изменить свой paths
карта так, чтобы вместо @lib/*
у вас есть карта для midi-lib/*
:
"midi-lib/*": ["projects/midi-lib/src/*"],
(Обратите внимание, что @
Символ не имеет особого значения в отношении TypeScript. Также обратите внимание, если ваш пакет предназначен для установки с областью, например @midi-project/midi-lib
тогда вам нужен объем в tsconfig.json
отображение тоже: "@midi-project/midi-lib/*": ...
)
По сути, цель здесь - установить отображение, которое позволит вам импортировать модули в ваш проект точно так же, как потребитель вашего проекта импортировал бы из него отдельные модули. Если потребитель вашего модуля будет импортировать ParseService
с участием import { ParseService } from "midi-lib/lib/service/parse.service"
то в вашем собственном коде вы бы использовали тот же import
когда вы хотите использовать этот модуль. (Обратите внимание, что не имеет значения, говорите ли вы потребителям импортировать этот модуль напрямую. Если бы потребители импортировали модуль напрямую, то какой путь они использовали бы?) Таким образом, один и тот же путь работает во время компиляции и во время выполнения (или во время компоновки).). Во время компиляции, tsc
преобразует путь. Во время выполнения или связывания алгоритм преобразования модуля Node (или инструмент, который может следовать тому же алгоритму, как Webpack или Rollup) преобразует путь.
То, сколько текста вы сэкономите с этим, сильно зависит от выбранных вами имен и того, как вы структурировали свою библиотеку.
Теоретически, вы можете сделать шаг после запуска ng build
это будет идти по файлам, созданным ng build
и заменить @lib
в именах модулей с фактическим путем, на который он должен указывать. Проблемы с этим:
Это не просто запуск отдельного инструмента или переключение флага в параметре конфигурации. Может быть, инструмент, как
rollup
может преобразовать файлы JS, но теперь вам нужно узнать, как это работает, и написать конфигурацию для него.AFAIK нет легкодоступного инструмента, который преобразует
.d.ts
файлы, как вам нужно. Скорее всего, вам придется написать свой собственный инструмент.Вам также необходимо будет исправить метаданные компиляции AOT, сгенерированные компилятором Angular AOT, поскольку он также содержит ссылки на модули, и эти ссылки используются потребителями вашей библиотеки. AFAIK, нет такого инструмента, который существует. Так что и здесь вам придется свернуть свой собственный.
Процесс сборки может прерваться, если новая версия Angular изменит формат метаданных компиляции AOT или добавит файл метаданных другого типа, для которого требуется исправление. Я знаю это по своему опыту: у меня есть несколько пакетов, которые являются экспериментальными приложениями Angular. По историческим причинам они полностью обходят использование Angular CLI для сборки. Каждое обновление Angular, начиная с версии 4 и выше, что-то нарушало в процессе сборки этих приложений. Часто это связано с обработкой метаданных AOT-компиляции.
Как уже говорили другие, машинопись не меняет ваш @app
а также @lib
импорт. Я столкнулся с той же проблемой, пытаясь использовать абсолютные пути в пакете библиотеки. Что вам нужно, это подготовить вашу библиотеку к публикации с помощью накопительного пакета или чего-то подобного.
В Rollup есть различные плагины, и я не буду описывать полную настройку, но вам нужен плагин, который перезапишет ваш импорт. Этот плагин выглядит так, как будто он это делает: https://github.com/bitshiftza/rollup-plugin-ts-paths
Для остальной части конфигурации накопительного пакета вам, вероятно, понадобятся rollup-plugin-node- resol и https://github.com/rollup/rollup-plugin-commonjs, а также плагин для обработки машинописи ( https://github.com/rollup/rollup-plugin-typescript), или вы можете пойти по более новому маршруту использования Babel. Найдите некоторые руководства, потому что есть популярные библиотеки, написанные на машинописном тексте, которые используют накопительный пакет для подготовки своего кода к упаковке (например, React).
Удачного кодирования.
Думаю нашел разрешение.
Удалить src
папку, вас ждет новый мир!