如何在TypeScript项目之间共享代码?

时间:2017-12-09 14:01:34

标签: 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的{​​{1}}。怎么做?

  • 将其作为 NPM模块发布 - 绝对不想,这对于这样一个简单的用例来说是一种过度杀伤力。我只是 想要在两个项目之间共享一个文件。

  • 使用project-b - 不起作用,TypeScript抱怨

import '../project-a/lib.ts'

  • 'lib.ts' is not under 'rootDir'. 'rootDir' is expected to contain all source files.提升一级,以便涵盖tsconfig.jsonproject-a - 不能这样做,TypeScript配置对于这些项目略有不同。它也不方便,不想这样做。

还有其他方法吗?

9 个答案:

答案 0 :(得分:6)

这可以通过使用tsconfig.json中'CompilerOptions'的'paths'属性来实现

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

下面是文件夹结构的屏幕截图。

enter image description here

下面是tsconfig.json的内容,该内容引用了其他ts-project

{
  "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语句,用于引用其他项目的出口。

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

答案 1 :(得分:4)

从Typescript 3.0开始,这可以通过“项目参考”来完成。

打字稿文档:https://www.typescriptlang.org/docs/handbook/project-references.html

我相信您将必须将lib.ts移入一个名为“ lib”之类的ts小项目中

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);

您现在可以从lib / lib.ts中的project-a和project-b中导入日志功能

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

在您的智能功能开始工作之前,您现在需要使用以下命令来构建project-a和project-b:

tsc -b 

首先将构建您的项目引用(在这种情况下为lib),然后再构建当前项目(project-a或project-b)。

打字稿编译器不会查看来自lib的实际打字稿文件。相反,它将仅使用在构建lib项目时生成的打字稿声明文件(* .d.ts)。

这就是为什么您的lib / tsconfig.json文件必须包含:

"declaration": true,

但是,如果使用Visual Studio代码中的F12键导航到project-a / app.ts中的日志功能的定义,则会显示正确的打字稿文件。 至少,如果您使用以下命令正确设置了lib / tsconfig.json

"declarationMap": true,

我创建了一个小的github存储库,演示了带有打字稿的项目引用示例:

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

答案 2 :(得分:0)

我认为@qqilihq的回复正确无误-尽管手动维护node_modules目录的内容存在一些潜在的问题。

我很幸运使用lerna来管理此问题(尽管还有很多其他类似的工具,例如yarn workspaces似乎有点相似,尽管我没有使用过他们自己)。

我只是在前面说过,这可能对您正在谈论的内容有些沉重,但这确实为您的项目提供了很大的灵活性,可以在将来进行扩展。

使用这种模式,您的代码最终看起来像:

/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文件中同时设置typespackage.json属性
  • common-code必须先进行编译,然后它的任何依赖项才能依赖它
  • common-code必须在其declaration中将tsconfig.json设置为true

我对此的一般经验是非常积极的,因为一旦您了解了基本概念,其中就几乎没有“魔术”了,它只是一组共享目录的标准节点程序包。

答案 3 :(得分:0)

回答我自己的问题。有一些方法,但是没有简便的方法来共享TypeScript项目。

答案 4 :(得分:0)

我在后端和前端文件夹之间使用如下结构进行共享:

enter image description here

tsconfig.base.json:

{
    "compilerOptions": {
        "target": "es2019",
        "baseUrl": "../src",
        "moduleResolution": "node",
        "alwaysStrict": true,
        "noImplicitAny": true,
        "noUnusedLocals": true,
        "noImplicitReturns": true,
        "noImplicitThis": true,
        "noFallthroughCasesInSwitch": true,
        "allowSyntheticDefaultImports": true,
        "esModuleInterop": true,
        "resolveJsonModule": true,
        "removeComments": true,
        "strictNullChecks": true,
        "sourceMap": true
    }
}

