Как иметь абсолютные пути импорта в проекте библиотеки?

У меня есть библиотека с рабочим пространством, содержащим два проекта, один для самой библиотеки и один для тестового приложения.

├── 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 в именах модулей с фактическим путем, на который он должен указывать. Проблемы с этим:

  1. Это не просто запуск отдельного инструмента или переключение флага в параметре конфигурации. Может быть, инструмент, как rollup может преобразовать файлы JS, но теперь вам нужно узнать, как это работает, и написать конфигурацию для него.

  2. AFAIK нет легкодоступного инструмента, который преобразует .d.ts файлы, как вам нужно. Скорее всего, вам придется написать свой собственный инструмент.

  3. Вам также необходимо будет исправить метаданные компиляции AOT, сгенерированные компилятором Angular AOT, поскольку он также содержит ссылки на модули, и эти ссылки используются потребителями вашей библиотеки. AFAIK, нет такого инструмента, который существует. Так что и здесь вам придется свернуть свой собственный.

  4. Процесс сборки может прерваться, если новая версия 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 папку, вас ждет новый мир!

Другие вопросы по тегам