איך לשתף קוד בין פרויקטים של 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 אפשר לעשות זאת עם הפניות לפרויקטים.
מסמכי TypeScript: https://www.typescriptlang.org/docs/handbook/project-references.html
אני מאמין שתצטרך להעביר את lib.ts לפרויקט TypeScript קטן שנקרא משהו כמו '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, הוסף את ההפניה לפרויקט הספריה הזו בתוך tsconfig שלך
// 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,
}
]
}
בפרויקט הספרייה. צור קובץ 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");
לפני שהאינטליסנס שלך יעבוד, עכשיו אתה צריך לבנות גם את project-a וגם את project-b באמצעות:
tsc -b
שזה ייבנה תחילה את ההפניות של הפרויקט שלך (lib במקרה זה) ואז יבנה את הפרויקט הנוכחי (project-a או project-b).
מהמחשב הקומפיילר של TypeScript לא יסתכל על קבצי ה-TypeScript בפועל מהספרייה. במקום זאת הוא ישתמש רק בקבצי ההצהרה של TypeScript (*.d.ts) שנוצרו בעת בניית פרויקט הספרייה.
זו הסיבה שקובץ lib/tsconfig.json שלך חייב להכיל:
"declaration": true,
עם זאת, אם תנווט להגדרת הפונקציה log בקובץ project-a/app.ts באמצעות מקש F12 בקוד Visual Studio, יופיע בפניך קובץ TypeScript הנכון. לפחות, אם הגדרת נכון את lib/tsconfig.json שלך עם:
"declarationMap": true,
יצרתי מאגר GitHub קטן המציג את הדוגמה הזו של הפניות פרויקט עם TypeScript:
https://github.com/thdk/TS3-projects-references-example
תשובה #2
ניתן להשיג זאת באמצעות השימוש בתכונת 'paths' של 'CompilerOptions' בקובץ tsconfig.json
{
"compilerOptions": {
"paths": {
"@otherProject/*": [
"../otherProject/src/*"
]
}
},
}
להלן צילום מסך של מבנה התיקיות.
להלן תוכן הקובץ tsconfig.json שמפנה לפרויקט TypeScript אחר
{
"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 (למרות שיש מספר כלים דומים אחרים שם, לדוגמה 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וגם את המאפייןtypesמוגדר בקובץpackage.jsonשלוcommon-codeצריך להיות מקומפל לפני שכל אחת מהתלויות שלו תוכל להסתמך עליוcommon-codeצריך שיהיה לוdeclarationמוגדר ל-true בקובץtsconfig.jsonשלו
החוויה הכללית שלי עם זה הייתה די חיובית, שכן ברגע שמבינים את הרעיון הבסיסי, יש בו מעט מאוד 'קסם', זו פשוט קבוצת חבילות נוד סטנדרטיות שמקריות לשתף ספרייה.