后端tsconfig:

    {
      "compilerOptions": {
        "module": "commonjs",
        "outDir": "../../build/backend"
      },
      "extends": "../../configs/tsconfig.base.json",
      "references": [
        {
          "path": "../shared"
        }
      ],
      "paths": {
        "shared": [
          "shared/index"
        ]
      },
      "lib": [
        "es2019"
      ],
    }

前端tsconfig:

 {
          "compilerOptions": {
            "outDir": "../../build/frontend",
            "jsx": "react"
          },
          "extends": "../../configs/tsconfig.base.json",
          "references": [
            {
              "path": "../shared"
            }
          ],
          "paths": {
            "shared": [
              "shared/index"
            ]
          },
          "lib": [
            "es2019",
            "dom"
          ]
        }

共享的tsconfig:

        {
          "compilerOptions": {
            "composite": true,
            "declaration": true,
            "outDir": "../../build/shared",
          },
          "extends": "../../configs/tsconfig.base.json"
        }

运行该脚本的npm脚本:

 "server-tsc": "cd src/backend && tsc -b -w"
 "client-tsc": "cd src/frontend && tsc -b -w"

答案 5 :(得分:0)

似乎我们这里有一些选择:

(1)将两个项目都放在一个单库中,并使用TS项目引用使用@ThdK给出的答案

如果您不希望使用单色存储库,那就不好了

(2)使用Lerna-通过@metric_caution查看答案

如果您不愿意学习Lerna或不想将共享文件发布到npm,那就不好了

(3)创建一个共享的npm包

如果您不想将共享文件发布到npm,那就不好

(4)将共享文件夹放在项目A的“共享”目录中,并编写脚本以将共享文件夹中的文件从项目A复制到在git push上执行的项目B的共享文件夹,或者使用脚本来同步两个文件夹。

在需要复制/同步时,可以在此处手动执行脚本。复制/同步也可以在使用husky进行git推送之前完成,并且共享文件会在脚本中自动添加到git中。

由于我不希望有单色仓库,所以我也不想为了这样可悲的目的发布npm软件包,所以我自己选择了选项4。

答案 6 :(得分:-1)

在类似的场景中,我还想避免必须执行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-aproject-b现在只需通过import { Whatever } from 'my-lib'即可访问lib。

备注:

  1. 就我而言,my-lib实际上仅适用于共享打字(即.d.ts子目录中的lib个文件。这意味着,我没有明确需要构建my-lib,我的my-lib/package.json看起来如下:

    {
      "name": "my-types",
      "version": "0.0.0",
      "private": true,
      "types": "lib/index"
    }
    
  2. 如果my-lib包含可运行代码,您显然需要构建my-lib,以便生成.js个文件,并添加"main"属性到显示主package.json文件的.js

  3. 最重要的是:尽管名称如此,/my-projects/node_modules 包含自定义代码,但没有已安装的依赖项(它们是实际上在单个项目中project-a/node_modulesproject-b/node_modules)。这意味着,有一个明确的git ignore设置, un - 使/node_modules目录不会被提交。

  4. 这是一个干净的解决方案吗?可能不是没有。它解决了我的问题吗?是。我很高兴听到改进建议吗?绝对!

答案 7 :(得分:-1)

由于我是唯一从事 2 个需要共享代码文件夹的项目的开发人员,因此我在公共代码共享文件夹之间设置了 2 路 real time sync

project A
 - shared/ -> 2-way sync with project B
 - abc/

project B
 - shared/ -> 2-way sync with project A
 - xyz/

这是一次性快速设置,但具有以下优点:

  • 没有配置和管理单存储库/多个 tsconfig 的麻烦
  • 无需构建步骤即可获取最新代码,立即生效
  • 使用云构建工具,因为共享代码位于存储库内,而不是 symlink
  • 更容易在本地调试,因为所有文件都在项目中
  • 我可以使用 commit hooks/husky 进一步检查共享文件夹并抛出警告等。

如果我想与其他团队成员合作,我可以提到使用这个同步工具作为项目设置的一部分。

答案 8 :(得分:-3)

我切换到deno。 TypeScript 项目中的代码共享终于很容易了。