Bagaimana cara membagikan kode antara proyek TypeScript?


Misalkan saya memiliki dua proyek dengan struktur file berikut

/my-projects/

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

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

Saya ingin menggunakan lib.ts yang terletak di project-a juga dari project-b. Bagaimana cara melakukannya?

  • Rilis itu sebagai modul NPM - sama sekali tidak menginginkan itu, ini terlalu berlebihan untuk kasus penggunaan yang begitu sederhana. Saya hanya ingin membagikan satu file antara dua proyek.

  • Gunakan import '../project-a/lib.ts' - tidak berhasil, TypeScript mengeluh

'lib.ts' is not under 'rootDir'. 'rootDir' is expected to contain all source files.
  • Taruh tsconfig.json satu level lebih atas supaya mencakup project-a dan project-b - tidak bisa melakukan itu, konfigurasi TypeScript sedikit berbeda untuk proyek-proyek tersebut. Selain itu, itu tidak terlalu nyaman, tidak ingin melakukan itu.

Ada cara lain?

Jawaban #1

Sejak Typescript 3.0 hal ini dapat dilakukan dengan Referensi Proyek.

Dokumentasi Typescript: https://www.typescriptlang.org/docs/handbook/project-references.html

Saya percaya Anda harus memindahkan lib.ts ke dalam proyek ts kecil yang disebut sesuatu seperti 'lib'

Proyek lib seharusnya memiliki tsconfig yang berisi:

// 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).
        }

Kemudian di kedua project-a dan project-b tambahkan referensi ke proyek lib ini ke dalam tsconfig Anda

// project-a/ts-config.json
// project-b/ts-config.json
{
        "compilerOptions": {
            "target": "es5", 
            "module": "es2015",
            "moduleResolution": "node"
            // ...
        },
        "references": [
            { 
                "path": "../lib",
                // add 'prepend' if you want to include the referenced project in your output file
                "prepend": true, 
            }
        ]
    }

Dalam proyek lib. Buat file index.ts yang harus mengekspor semua kode Anda yang ingin dibagikan dengan proyek lain.

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

Sekarang, misalkan lib/lib.ts terlihat seperti ini:

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

Anda sekarang dapat mengimpor fungsi log dari lib/lib.ts di proyek-a dan proyek-b

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

Sebelum intelissense Anda bekerja, sekarang Anda perlu membangun kedua project-a dan project-b Anda menggunakan:

tsc -b 

Yang pertama akan membangun referensi proyek Anda (lib dalam hal ini) dan kemudian membangun proyek saat ini (project-a atau project-b).

Kompiler TypeScript tidak akan melihat file TypeScript sebenarnya dari lib. Sebagai gantinya, ia hanya akan menggunakan file deklarasi TypeScript (*.d.ts) yang dihasilkan saat membangun proyek lib.

Itulah mengapa file lib/tsconfig.json Anda harus berisi:

"declaration": true,

Namun, jika Anda menavigasi ke definisi fungsi log di project-a/app.ts menggunakan tombol F12 di Visual Studio Code, Anda akan ditunjukkan file typescript yang benar. Setidaknya, jika Anda telah mengatur lib/tsconfig.json Anda dengan benar dengan:

"declarationMap": true,

Saya telah membuat repositori Github kecil yang menunjukkan contoh referensi proyek ini dengan TypeScript:

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

Jawaban #2

Ini dapat dicapai dengan menggunakan properti 'paths' dari 'CompilerOptions' di tsconfig.json

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

Di bawah ini adalah tangkapan layar dari struktur folder.

Di bawah ini adalah konten tsconfig.json yang merujuk ke proyek ts lainnya

{
  "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"
  ]
}

Di bawah ini adalah pernyataan impor untuk merujuk ekspor dari proyek lain.

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

Jawaban #3

Saya pikir bahwa @qqilihq berada di jalur yang benar dengan tanggapan mereka - Meskipun ada potensi masalah yang dicatat dengan secara manual mempertahankan isi dari direktori node_modules.

Saya cukup beruntung bisa mengelola ini dengan menggunakan lerna (meskipun ada sejumlah alat serupa lainnya di luar sana, misalnya yarn workspaces tampaknya agak mirip, meskipun saya sendiri belum menggunakannya).

Saya akan mengatakan di depan bahwa ini mungkin agak berat untuk apa yang sedang Anda bicarakan, tetapi ini memang memberi proyek Anda banyak fleksibilitas untuk berkembang di masa depan.

Dengan pola ini, kode Anda akan terlihat seperti berikut:

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

Teori umum di sini adalah bahwa alat ini membuat tautan simbolik antara pustaka internal Anda dan direktori node_modules dari paket yang bergantung padanya.

Kendala utama yang saya temui saat melakukan ini adalah

  • common-code harus memiliki properti main dan types yang diatur di file package.json-nya
  • common-code harus dikompilasi sebelum dependensinya dapat mengandalkannya
  • common-code harus memiliki declaration disetel ke true di tsconfig.json

Pengalaman umum saya dengan ini cukup positif, karena setelah Anda memahami gagasan dasarnya, hampir tidak ada 'sihir' di dalamnya, itu hanyalah seperangkat paket node standar yang kebetulan berbagi satu direktori.

Artikel terkait