Как использовать код между TypeScript проектами?

Скажем, у меня есть два проекта со следующей структурой файла

/my-projects/

  /project-a/
    lib.ts
    app.ts
    tsconfig.json

  /project-b/
    app.ts         // import '../project-a/lib.ts'
    tsconfig.json

Я хочу потреблять lib.ts, расположенный в project-a также из project-b. Как это сделать?

  • Отпустите его как модуль NPM - абсолютно не хотите, чтобы, это излишний для такого простого использования. я просто хотите поделиться одним файлом между двумя проектами.

  • Использовать import '../project-a/lib.ts' - не работает, TypeScript жалуется

'lib.ts' is not under 'rootDir'. 'rootDir' is expected to contain all source files.

  • Поместите tsconfig.json на один уровень вверх, чтобы он охватывал как project-a, так и project-b - не может этого сделать, конфигурация TypeScript немного отличается для этих проектов. Также это не очень удобно, не хочу этого делать.

Любые другие способы?

Ответ 1

Начиная с Typescript 3.0 это можно сделать с помощью ссылок проекта.

Документы для машинописи: https://www.typescriptlang.org/docs/handbook/project-references.html

Я полагаю, вам придется переместить lib.ts в небольшой проект ts, который называется что-то вроде 'lib'

Проект lib должен иметь tsconfig, содержащий:

// lib/tsconfig.json
    {
          "compilerOptions": {
            /* Truncated compiler options to list only relevant options */
            "declaration": true, 
            "declarationMap": true,
            "rootDir": ".",   
            "composite": true,     
          },
          "references": []  // * Any project that is referenced must itself have a 'references' array (which may be empty).
        }

Затем и в project-a, и в project-b добавьте ссылку на этот проект lib в свой tsconfig

// project-a/ts-config.json
// project-b/ts-config.json
{
        "compilerOptions": {
            "target": "es5", 
            "module": "es2015",
            "moduleResolution": "node"
            // ...
        },
        "references": [
            { "path": "../lib" }
        ]
    }

В проекте lib. Создайте файл index.ts, который должен экспортировать весь ваш код, которым вы хотите поделиться с другими проектами.

// lib/index.ts    
export * from 'lib.ts';

Теперь, скажем, lib/lib.ts выглядит следующим образом:

// lib/lib.ts
export const log = (message: string) => console.log(message);

Теперь вы можете импортировать функцию log из lib/lib.ts как в project-a, так и в project-b.

// project-a/app.ts 
// project-b/app.ts
import { log } from '../lib';
log("This is a message");

Прежде чем ваш intelissense заработает, вам нужно создать оба проекта project-a и project-b, используя:

tsc -b 

который сначала создаст ссылки на ваш проект (в данном случае lib), а затем создаст текущий проект (project-a или project-b).

Компилятор машинописного текста не будет смотреть на фактические файлы машинописного текста из lib. Вместо этого он будет использовать только файлы объявлений машинописного текста (*.d.ts), сгенерированные при сборке проекта lib.

Вот почему ваш файл lib/tsconfig.json должен содержать:

"declaration": true,

Однако, если вы перейдете к определению функции журнала в project-a/app.ts с помощью клавиши F12 в коде Visual Studio, вам будет показан правильный файл машинописного текста. По крайней мере, если вы правильно настроили свой lib/tsconfig.json с помощью:

"declarationMap": true,

Я создал небольшое репозиторий github, демонстрирующий этот пример ссылок на проекты с машинописью:

https://github.com/thdk/TS3-projects-references-example

Ответ 2

Это может быть достигнуто с помощью свойства 'paths' CompilerOptions в tsconfig.json

{
  "compilerOptions": {
    "paths": {
      "@otherProject/*": [
        "../otherProject/src/*"
      ]
    }
  },
}

Ниже приведен скриншот структуры папок.

enter image description here

Ниже приведен контент tsconfig.json, который ссылается на другой ts-проект

{
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./tsc-out",
    "sourceMap": false,
    "declaration": false,
    "moduleResolution": "node",
    "module": "es6",
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2017",
      "dom"
    ],
    "paths": {
      "@src/*": [ "src/*" ],
      "@qc/*": [
        "../Pti.Web/ClientApp/src/app/*"
      ]
    }
  },
  "exclude": [
    "node_modules",
    "dist",
    "tsc-out"
  ]
}

Ниже приведено утверждение импорта для ссылки на экспорт из другого проекта.

import { IntegrationMessageState } from '@qc/shared/states/integration-message.state';

Ответ 3

Я думаю, что @qqilihq находится на правильном пути с их ответом - Хотя есть отмеченные потенциальные проблемы с ручным обслуживанием содержимого node_modules.

Мне посчастливилось справиться с этим с помощью lerna (хотя есть ряд других подобных инструментов, например, рабочие области пряжи кажутся чем-то похожими, хотя я сам ими не пользовался).

Я просто скажу заранее, что это может быть немного тяжелым для того, о чем вы говорите, но это дает вашему проекту большую гибкость, чтобы расти в будущем.

С этим шаблоном ваш код будет выглядеть примерно так:

/my-projects/
    /common-code/
        lib.ts
        tsconfig.json
        package.json
    /project-a/
        app.ts (Can import common-code)
        tsconfig.json
        package.json (with a dependency on common-code)
    /project-b/
        app.ts (Can import common-code)
        tsconfig.json
        package.json (with a dependency on common-code)

Общая теория здесь заключается в том, что инструмент создает символические ссылки между вашими внутренними библиотеками и каталогами node_modules их зависимых пакетов.

Основные подводные камни, с которыми я столкнулся при этом:

  • common-code должно быть установлено свойство main и types в файле package.json
  • common-code должен быть скомпилирован, прежде чем любая из его зависимостей сможет положиться на него
  • common-code должен быть declaration установлена верно в tsconfig.json

Мой общий опыт с этим был довольно положительным, поскольку, как только вы поняли основную идею, в ней очень мало "магии", это просто набор стандартных узловых пакетов, которые, как правило, совместно используют каталог.

Ответ 4

Отвечая на мой собственный вопрос. Существует несколько способов, но нет простого способа делиться проектами TypeScript.

Ответ 5

В аналогичном сценарии, где я также хотел избежать накладных расходов на выполнение выпуска NPM, я пошел на следующую структуру (после многих проб и ошибок и неудачных попыток):

/my-projects/

  /node_modules/
    /my-lib/
      lib.ts
      tsconfig.json
      package.json

  /project-a/
    app.ts
    tsconfig.json

  /project-b/
    app.ts         
    tsconfig.json

Основная идея состоит в том, чтобы переместить общий материал в каталог node_modules над отдельными проектами (это использует механизм загрузки NPM, который начнет искать зависимости в текущем каталоге, а затем двигаться вверх).

Итак, project-a и project-b теперь могут получить доступ к lib просто через import { Whatever } from 'my-lib'.

Примечания:

  • В моем случае my-lib фактически используется только для общих типизированных (т.е. .d.ts файлов в подкаталоге lib). Это означает, что мне явно не нужно строить my-lib, а мой my-lib/package.json выглядит следующим образом:

    {
      "name": "my-types",
      "version": "0.0.0",
      "private": true,
      "types": "lib/index"
    }
    
  • В случае, если my-lib содержит исполняемый код, вам, очевидно, нужно будет построить my-lib, чтобы файлы .js были сгенерированы и добавили свойство "main" в package.json, которое предоставляет основной .js.

  • Самое главное: Несмотря на свое название, /my-projects/node_modules только содержит пользовательский код, не зависимые установленные (они фактически находятся в отдельные проекты project-a/node_modules и project-b/node_modules). Это означает, что существует явный параметр игнорирования git, который un -значает каталог /node_modules.

Является ли это чистым решением? Наверное, нет. Решила ли моя проблема? Да. Я рад услышать о предложениях по улучшению? Абсолютно!