Mendengarkan @nycdotnet membuat saya bersemangat untuk mengatasi yang satu ini. Terima kasih, Steve. (btw, Anda dapat melihat wawancara bagusnya di sini: http://www.dotnetrocks.com/default.aspx?showNum=1149)
Usulan di sini pertama kali dimulai pada zaman prasejarah (bahkan sebelum #11), ketika dinosaurus berjalan di bumi yang hangus. Meskipun tidak ada dalam proposal ini yang baru, saya yakin sudah saatnya kita menangani masalah ini. Usulan Steve sendiri adalah #3394.
Saat ini, di TypeScript, agak mudah untuk memulai dan memulai, dan kami membuatnya lebih mudah setiap hari (dengan bantuan hal-hal seperti #2338 dan pekerjaan di System.js). Ini luar biasa. Tetapi ada sedikit rintangan seiring dengan bertambahnya ukuran proyek. Saat ini kami memiliki model mental yang berjalan seperti ini:
Untuk proyek berukuran kecil, tsconfig.json memberi Anda cara yang mudah disiapkan untuk memulai dengan editor mana pun secara lintas platform. Untuk proyek skala besar, kemungkinan besar Anda akan beralih ke sistem build karena beragam persyaratan proyek skala besar, dan hasil akhirnya akan menjadi sesuatu yang sesuai untuk skenario Anda tetapi sulit untuk digunakan karena terlalu sulit untuk digunakan. berbagai sistem dan opsi build.
Steve, dalam wawancaranya, menunjukkan bahwa ini bukanlah model dunia yang tepat, dan saya cenderung setuju dengannya. Sebaliknya, ada tiga ukuran proyek:
Saat Anda menskalakan ukuran proyek, Steve berpendapat, Anda harus mampu menskalakan melalui langkah menengah, atau dukungan alat akan jatuh terlalu cepat.
Untuk mengatasi ini, saya mengusulkan kami mendukung proyek "berukuran sedang". Proyek-proyek ini memiliki langkah-langkah pembuatan standar yang dapat dijelaskan di tsconfig.json hari ini, dengan pengecualian bahwa proyek tersebut dibangun dari beberapa komponen. Hipotesis di sini adalah bahwa ada cukup banyak proyek pada tingkat ini yang dapat dilayani dengan baik oleh dukungan ini.
Berikan pengalaman yang mudah digunakan bagi pengembang yang membuat proyek "berukuran sedang" untuk kompilasi baris perintah dan saat bekerja dengan proyek ini dalam IDE.
Proposal ini _tidak_ menyertakan kompilasi opsional, atau langkah apa pun di luar apa yang ditangani oleh kompiler saat ini. Proposal ini juga tidak mencakup bundling atau pengemasan, yang akan ditangani dalam proposal tersendiri. Singkatnya, seperti namanya, proposal ini hanya mencakup proyek-proyek 'menengah' dan bukan kebutuhan skala besar.
Untuk mendukung proyek berukuran sedang, kami fokus pada kasus penggunaan satu tsconfig.json yang mereferensikan yang lain.
Contoh tsconfig.json hari ini:
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"sourceMap": true
},
"files": [
"core.ts",
"sys.ts"
]
}
Bagian 'dependensi' tsconfig.json yang diusulkan:
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"sourceMap": true
},
"dependencies": [
"../common",
"../util"
],
"files": [
"core.ts",
"sys.ts"
]
}
Ketergantungan menunjuk ke salah satu dari:
Dependensi bersifat hierarkis. Untuk mengedit proyek lengkap, Anda perlu membuka direktori yang benar yang berisi root tsconfig.json. Ini menyiratkan bahwa dependensi tidak dapat bersifat siklik. Meskipun mungkin untuk menangani dependensi siklik dalam beberapa kasus, kasus lain, yaitu dengan tipe yang memiliki dependensi melingkar, mungkin tidak mungkin untuk melakukan resolusi penuh.
Dependensi dibangun terlebih dahulu, dalam urutan mereka terdaftar di bagian 'dependensi'. Jika dependensi gagal dibangun, kompiler akan keluar dengan kesalahan dan tidak melanjutkan pembangunan proyek lainnya.
Saat setiap dependensi selesai, file '.d.ts' yang mewakili output akan tersedia untuk build saat ini. Setelah semua dependensi selesai, proyek saat ini dibangun.
Jika pengguna menetapkan subdirektori sebagai dependensi, dan juga menyiratkan kompilasinya dengan tidak menyediakan bagian 'file', dependensi dikompilasi selama kompilasi dependensi dan juga dihapus dari kompilasi proyek saat ini.
Layanan bahasa dapat melihat setiap ketergantungan. Karena setiap ketergantungan akan dihapus dari tsconfig.jsonnya sendiri, ini mungkin berarti bahwa beberapa contoh layanan bahasa perlu dibuat. Hasil akhirnya adalah layanan bahasa terkoordinasi yang mampu melakukan refactoring, navigasi kode, menemukan semua referensi, dll di seluruh dependensi.
Menambahkan direktori sebagai dependensi yang tidak memiliki tsconfig.json dianggap sebagai kesalahan.
Output dari dependensi diasumsikan mandiri dan terpisah dari proyek saat ini. Ini menyiratkan bahwa Anda tidak dapat menggabungkan output .js dari ketergantungan dengan proyek saat ini melalui tsconfig.json. Alat eksternal, tentu saja, dapat menyediakan fungsi ini.
Seperti disebutkan sebelumnya, dependensi melingkar dianggap sebagai kesalahan. Dalam kasus sederhana:
A - B
\ C
A adalah 'proyek saat ini' dan bergantung pada dua dependensi: B dan C. Jika B dan C sendiri tidak memiliki dependensi, kasus ini sepele. Jika C bergantung pada B, B tersedia untuk C. Ini tidak dianggap melingkar. Namun, jika B bergantung pada A, ini dianggap melingkar dan akan menjadi kesalahan.
Jika, dalam contoh, B bergantung pada C dan C mandiri, ini tidak akan dianggap sebagai siklus. Dalam hal ini, urutan kompilasinya adalah C, B, A, yang mengikuti logika yang kita miliki untuk ///ref.
Jika dependensi tidak dibangun kembali, maka langkah pembangunannya akan dilewati dan representasi '.d.ts' dari pembangunan sebelumnya digunakan kembali. Ini dapat diperluas untuk ditangani jika kompilasi dependensi telah membangun dependensi yang akan muncul nanti dalam daftar 'dependensi' proyek saat ini (seperti yang terjadi pada contoh yang diberikan di bagian Batasan).
Daripada memperlakukan direktori yang diteruskan sebagai dependensi yang tidak memiliki tsconfig.json sebagai kasus kesalahan, kita dapat secara opsional menerapkan 'file' default dan pengaturan proyek saat ini ke dependensi itu.
Ya Tuhan!
:+1:
Ya! Ini sangat masuk akal untuk kasus penggunaan yang Anda berikan. Menyediakan alat yang kami gunakan dengan pandangan yang lebih baik tentang bagaimana kode kami dimaksudkan untuk dikonsumsi jelas merupakan hal yang benar untuk dilakukan. Setiap kali saya F12 ke dalam file .d.ts secara tidak sengaja, saya merasa seperti mencekik anak kucing!
Jonatan,
Terima kasih banyak atas umpan balik yang baik dan telah memutuskan untuk menerima ini. TypeScript adalah alat yang hebat dan fungsi ini akan membantu banyak orang yang ingin membuat komponen basis kode berukuran sedang mereka yang tidak dapat membenarkan inefisiensi yang diamanatkan oleh proyek-proyek besar yang bergantung pada pembagian perhatian yang ketat (misalnya portal Azure atau proyek Monacos of dunia dengan > 100kloc dan banyak tim independen). Dengan kata lain, ini akan sangat membantu "orang biasa". Juga, yang lain telah mengusulkan hal-hal untuk ini, misalnya @NoelAbrahams (#2180), dan lainnya jadi saya tidak dapat mengklaim orisinalitas di sini. Ini hanya sesuatu yang saya butuhkan untuk sementara waktu.
Saya pikir proposal Anda sangat bagus. Satu-satunya kekurangan yang saya lihat dibandingkan proposal saya (#3394), yang sekarang telah saya tutup, adalah tidak adanya mekanisme mundur untuk referensi.
Pertimbangkan skenario dunia nyata berikut yang saya perinci di sini: https://github.com/Microsoft/TypeScript/issues/3394#issuecomment -109359701
Saya memiliki proyek TypeScript grunt-ts yang bergantung pada proyek csproj2ts yang berbeda. Hampir tidak ada orang yang bekerja di grunt-ts juga ingin bekerja di csproj2ts karena memiliki cakupan fungsionalitas yang sangat terbatas. Namun, untuk orang seperti saya - Akan sangat bagus untuk dapat mengerjakan kedua proyek secara bersamaan dan melakukan refactoring/buka definisi/temukan semua referensi di antara mereka.
Ketika saya membuat proposal saya, saya menyarankan agar objek dependensi menjadi objek literal dengan fallback bernama. Versi yang lebih sesuai dengan proposal Anda adalah:
"dependencies": {
"csproj2ts": ["../csproj2ts","node_modules/csproj2ts/csproj2ts.d.ts"],
"SomeRequiredLibrary": "../SomeRequiredLibraryWithNoFallback"
}
Untuk mempermudah hal itu masih menjadi sebuah array, saya sarankan pelaksanaan alternatif berikut masa depan yang hipotetis dependencies
bagian dari mendengus-ts tsconfig.json
berkas:
"dependencies": [
["../csproj2ts","node_modules/csproj2ts/csproj2ts.d.ts"],
"../SomeRequiredLibraryWithNoFallback"
]
Aturan resolusi untuk setiap item tipe array di dependencies
adalah: item _first_ yang ditemukan di masing-masing item adalah item yang digunakan, dan sisanya diabaikan. Item tipe string ditangani seperti yang dinyatakan oleh proposal Jonathan.
Ini adalah solusi yang sedikit lebih rumit untuk diterapkan, namun memberikan pengembang (dan penulis perpustakaan) _jauh lebih besar_ fleksibilitas. Untuk pengembang yang tidak perlu mengembangkan di csproj2ts (dan karena itu tidak memiliki file ../csproj2ts/tsconfig.json
), dependensi hanya akan menjadi file definisi yang ditambahkan ke konteks kompilasi. Untuk pengembang yang _melakukan_ file ../csproj2ts/tsconfig.json
, proposal akan bekerja persis seperti yang Anda jelaskan di atas.
Dalam contoh di atas, "../SomeRequiredLibraryWithNoFallback"
akan diminta untuk ada di sana seperti dalam proposal Anda yang ada, dan ketidakhadirannya akan menjadi kesalahan kompiler.
Terima kasih banyak telah mempertimbangkan hal ini.
Ada dua masalah di sini yang perlu kita pecahkan, ada yang membangun, dan ada dukungan layanan bahasa.
Untuk Build, saya tidak berpikir tsconfig adalah tempat yang tepat untuk ini. ini jelas merupakan masalah sistem build. dengan proposal ini kompiler TypeScript harus berada dalam bisnis:
Ini semua jelas merupakan tanggung jawab sistem pembangunan; ini adalah masalah yang sulit dan sudah ada alat yang melakukan itu, misalnya MSBuild, grunt, gulp, dll.
Setelah tsconfig dan tsc menjadi driver build, Anda akan menginginkannya menggunakan semua CPU untuk membangun subtree yang tidak terkait, atau memiliki perintah post dan pre build untuk setiap proyek, dan mungkin juga membangun proyek lain. sekali lagi, saya pikir ada alat build di luar sana yang bagus dalam apa yang mereka lakukan, dan tidak perlu bagi kita untuk membuatnya kembali.
Untuk Layanan Bahasa,
Saya pikir itu baik-baik saja untuk perkakas untuk mengetahui tentang beberapa file tsconfig dan dapat menyimpulkan dari itu dan membantu Anda lebih banyak, tetapi itu seharusnya tidak memengaruhi build Anda. saya akan mempertimbangkan sesuatu seperti:
"files" : [
"file1.ts",
{
"path": "../projectB/out/projectB.d.ts",
"sourceProject": "../projectB/"
}
]
Di mana tsc hanya akan melihat "jalur" tetapi alat dapat melihat informasi lain dan mencoba membantu semampu mereka.
Saya mengakui adanya masalah tetapi tidak menganggap lumping build dan tooling adalah solusi yang tepat. tsconfig.json harus tetap menjadi tas konfigurasi (yaitu alternatif json untuk file respons) dan tidak menjadi sistem pembangunan. satu tsconfig.json mewakili satu permintaan tsc. tsc harus tetap sebagai kompiler proyek tunggal.
Proyek MSBuild di VS adalah contoh penggunaan sistem build untuk membangun fitur IDE dan sekarang ppl tidak senang dengannya karena terlalu besar.
Terima kasih atas balasan Anda, Muhammad. Biarkan saya menyatakan kembali untuk melihat apakah saya mengerti:
tsc --project
pada tsconfig.json
akan sama dengan menjalankan tsc file1.ts ../project/out/project.d.ts
. Namun, membuka proyek semacam itu di VS atau editor lain dengan layanan bahasa TypeScript akan memungkinkan "go to definition" untuk membawa pengembang ke _actual TypeScript file_ tempat fitur itu didefinisikan (bukan definisi di projectB.d.ts
)Apakah saya memiliki hak itu?
Jika demikian, saya pikir ini sangat adil. Dalam proposal asli saya ( https://github.com/Microsoft/TypeScript/issues/3394 ), saya memang mengatakan bahwa ide saya tidak lengkap karena tidak menyertakan langkah menyalin hasil yang dipancarkan dari tempat mereka akan dikeluarkan di perpustakaan yang direferensikan ke tempat perpustakaan referensi mengharapkannya saat runtime. Saya pikir Anda mengatakan "mengapa pergi setengah jalan untuk membangun ketika yang benar-benar dibutuhkan adalah dukungan layanan bahasa".
Untuk sedikit mengubah data dalam contoh Anda, apakah Anda bersedia mendukung sesuatu seperti ini?
"files" : [
"file1.ts",
{
"path": "externalLibraries/projectB.d.ts",
"sourceProject": "../projectB/"
}
]
Asumsinya adalah bahwa proyek saat ini akan dikirimkan dengan definisi untuk projectB yang akan digunakan secara default, tetapi jika sumber aktual untuk projectB tersedia, sumber aktual akan digunakan sebagai gantinya.
@nycdotnet Anda menyimpulkannya dengan benar; saya ingin membuat sistem yang digabungkan secara longgar dan memungkinkan pencampuran dan pencocokan alat pembuatan yang berbeda dengan IDE yang berbeda tetapi tetap mendapatkan pengalaman waktu desain yang hebat.
Kedengarannya bagus!
Saya setuju dengan @mhegazy dan sebenarnya menurut saya penting bagi TypeScript untuk berhenti menganggap dirinya sebagai 'compiler' dan mulai menganggap dirinya sebagai 'type-checker' dan 'transpiler'. Sekarang ada dukungan transpilasi file tunggal Saya tidak melihat alasan untuk membuat file JavaScript yang dikompilasi kecuali untuk saat runtime/bundling. Saya juga tidak mengerti mengapa perlu untuk menghasilkan definisi referensi eksternal selama pengecekan tipe ketika sumber TypeScript yang sebenarnya tersedia.
Resolusi file dan paket adalah tanggung jawab sistem build yang Anda gunakan (browserify, systemjs, webpack dll), jadi agar perkakas berfungsi, layanan bahasa harus dapat menyelesaikan file dengan cara yang sama seperti sistem/platform build apa pun yang Anda gunakan. sedang menggunakan. Ini berarti mengimplementasikan LanguageServicesHost kustom untuk setiap sistem build atau menyediakan alat untuk masing-masing sistem yang menghasilkan entri pemetaan yang benar di tsconfig.json. Salah satu dari ini dapat diterima.
@nycdotnet Saya pikir kasus penggunaan Anda untuk beberapa jalur mundur akan lebih baik ditangani menggunakan npm link ../csproj2ts
?
Saya setuju dengan @mhegazy bahwa kita harus memisahkan build dari compiler/transpiler. Saya suka menyertakan ketergantungan tsconfig -> tsconfig di bagian file dengan asumsi bahwa jika bagian tersebut tidak mencantumkan file *.ts, ia masih memindainya. Misalnya
"berkas" : [
{
"path": "externalLibraries/projectB.d.ts",
"sourceProject": "../projectB/"
}
]
Akan tetap menyertakan semua file ts dalam direktori dan subdirektori yang berisi file tsconfig.json.
@dbaeumer Anda kemudian ingin memilikinya di properti yang berbeda, benar? saat ini, jika file didefinisikan, itu selalu digunakan dan kami mengabaikan bagian include *.ts.
@mhegazy belum tentu bagian yang berbeda meskipun pada akhirnya akan membuat segalanya lebih jelas. Yang ingin saya hindari adalah dipaksa untuk membuat daftar semua file jika saya menggunakan tsconfig -> tsconfig dependensi. Dalam contoh di atas saya masih ingin untuk tidak mencantumkan file *.ts untuk memasukkannya ke dalam kompiler.
Saya rasa ini sangat dibutuhkan. Saya tidak berpikir kita bisa menghindari pertanyaan build. Itu tidak berarti kita perlu menerapkan sistem pembangunan bersama dengan proposal ini, tetapi kita harus memikirkan beberapa panduan bagus yang berfungsi dalam konfigurasi seperti yang diusulkan. Tidak akan mudah untuk memperbaikinya (dan kita perlu menyelesaikannya untuk Visual Studio).
Dalam proposal di atas (di mana .d.ts dan sumber direferensikan), apakah itu mendeteksi jika .d.ts kedaluwarsa (yaitu perlu dibangun kembali)? Apakah operasi seperti Refactor/Rename bekerja di seluruh proyek (yaitu memperbarui nama di sumber proyek yang direferensikan, bukan hanya file .d.ts yang akan ditimpa build berikutnya)? Apakah GoToDef membawa saya ke kode asli dalam proyek yang direferensikan (bukan di tengah file .d.ts raksasa untuk keseluruhan proyek)? Ini tampaknya menyiratkan perlu untuk menyelesaikan, dan dalam beberapa kasus menganalisis, sumber proyek yang direferensikan, dalam hal mana .d.ts yang berguna?
Solusi umum, yang kita miliki hari ini, Anda memiliki .d.ts sebagai output build dari satu proyek, dan kemudian dirujuk sebagai input di proyek lain. Ini berfungsi dengan baik untuk build, jadi tidak perlu mengubahnya.
Masalahnya adalah skenario pengeditan. Anda tidak ingin melalui file yang dihasilkan saat mengedit. Solusi yang saya usulkan adalah memberikan "petunjuk" dari mana .d.ts yang dihasilkan berasal. Layanan bahasa kemudian tidak akan memuat .d.ts, dan sebagai gantinya memuat "proyek" dari jalur petunjuk. cara ini goto def akan membawa Anda ke file implementasi alih-alih .d.ts dan kesalahan serupa akan bekerja tanpa perlu kompilasi.
operasi seperti mengganti nama, akan "menyebar" dari satu proyek ke proyek lain, juga menemukan referensi, akan dilakukan.
Hari ini sepenuhnya tergantung pada host (IDE, apa pun) untuk menemukan file tsconfig.json, meskipun TS kemudian menyediakan API untuk membaca dan menguraikannya. Bagaimana Anda membayangkan ini bekerja jika ada beberapa tsconfig.json yang terletak secara hierarkis? Apakah tuan rumah masih bertanggung jawab untuk menyelesaikan file awal tetapi tidak yang lain atau apakah tuan rumah akan bertanggung jawab untuk menyelesaikan semua tsconfig?
Sepertinya ada tradeoff antara kenyamanan/konvensi dan fleksibilitas.
Bukankah ini akan dimulai dengan kemampuan untuk membuat file d.ts seperti yang dijelaskan di #2568 (atau setidaknya memiliki impor relatif)?
@spion saya tidak yakin saya melihat ketergantungan di sini. Anda dapat memiliki beberapa keluaran proyek, Anda tidak harus menjadi satu file delectation. sistem build harus dapat mengetahuinya dan menghubungkannya sebagai input ke proyek yang bergantung.
@mhegazy Ups, maaf. Melihat masalah lagi, tampaknya ini lebih terkait dengan layanan bahasa. Saya membaca yang berikut ini
- Proyek berukuran sedang: proyek dengan build standar dan komponen bersama
dan secara otomatis menganggapnya terkait dengan dukungan yang lebih baik untuk npm/browserify (atau webpack) membangun worfklow di mana bagian dari proyek adalah modul eksternal.
AFAIK belum ada cara untuk menghasilkan file .d.ts untuk modul eksternal? Jika demikian, satu-satunya cara layanan bahasa dapat menautkan proyek yang mengimpor modul eksternal adalah dengan memiliki sesuatu seperti ini di tsconfig.json :
{
"provides": "external-module-name"
}
yang akan menginformasikan LS ketika proyek direferensikan di tsconfig.json
AFAIK belum ada cara untuk menghasilkan file .d.ts untuk modul eksternal?
Saya tidak berpikir ini benar. memanggil tsc --m --d
akan menghasilkan file deklarasi yang merupakan modul eksternal itu sendiri. logika resolusi akan mencoba menemukan .ts dan jika tidak maka .d.ts dengan nama yang sama,
@spion TypeScript dapat menghasilkan file d.ts untuk modul eksternal seperti yang dikatakan @mhegazy , tetapi ini menghasilkan rasio definisi 1: 1 ke file sumber yang berbeda dari cara definisi TypeScript perpustakaan biasanya dikonsumsi. Salah satu cara untuk mengatasinya adalah perpustakaan TypeStrong ini: https://github.com/TypeStrong/dts-bundle
@mhegazy maaf, maksud saya untuk "modul eksternal ambient" yaitu jika saya menulis external-module-name
di TypeScript dan mengimpor salah satu kelasnya dari modul lain:
import {MyClass} from 'external-module-name'
tidak ada cara untuk membuat tsc
menghasilkan file .d.ts yang sesuai yang menyatakan 'external-module-name'
@nycdotnet Saya mengetahui dts-bundle dan dts-generator tetapi masih jika layanan bahasa mengetahui tentang sumber proyek saya yang lain, ia juga harus tahu nama modul apa yang disediakannya untuk dapat melacak impor dengan benar
Apa status fitur ini? tampaknya ini adalah opsi penting untuk proyek ukuran sedang. Bagaimana Anda mengonfigurasi proyek yang memiliki sumber di folder berbeda dengan konfigurasi "requirejs" tertentu?
@llgcode silakan lihat di https://github.com/Microsoft/TypeScript/issues/5039 , ini harus tersedia di typescript@next
.
Saya tidak begitu mengerti apa yang sulit tentang menulis gulpfile dengan tugas-tugas yang mengkompilasi sub-proyek seperti yang Anda butuhkan untuk proyek berukuran sedang. Saya bahkan melakukan ini dalam proyek berukuran kecil. Satu-satunya alasan saya menggunakan tsconfig.json adalah untuk Kode VS
Pertama saya tidak menggunakan gulp. Kedua, ini bisa menjadi proyek besar di mana Anda tidak ingin mengkompilasi ulang setiap saat. Tetapi jika Anda memiliki solusi yang baik dengan tegukan, beri tahu saya bagaimana melakukan ini.
@llgcode Yah, tegukan adalah pelari tugas. Anda menulis gulpfile.js di mana Anda mendefinisikan tugas sebanyak yang Anda suka dengan gulp.task()
. Di dalam tugas Anda, Anda dapat mengambil aliran file input dengan gulp.src()
dan kemudian .pipe()
mereka melalui pipa transformasi, seperti kompilasi, penggabungan, minifikasi, peta sumber, menyalin aset ... Anda dapat lakukan apa pun yang mungkin dengan modul Node dan NPM.
Jika Anda harus mengkompilasi beberapa proyek, cukup tentukan tugas yang melakukan ini. Jika Anda ingin menggunakan beberapa tsconfig.json, gulp -typescript memiliki dukungan untuk itu, atau Anda bisa membaca file json. Build tambahan juga dimungkinkan. Saya tidak tahu bagaimana proyek Anda terstruktur, jika Anda memilikinya di repo yang berbeda dan menggunakan submodul, atau apa pun. Tapi tegukan 100% fleksibel.
Ok terima kasih tampaknya menjadi alat yang hebat. jika saya memerlukan pemetaan seperti require("mylibs/lib") dan file saya misalnya dalam folder project/src/lib.js maka penyelesaian tidak akan berfungsi di atom dan saya tidak tahu bagaimana TypeScript atau gulp akan menyelesaikannya pemetaan/konfigurasi dilakukan dengan "mylibs" dan jalur lokal. jadi saya pikir jalur opsi baru di #5039 ini adalah solusi yang baik untuk masalah ini.
@llgcode Nah dengan https://www.npmjs.com/package/gulp-typescript#resolve -files.
Saya hanya berpikir TypeScript mencoba melakukan banyak hal di sini, ini adalah transpiler dan bukan alat build. Mengelola "dependensi" seperti yang disebutkan dalam proposal benar-benar tugas manajer paket atau sistem kontrol versi dan menghubungkannya bersama-sama adalah tugas membangun alat.
@felixfbecker saya tidak setuju. Setiap kompiler (dengan pemeriksaan tipe) yang saya tahu memiliki opsi seperti ini. Misalnya:
gcc -> sertakan file
Java -> classpath & sourcepath
pergi -> GOPATH
python -> PYTHONPATH
kompiler/transpiler perlu mengetahui file sumber apa yang perlu ditranspilasikan file sumber apa yang hanya termasuk/lib file.
Membangun alat seperti gulp diperlukan untuk mengetahui apa yang harus dilakukan ketika sebuah file berubah.
Setuju dengan @llgcode . Selain itu, selain mengekspos sebagai kompiler, TypeScript juga mengekspos sebagai layanan bahasa, yang menyediakan sorotan sintaks (sebenarnya deteksi) dan fungsionalitas penyelesaian ke IDE. Dan ITU juga perlu berjalan di pohon ketergantungan.
@llgcode @unional Poin yang valid. Satu hal yang mungkin juga membantu adalah membuat properti files
di tsconfig.json menerima gumpalan sehingga Anda dapat menentukan semua file di semua folder yang ingin Anda sertakan. Tapi saya melihat dari mana Anda berasal dan mengapa seseorang mungkin menginginkan beberapa tsconfig.json untuk proyek yang lebih besar.
AFAIK untuk CommonJS ini sudah didukung melalui node_modules
dan npm link ../path/to/other-project
npm link tidak berfungsi segera setelah Anda mulai menggunakan kembali perpustakaan di seluruh proyek. Jika Anda menggunakan perpustakaan umum antara dua proyek terpisah Anda sendiri, (mengambil rxjs sebagai contoh) TypeScript akan memberi tahu Anda bahwa 'Observable is not assignable to Observable'. Itu karena jalur sertakan mengikuti folder symlink ke dua folder node_modules yang berbeda dan meskipun merupakan perpustakaan yang sama. Solusi menghasilkan tugas teguk atau repo npm lokal/pribadi, pada dasarnya kembali ke opsi proyek besar.
@EricABC itu mungkin karena mereka menggunakan deklarasi modul eksternal ambient, dalam hal ini mereka juga harus menyertakan definisi untuk file .d.ts berbasis node_modules
baru didukung. Selain itu, seharusnya tidak ada masalah karena tipe TS hanya diperiksa secara struktural, jadi tidak masalah jika mereka berasal dari modul yang berbeda atau memiliki nama yang berbeda selama strukturnya cocok.
Terima kasih @spion , anggap saja itu berbasis file, sepertinya Anda akan menyelamatkan saya dari rasa sakit yang diderita sendiri.
Satu hal yang mungkin juga membantu adalah membuat properti files di tsconfig.json menerima gumpalan...
Ada properti include
dalam diskusi
Pertanyaan dan komentar:
dependencies
harus mengizinkan jalur tsconfig.json penuh karena tsc mengizinkannyadependencies
) ketika files
sudah ada dan baik-baik saja?{
"compilerOptions": {
// ...
},
"files": [
"../common/tsconfig.json", // <== takes the `files` part of the tsconfig.json
"../common/tsconfig.util.json", // <==
"core.ts",
"sys.ts"
]
}
compilerOptions
?Mari kita melangkah lebih jauh/liar :-) dan mungkin mengizinkan (di masa depan) compilerOptions
, exclude
... untuk referensi tsconfig.json lain:
// File app/tsconfig.json
{
"compilerOptions": "../common/tsconfig.compilerOptions.json",
"files": [
"../common/tsconfig.json",
"../common/tsconfig.util.json",
"core.ts",
"sys.ts"
],
"exclude": "../common/exclude.json"
}
// File ../common/tsconfig.compilerOptions.json
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"sourceMap": true
}
}
// File ../common/exclude.json
{
"exclude": [
"node_modules",
"wwwroot"
]
}
// File ../common/tsconfig.util.json
{
"files": [
"foo.ts",
"bar.ts"
]
}
Anda mendapatkan logikanya: files
, compilerOptions
, exclude
... dapat mereferensikan file tsconfig.json lain dan itu hanya akan "mengambil" bagian kata kunci yang cocok dari tsconfig lain File .json => mudah dan skalabel. Dengan demikian, Anda dapat membagi tsconfig.json menjadi beberapa file jika Anda mau dan menggunakannya kembali.
Membaca bagian dari diskusi Anda, tampaknya paling relevan untuk mendapatkan "layanan bahasa"/definisi goto ini dengan benar. Debugger JavaScript menggunakan sourceMaps. Sekarang, jika tsc menghasilkan data sourceMap tidak hanya di .js tetapi juga di file .d.ts...
Di luar itu saya benar-benar tidak melihat banyak manfaat dalam memicu pembangunan proyek anak dari dalam file tsconfig.json. Jika Anda memerlukan dependensi waktu pembuatan semacam ini, skrip shell sederhana akan melakukan pekerjaan itu. Jika Anda membutuhkan bangunan inkremental yang cerdas, di sisi lain, pendekatan yang diusulkan tampaknya terlalu sederhana. Dalam banyak skenario, tsc berakhir hanya sebagai satu langkah pembangunan di antara yang lain. Seberapa aneh dependensi penulisan untuk tsc di tsconfig.json tetapi beberapa file lain untuk sisanya? Sekali lagi, untuk hal-hal sederhana dengan tsc menjadi satu-satunya langkah pembuatan yang akan dilakukan skrip Shell.
Bagaimanapun, bagaimana menghasilkan pemetaan sumber dalam file .d.ts seperti pada file .js?
kami hanya menggunakan modul node + tautan npm, satu-satunya hal yang tidak berfungsi adalah node moduleResolution: tidak kompatibel dengan modul ES6, yang memungkinkan pengoptimalan inlining / tree-shaking (lihat juga #11103 )
Bukan untuk keluar dari topik, tetapi dalam beberapa hal, ini tampaknya paralel dengan tantangan bekerja dengan beberapa proyek paket Node secara lokal. Saya tidak berpikir itu sesederhana hanya menggunakan "tautan npm." Mereka mungkin memiliki skrip build yang berbeda, Anda harus menjalankan semuanya dalam urutan yang benar, lebih sulit untuk melakukannya secara bertahap, lebih sulit untuk menggunakan mode tontonan, lebih sulit untuk men-debug sesuatu, dan lebih sulit untuk menyelesaikan peta sumber. Tergantung pada editor pilihan Anda, ini mungkin lebih menantang.
Umumnya saya hanya menyerah, memasukkan semuanya ke dalam satu proyek raksasa, lalu membaginya menjadi paket-paket terpisah setelah mereka stabil, tetapi itu hanya membantu karena tantangannya lebih jarang dihadapi. Saya menemukan seluruh pengalaman benar-benar menjengkelkan. Apakah saya melewatkan sesuatu?
Jadi, apa pun akhirnya, saya hanya berharap saya akhirnya dapat memiliki solusi yang elegan untuk seluruh pengalaman pengembangan ini.
Hanya berdentang bahwa ini akan bagus untuk pekerjaan kita sehari-hari!
Karena sifat pengembangan web, kami memiliki beberapa proyek ts dengan setiap proyek berisi beberapa file ts yang dikompilasi ke dalam satu file js ( --outFile
). Ini adalah proyek seperti aplikasi (mereka melakukan hal tertentu atau menambahkan fitur tertentu) atau proyek seperti lib (kode yang dapat digunakan kembali untuk aplikasi). Seringkali kami mengerjakan beberapa proyek ts ini secara bersamaan, meningkatkan perpustakaan untuk memfasilitasi pengembangan pada aplikasi. Tapi saya rasa tidak ada rekan pengembang saya yang memiliki semua proyek ts kami di lingkungan lokal mereka kapan saja.
Untuk meningkatkan alur kerja kami, opsi kami saat ini adalah
tsc -d -w
dari beberapa terminal, atau menjalankan skrip yang melakukan itu untuk semua subdirektori tempat tsconfig ditemukan.Proyek kami tidak cukup besar untuk memisahkan pengembangan perpustakaan dari aplikasi, tetapi tidak cukup kecil sehingga kami dapat menggabungkan semuanya. Kami menemukan diri kami kekurangan pilihan anggun dengan TypeScript.
Jika dependencies
bisa menjadi pilihan terbaik dari kedua dunia, itu akan luar biasa; fungsi daritag ke semua file ts dependensi, tetapi kompilasi output sesuai dengan file tsconfig.
Apakah ada pembaruan tentang topik ini. Bagaimana kita bisa memiliki beberapa proyek TypeScript yang dikompilasi secara independen satu sama lain? Bagaimana kita bisa menggambarkan ketergantungan seperti itu di tsconfig.json?
Ini sekarang termasuk dalam peta jalan di bagian mendatang dengan judul "Dukungan untuk referensi proyek". Jadi, saya kira file .tsconfig
akan dapat menautkan file .tsconfig
sebagai dependensi.
Apakah ada pembaruan tentang topik ini. Bagaimana kita bisa memiliki beberapa proyek TypeScript yang dikompilasi secara independen satu sama lain? Bagaimana kita bisa menggambarkan ketergantungan seperti itu di tsconfig.json?
Ketergantungan build harus dikodekan dalam sistem build Anda. membangun sistem seperti gulp, grunt, brokoli, msbuild, basal, dll. dibangun untuk menangani kasus seperti itu.
Untuk informasi tipe, output dari satu proyek harus menyertakan .d.ts dan itu harus diteruskan sebagai input ke proyek lainnya.
@mhegazy Proyek kami bekerja seperti ini. Kami memiliki sejumlah paket dalam lerna monorepo, setiap paket memiliki dependensinya sendiri di package.json, dan dependensi yang sama di properti "types"
di tsconfig.json
. Setiap proyek dikompilasi dengan --outFile
(ini adalah proyek lama yang belum pindah ke modul ES), dan kunci "typings"
package.json
ke paket .d.ts
berkas.
Kami menggunakan gulp untuk bundling/watching.
Ini berfungsi untuk sebagian besar, tetapi ada beberapa masalah:
.d.ts
dibundel. Idealnya ini akan membawa Anda ke sumber di proyek lain.lerna run build --sort
(efektif tsc
di setiap direktori), yang memiliki overhead tambahan karena akan menelurkan satu proses kompiler TypeScript untuk setiap paket, melakukan banyak pekerjaan berulang .Saya terus memperhatikan masalah ini karena kami juga berada dalam situasi yang sama seperti yang dijelaskan orang lain.
Beberapa "proyek", masing-masing dengan file tsconfig.json-nya.
Kami memiliki proses build yang berfungsi seperti yang ditunjukkan @mhegazy : setiap proyek mengeluarkan file .d.ts
dan itu digunakan sebagai input untuk proyek yang bergantung.
Masalah sebenarnya adalah dukungan IDE: ketika mencari referensi, mereka hanya ditemukan dalam lingkup tsconfig.json
tunggal. Lebih buruk lagi, efek cascading dari file yang diubah tidak menyebar ke seluruh proyek karena tergantung file di luar lingkup tsconfig.json
tidak dikompilasi ulang. Ini sangat buruk untuk pemeliharaan proyek kami dan terkadang menyebabkan kesalahan build yang bisa saja tertangkap di IDE.
YA TUHAN
Skenario yang diperbarui di mana saya ingin ini melibatkan komponen React. Kami memiliki repo komponen yang berisi modul JSX (atom, molekul, dan organisme) yang membuat komponen UI sesuai untuk semua aplikasi di perusahaan kami. Repo komponen ini digunakan oleh semua pengembang front-end saat mereka mengerjakan aplikasi masing-masing. Akan SANGAT BAIK jika saya dapat memiliki pengalaman layanan bahasa TypeScript yang memungkinkan saya untuk mengedit UI aplikasi khusus saya dan "Pergi ke definisi" ke dalam repo komponen UI umum. Hari ini kita harus menggabungkan komponen-komponen ini satu per satu dan menyalinnya. Ini adalah masalah "buat pipa proyek Anda sendiri" yang ingin saya perbaiki (untuk itu ada cerita yang sangat bagus di dunia .NET dengan proyek di bawah solusi).
TypeScript telah ditingkatkan ke proyek ratusan ribu baris, tetapi tidak secara asli mendukung skala semacam ini sebagai perilaku bawaan. Tim telah mengembangkan solusi dengan berbagai efektivitas dan tidak ada cara standar untuk mewakili proyek besar. Meskipun kami telah sangat meningkatkan kinerja pemeriksa tipe dari waktu ke waktu, masih ada batasan keras dalam hal seberapa cepat TS bisa mendapatkan,
dan kendala seperti ruang alamat 32-bit yang mencegah layanan bahasa meningkatkan skala "tanpa batas" dalam skenario interaktif.
Secara intuitif, mengubah satu baris BEJ di komponen front-end seharusnya tidak memerlukan pengecekan ulang seluruh komponen logika bisnis inti dari proyek 500.000 LOC. Tujuan dari referensi proyek adalah untuk memberikan alat pengembang untuk mempartisi kode mereka menjadi blok yang lebih kecil. Dengan mengaktifkan alat untuk beroperasi pada bagian pekerjaan yang lebih kecil pada satu waktu, kami dapat meningkatkan daya tanggap dan mengencangkan loop pengembangan inti.
Kami percaya arsitektur kami saat ini hanya memiliki sedikit "makan siang gratis" yang tersisa dalam hal peningkatan drastis dalam kinerja atau konsumsi memori. Sebaliknya, partisi ini adalah pertukaran eksplisit yang meningkatkan kecepatan dengan mengorbankan beberapa pekerjaan di muka. Pengembang harus meluangkan waktu untuk mempertimbangkan grafik ketergantungan sistem mereka, dan fitur interaktif tertentu (misalnya penggantian nama lintas proyek) mungkin tidak tersedia sampai kami menyempurnakan alat lebih lanjut.
Kami akan mengidentifikasi kendala utama yang diberlakukan oleh sistem ini dan menetapkan pedoman untuk ukuran proyek, struktur direktori, dan pola pembangunan.
Ada tiga skenario utama yang perlu dipertimbangkan.
Beberapa proyek secara ekstensif menggunakan impor relatif . Impor ini secara jelas diselesaikan ke file lain di disk. Jalur seperti ../../core/utils/otherMod
akan umum ditemukan, meskipun struktur direktori yang lebih datar biasanya lebih disukai dalam repo ini.
Berikut ini contoh dari proyek perseus Khan Academy:
Diadaptasi dari https://github.com/Khan/perseus/blob/master/src/components/graph.jsx
const Util = require("../util.js");
const GraphUtils = require("../util/graph-utils.js");
const {interactiveSizes} = require("../styles/constants.js");
const SvgImage = require("../components/svg-image.jsx");
Sementara struktur direktori menyiratkan struktur proyek, itu belum tentu definitif. Dalam contoh Khan Academy di atas, akan dapat menyimpulkan bahwa util
, styles
, dan components
mungkin akan menjadi proyek mereka sendiri. Tetapi mungkin juga direktori ini cukup kecil dan sebenarnya akan dikelompokkan ke dalam satu unit build.
Mono-repo terdiri dari sejumlah modul yang diimpor melalui jalur non-relatif . Impor dari sub-modul (misalnya import * as C from 'core/thing
) mungkin umum. Biasanya, tetapi tidak selalu, setiap modul root sebenarnya diterbitkan di NPM.
Diadaptasi dari https://github.com/angular/angular/blob/master/packages/forms/src/validators.ts
import {InjectionToken, ɵisObservable as isObservable, ɵisPromise as isPromise} from '@angular/core';
import {forkJoin} from 'rxjs/observable/forkJoin';
import {map} from 'rxjs/operator/map';
import {AbstractControl, FormControl} from './model';
Unit pembagian tidak harus menjadi bagian utama dari nama modul. rxjs
, misalnya, sebenarnya mengkompilasi subbagiannya ( observable
, operator
) secara terpisah, seperti halnya paket cakupan (misalnya @angular/core
).
TypeScript dapat menggabungkan file inputnya menjadi file JavaScript output tunggal. Arahan referensi, atau pemesanan file di tsconfig.json, membuat urutan output deterministik untuk file yang dihasilkan. Ini jarang digunakan untuk proyek baru, tetapi masih lazim di antara basis kode lama (termasuk TypeScript itu sendiri).
https://github.com/Microsoft/TypeScript/blob/master/src/compiler/tsc.ts
/// <reference path="program.ts"/>
/// <reference path="watch.ts"/>
/// <reference path="commandLineParser.ts"/>
https://github.com/Microsoft/TypeScript/blob/master/src/harness/unittests/customTransforms.ts
/// <reference path="..\..\compiler\emitter.ts" />
/// <reference path="..\harness.ts" />
Beberapa solusi yang menggunakan konfigurasi ini akan memuat setiap outFile
melalui tag script
(atau yang setara), tetapi yang lain (misalnya TypeScript sendiri) memerlukan penggabungan file sebelumnya karena mereka sedang membangun keluaran monolitik .
Beberapa pengamatan kritis dari interaksi dengan proyek nyata:
skipLibCheck
, hampir "gratis" dalam hal pengecekan tipe dan biaya memoriMenyatukan ini, jika mungkin untuk hanya memeriksa satu 50.000 LOC potongan kode implementasi sekaligus, hampir tidak ada interaksi "lambat" dalam skenario interaktif, dan kami hampir tidak pernah kehabisan memori.
Kami memperkenalkan konsep baru, referensi proyek , yang mendeklarasikan jenis ketergantungan baru antara dua unit kompilasi TypeScript di mana kode implementasi unit dependen tidak dicentang; alih-alih kita cukup memuat output .d.ts
dari lokasi deterministik.
Opsi references
(TODO: Bikeshed!) ditambahkan ke tsconfig.json
:
{
"extends": "../tsproject.json",
"compilerOptions": {
"outDir": "../bin",
"references": [
{ "path": "../otherProject" }
]
}
}
Array references
menentukan satu set proyek lain untuk referensi dari proyek ini.
Setiap references
objek path
menunjuk ke file tsconfig.json
atau folder yang berisi file tsconfig.json
.
Pilihan lain dapat ditambahkan ke objek ini saat kami menemukan kebutuhan mereka.
Referensi proyek mengubah perilaku berikut:
.ts
di subdirektori dari proyek rootDir
, alih - .d.ts
di proyek itu outDir
Referenced project "../otherProject" is not built
daripada "file tidak ditemukan" sederhanaUntuk meningkatkan kinerja build secara bermakna, kita perlu memastikan untuk membatasi perilaku TypeScript saat melihat referensi proyek.
Secara khusus, hal-hal berikut harus benar:
tsconfig.json
dari proyek yang direferensikan yang harus dibaca dari diskUntuk memenuhi janji ini, kami perlu memberlakukan beberapa batasan pada proyek yang Anda referensikan.
declaration
secara otomatis disetel ke true
. Ini adalah kesalahan untuk mencoba menimpa pengaturan inirootDir
default ke "."
(direktori yang berisi file tsconfig.json
), daripada disimpulkan dari kumpulan file inputfiles
disediakan, itu harus memberikan nama semua file inputnode_modules/@types
) tidak perlu ditentukanreferences
(yang mungkin kosong)."declaration": true
?Referensi proyek meningkatkan kecepatan build dengan menggunakan file deklarasi (.d.ts) sebagai pengganti file implementasinya (.ts).
Jadi, tentu saja, setiap proyek yang direferensikan harus memiliki pengaturan declaration
.
Ini tersirat oleh "project": true
rootDir
?rootDir
mengontrol bagaimana file input dipetakan ke nama file output. Perilaku default TypeScript adalah menghitung direktori sumber umum dari grafik lengkap file input. Misalnya, kumpulan file input ["src/a.ts", "src/b.ts"]
akan menghasilkan file output ["a.js", "b.js"]
,
tetapi kumpulan file input ["src/a.ts", "b.ts"]
akan menghasilkan file output ["src/a.js", "b.js"]
.
Menghitung kumpulan file input memerlukan penguraian setiap file root dan semua referensinya secara rekursif,
yang mahal dalam proyek besar. Tetapi kita tidak dapat mengubah perilaku ini hari ini tanpa merusak proyek yang ada dengan cara yang buruk, jadi perubahan ini hanya terjadi ketika array references
disediakan.
Secara alami, proyek mungkin tidak membentuk grafik dengan sirkularitas apa pun. (TODO: Masalah apa yang sebenarnya disebabkan oleh hal ini, selain mimpi buruk orkestrasi build?) Jika ini terjadi, Anda akan melihat pesan kesalahan yang menunjukkan jalur melingkar yang terbentuk:
TS6187: Project references may not form a circular graph. Cycle detected:
C:/github/project-references-demo/core/tsconfig.json ->
C:/github/project-references-demo/zoo/tsconfig.json ->
C:/github/project-references-demo/animals/tsconfig.json ->
C:/github/project-references-demo/core/tsconfig.json
tsbuild
Proposal ini sengaja dibuat kabur tentang bagaimana itu akan digunakan dalam sistem pembangunan "nyata". Sangat sedikit proyek yang melampaui batas "cepat" 50.000 LOC tanpa memperkenalkan sesuatu selain tsc
untuk mengkompilasi kode .ts.
Skenario pengguna "Anda tidak dapat membuat foo
karena bar
belum dibuat" adalah jenis tugas "Ambil itu" yang harus ditangani oleh komputer, bukan dari beban mental pada pengembang.
Kami berharap alat seperti gulp
, webpack
, dll, (atau plugin TS masing-masing) akan membangun pemahaman tentang referensi proyek dan menangani dependensi build ini dengan benar, termasuk pemeriksaan terkini.
Untuk memastikan bahwa ini memungkinkan , kami akan menyediakan implementasi referensi untuk alat orkestrasi build TypeScript yang menunjukkan perilaku berikut:
Alat ini hanya boleh menggunakan API publik, dan didokumentasikan dengan baik untuk membantu pembuat alat memahami cara yang benar untuk mengimplementasikan referensi proyek.
Bagian yang harus diisi untuk melengkapi proposal ini
tsconfig.json
dan kemudian tambahkan referensi yang diperlukan untuk memperbaiki kesalahan pembuatanbaseUrl
dtsEmitOnly
untuk orang-orang yang mem-pipe JS mereka melalui mis. webpack/babel/rollup?references
+ noEmit
menyiratkan iniFantastis!
Cari tahu skenario Lerna
- Titik data yang tersedia (N = 1) mengatakan mereka tidak membutuhkan ini karena build mereka sudah terstruktur secara efektif dengan cara ini
Apakah "ini" merujuk pada proposal atau implementasi pembangunan referensi? Meskipun Anda dapat menggunakan lerna untuk melakukan pembangunan (tim saya melakukannya), itu sangat kasar dan akan jauh lebih efisien jika TS (atau alat yang dibuat dari proposal ini) menangani dirinya sendiri.
Bagian TODO adalah TODO untuk keseluruhan proposal
Bagus!
Setiap proyek yang direferensikan harus memiliki larik referensi (yang mungkin kosong).
Apakah ini benar-benar diperlukan? Tidakkah cukup jika paket seperti itu memiliki file .d.ts
?
(Dalam hal ini, bahkan mungkin tidak perlu karena ada tsconfig.json
, juga?)
Kasus penggunaan saya: pertimbangkan proyek (misalnya pihak ketiga) yang tidak menggunakan outDir
, jadi .ts
, .js
dan .d.ts
akan berada di sebelah satu sama lain, dan TS saat ini akan mencoba mengkompilasi .ts
daripada menggunakan .d.ts
.
Alasan untuk tidak menggunakan outDir
bagi saya adalah untuk lebih mudah mengizinkan impor import "package/subthing"
-style, yang seharusnya misalnya import "package/dist/subthing"
dengan outDir: "dist"
.
Dan untuk dapat menggunakan paket NPM, atau repositori sumbernya secara langsung (misalnya dengan npm link
).
(Akan sangat membantu jika package.json
diizinkan menentukan direktori di main
, tapi sayangnya...)
Apakah kita memerlukan pengaturan dtsEmitOnly untuk orang-orang yang menyalurkan JS mereka melalui misalnya webpack/babel/rollup?
Sangat! Ini adalah bagian besar yang hilang saat ini. Saat ini Anda bisa mendapatkan satu file d.ts saat menggunakan outFile
, tetapi ketika Anda beralih ke modul dan menggunakan bundler, Anda kehilangan ini. Mampu memancarkan satu file d.ts untuk titik masuk modul (dengan export as namespace MyLib
) akan luar biasa. Saya tahu alat eksternal dapat melakukan ini tetapi akan sangat bagus jika diintegrasikan ke dalam emitor dan layanan bahasa.
Apakah ini benar-benar diperlukan? Tidakkah cukup jika paket seperti itu memiliki file .d.ts?
Kami membutuhkan sesuatu di tsconfig target yang memberi tahu kami di mana diharapkan file output berada. Versi sebelumnya dari proposal ini memiliki "Anda harus menentukan rootDir
eksplisit " yang agak rumit (Anda harus menulis "rootDir": "."
di setiap tsconfig). Karena kami ingin membalik berbagai perilaku di dunia ini, lebih masuk akal untuk mengatakan bahwa Anda mendapatkan perilaku "proyek" jika Anda memiliki larik referensi dan menjadikannya sebagai hal yang dimatikan, daripada menentukan sekelompok flag yang harus Anda nyatakan secara eksplisit.
Proposal ini akan sejalan dengan bagaimana kami telah menyusun proyek TypeScript kami. Kami telah membagi lagi menjadi unit yang lebih kecil yang masing-masing memiliki tsconfig.json dan dibangun secara independen melalui gulp. Proyek referensi satu sama lain dengan referensi file d.ts.
Di dunia yang ideal, proyek yang direferensikan tidak perlu dibuat sebelumnya. yaitu. TypeScript melakukan "build" dari proyek yang direferensikan dan mempertahankan "d.ts" yang setara dalam memori dalam layanan bahasa. ini akan memungkinkan perubahan yang dibuat dalam proyek "sumber" muncul di proyek "bergantung" tanpa perlu membangun kembali.
Kami membutuhkan sesuatu di tsconfig target yang memberi tahu kami di mana diharapkan file output berada.
Itu hanya benar ketika outDir
digunakan, bukan?
Seperti pada: jika saya memiliki tsconfig yang:
outDir
(tetapi memiliki declaration: true
, tentu saja), maka kita tidak perlu rootDir
, atau references
outDir
, maka Anda perlu references
dan/atau rootDir
(dan declaration: true
) untuk disetelAlasan untuk bertanya adalah bahwa saya kemudian dapat mengaktifkan 'mode proyek' untuk paket TS apa pun hanya dengan merujuknya, yaitu dalam kendali saya.
Dalam hal ini, akan lebih baik jika juga bekerja segera setelah menemukan file .d.ts yang dicari (yaitu tidak akan mengeluh jika tidak ada file .ts, atau file tsconfig). Karena itu akan memungkinkan kasus lain untuk 'mengganti' versi NPM (yang mungkin hanya memiliki file .d.ts) dengan versi sumbernya bila diperlukan.
Misalnya, pertimbangkan paket NPM MyApp dan SomeLib.
SomeLib dapat memiliki tsconfig: declaration: true
.
Repositori seperti:
package.json
tsconfig.json
index.ts
sub.ts
Dikompilasi, ini menjadi:
package.json
tsconfig.json
index.ts
index.d.ts
index.js
sub.ts
sub.d.ts
sub.js
Struktur ini memungkinkan misalnya
// somewhere in MyApp
import something from "SomeLib/sub";
Dalam paket NPM yang diterbitkan, saat ini saya selalu harus menghapus file .ts, jika tidak, semua sumber akan dikompilasi ulang oleh TS jika MyApp menggunakan SomeLib:
Jadi, pada NPM, ini menjadi:
package.json
index.d.ts
index.js
sub.d.ts
sub.js
Sekarang, jika saya memasukkan references: ["SomeLib"]
di tsconfig MyApp, akan lebih baik jika berfungsi 'apa adanya' untuk versi NPM dan versi sumber SomeLib , yaitu bahwa ia tidak akan mengeluh tentang misalnya hilang tsconfig, selama itu menemukan sub.d.ts
di tempat yang tepat.
Terkait, tetapi pertanyaan yang berbeda:
Saya sekarang menyadari, bahwa JIKA penulis SomeLib
menempatkan references
di tsconfig-nya, ini akan memungkinkan untuk menerbitkan paket NPM DENGAN file .ts, di masa mendatang. Tapi kemudian, saya kira TS masih akan selalu mengkompilasi ulang ini ketika paket dependen apa pun tidak secara eksplisit memasukkan references: ["SomeLib"]
di tsconfig mereka.
Atau apakah maksud juga bahwa references
di MyLib akan secara otomatis juga memperkenalkan 'batas proyek' ketika hanya import
'menyimpannya (yaitu bukan references
'ing itu)?
IIRC, salah satu ide awalnya adalah jika sebuah modul misalnya terletak melalui node_modules
, maka file .d.ts
akan lebih disukai daripada file .ts
, tetapi ini kemudian diubah kembali , karena heuristik ("melalui node_modules
") secara umum terlalu bermasalah. Mungkinkah memiliki 'batas proyek' eksplisit akan menyelesaikan ini (misalnya projectRoot: true
, alih-alih atau selain memiliki references
)?
Untuk kasus lerna, saya mengharapkan solusi yang lebih sederhana.
Seluruh kekhawatiran saya adalah bahwa setelah Anda menambahkan referensi menggunakan jalur relatif turun "../xx"
ke file konfigurasi proyek individu, mereka tidak lagi dapat digunakan sebagai modul yang berdiri sendiri - mereka harus berada dalam struktur ruang kerja tertentu.
Menambahkan konsep baru "ruang kerja" tsconfig.json memecahkan masalah ini. Dengan begitu jika Anda misalnya "git clone" paket individu, menginstal dependensinya dengan cara biasa (misalnya menggunakan npm atau yarn) akan membiarkan Anda mengerjakannya secara terpisah, karena dependensi yang dikompilasi akan membawa file definisinya. Jika Anda mengkloning seluruh ruang kerja dan menjalankan perintah untuk memasukkan semua paket, konfigurasi ruang kerja akan memungkinkan Anda menavigasi semua sumber.
Perhatikan bahwa ruang kerja tsconfig.json
juga selaras sempurna dengan ruang kerja Benang package.json
https://yarnpkg.com/lang/en/docs/workspaces/
Saya melakukan sedikit bukti konsep di sini
https://github.com/spion/typescript-workspace-plugin
Cukup tambahkan plugin ke semua file tsconfig.json
dari masing-masing repo
{
"plugins": [{"name": "typescript-workspace-plugin"}]
}
Kemudian di package.json tingkat atas di samping entri "ruang kerja" benang, tambahkan entri "sumber ruang kerja":
{
"workspaces": ["packages/*"],
"workspace-sources": {
"*": ["packages/*/src"]
}
}
Bidang ini bekerja sangat mirip dengan bidang "jalur" di tsconfig.json tetapi hanya memengaruhi layanan bahasa dari masing-masing proyek, mengarahkannya ke sumber paket. Mengembalikan fungsionalitas "pergi ke definisi/ketik" yang tepat dan serupa.
Itu hanya benar ketika outDir digunakan, bukan?
Benar. Kami telah berhipotesis bahwa hampir semua orang dengan proyek besar menggunakan outDir
. Saya akan tertarik untuk mendengar tentang proyek yang tidak
Sekarang, jika saya meletakkan referensi: ["SomeLib"] di tsconfig MyApp, akan lebih baik jika berfungsi 'apa adanya' untuk versi NPM dan versi sumber SomeLib
Penggemar berat, saya sangat menyukai ide ini. Saya perlu memikirkan apakah itu benar-benar diperlukan atau tidak.
Satu peringatan di sini adalah bahwa saya pikir paket penulis perlu baik) mempublikasikan baik ts dan file tsconfig bersama-sama di tempat di mana TS menemukan mereka, atau b) menerbitkan tidak dan hanya memiliki file .d.ts terjangkau. Dalam kasus (a) kami akan mengikuti referensi proyek secara rekursif dan hal yang benar akan terjadi dan dalam (b) kami tidak akan menjelajah ke tempat yang salah.
Atau maksud juga bahwa referensi di MyLib akan secara otomatis juga memperkenalkan 'batas proyek' ketika hanya mengimpornya (yaitu tidak mereferensikannya)?
Berbicara dengan @mhegazy dan kami pikir sebenarnya ada model sederhana tentang bagaimana perilaku referensi proyek: proyek apa pun dengan array references
tidak pernah "melihat" file .ts
luar folder proyek - ini termasuk file di bawah direktori exclude
d. Perubahan ini saja membuat skenario lerna bekerja ("bekerja" yang berarti "referensi modul selalu diselesaikan ke .d.ts") di luar kotak, serta yang lainnya.
Saya perlu melihat model "ruang kerja" lebih banyak.
Itu hanya benar ketika outDir digunakan, bukan?
Benar. Kami telah berhipotesis bahwa hampir semua orang dengan proyek besar menggunakan outDir. Saya akan tertarik untuk mendengar tentang proyek yang tidak
Kami memiliki 67 Proyek TS dalam solusi studio visual yang dikompilasi tanpa outdir
dan postbuild gruntasks untuk membuat struktur direktori keluaran (dan uglify dan postprocessing lainnya).
Sebagian besar proyek memiliki tsconfig.json
"include": [
"../baseProj/Lib/jquery.d.ts",
"../baseProj/baseProj.d.ts"
]
Saya meluangkan waktu untuk membaca proposal referensi, dan mengoreksi - AFAICT lerna dan pengguna ruang kerja benang tidak memerlukan fungsionalitas ruang kerja yang diusulkan di sini:
skipLibCheck
seharusnya membuat dampak kinerja diabaikan, tetapi saya belum memeriksanya.Apa yang tidak kami miliki, dan apa yang disediakan oleh plugin yang saya tulis, adalah cara untuk memuat semua sumber secara bersamaan. Ketika saya perlu membuat perubahan pada dua atau lebih modul secara bersamaan, saya tidak ingin "pergi ke definisi" dan "ke jenis definisi" untuk mengirim saya ke file .d.ts. Saya ingin mengirim saya ke lokasi kode sumber asli, sehingga mungkin saya dapat mengeditnya. Jika tidak, saya hanya akan memuat direktori proyek individu dan symlink node_modules yang dibuat oleh lerna/yarn hanya akan berfungsi.
Hal yang sama untuk kita. Alih-alih Lerna, kami menggunakan Rush untuk menghitung grafik ketergantungan kami, tetapi efeknya sama. Saat kita membangun proyek, tsc
hanyalah salah satu dari banyak tugas yang perlu dijalankan. Opsi kompiler kami dihitung oleh sistem build yang lebih besar, dan kami pindah ke model di mana tsconfig.json bukan file input, melainkan output yang dihasilkan (terutama untuk kepentingan VS Code).
Apa yang tidak kami miliki, dan apa yang disediakan oleh plugin yang saya tulis, adalah cara untuk memuat semua sumber secara bersamaan. Ketika saya perlu membuat perubahan pada dua atau lebih modul secara bersamaan, saya tidak ingin "pergi ke definisi" dan "ke jenis definisi" untuk mengirim saya ke file .d.ts. Saya ingin mengirim saya ke lokasi kode sumber asli, sehingga mungkin saya dapat mengeditnya.
+1 ini akan luar biasa.
Jika kita memimpikan dukungan multi-proyek yang lebih baik, permintaan pertama saya adalah layanan kompiler, seperti cara kerja VS Code IntelliSense. Pembuatan kami akan jauh lebih cepat jika Rush dapat memanggil tsc
100 kali tanpa harus memutar mesin kompiler 100 kali. Kompiler adalah salah satu langkah pembuatan kami yang paling mahal. Dalam monorepo, waktu pembuatan sangat penting.
@iclanton @nickpape-msft @qz2017
Ya silahkan!
Saya pikir salah satu hasil yang paling berguna dari sistem proyek adalah jika
'pergi ke definisi' pergi ke file sumber alih-alih file d.ts dan
'temukan semua referensi' yang dicari melalui pohon referensi proyek.
Agaknya ini juga akan membuka refactoring tipe 'ganti nama global'.
Pada Thu, Nov 9, 2017 at 09:30 Salvatore Previti [email protected]
menulis:
Ya silahkan!
—
Anda menerima ini karena Anda berlangganan utas ini.
Balas email ini secara langsung, lihat di GitHub
https://github.com/Microsoft/TypeScript/issues/3469#issuecomment-343356868 ,
atau matikan utasnya
https://github.com/notifications/unsubscribe-auth/AANX6d19Zz7TCd_GsP7Kzb-9XJAisG6Hks5s07VXgaJpZM4E-oPT
.
Berbicara dengan @mhegazy dan kami pikir sebenarnya ada model sederhana tentang bagaimana perilaku referensi proyek: proyek apa pun dengan array referensi tidak pernah "melihat" file .ts di luar folder proyek - ini termasuk file di bawah direktori yang dikecualikan.
Bagus, dan dalam hal ini, mengapa seseorang harus menentukan referensi spesifik sama sekali?
Tampaknya cukup memiliki flag (seperti projectRoot: true
).
Misalnya, apa perbedaan antara references: ["foo"]
dan hanya references: []
?
Karena jika saya import "foo"
atau import "bar"
, keduanya akan mengabaikan file .ts
.
Jadi, dalam hal ini, proposal menjadi:
Diberikan tsconfig.json ini (TODO bikeshed pada projectRoot
):
{
"extends": "../tsproject.json",
"compilerOptions": {
"projectRoot": true
}
}
Ketika tsc
kemudian perlu menyelesaikan sesuatu di luar folder proyek (termasuk file di bawah direktori yang dikecualikan), itu hanya akan melihat file .d.ts
(sebagai alternatif, mungkin hanya _prefer_ .d.ts
file, dan kembali ke tsconfig
dan/atau .ts
jika hanya melihatnya).
Ini membuat resolusi selama kompilasi cepat dan sederhana.
Ia bekerja untuk referensi monorepo (yaitu import "../foo"
) dan referensi berbasis paket (yaitu import "foo"
).
Ini berfungsi untuk paket NPM dan representasi kode sumbernya.
Dan itu menghilangkan kebutuhan untuk menyelesaikan mesin tsconfig.json
selama kompilasi, meskipun pesan kesalahan jika tidak dapat menemukan .d.ts
akan kurang membantu.
Kedengarannya agak terlalu bagus untuk menjadi kenyataan, jika memang sesederhana ini, jadi saya mungkin mengabaikan sesuatu yang penting :)
Seperti yang juga ditunjukkan oleh orang lain, masih sangat penting bahwa 'IntelliSense' tetap bekerja dengan file .ts.
Jadi, jika permintaan untuk 'go to definition', 'find references' dll dibuat, itu harus menggunakan beberapa pemetaan terbalik untuk menemukan file .ts
sesuai dari file .d.ts
yang digunakannya jauh.
Pemetaan ini dapat dilakukan dengan menggunakan misalnya:
//# sourceURL = ../src/foo.ts
di .d.ts
.d.ts
'digulung' kembali ke .ts
asalnya.js
, dan menggunakan peta sumbernya untuk menemukan `.tsIni memang memperkenalkan topik membangun kembali .d.ts
ketika .ts
itu diubah, tetapi saya tidak yakin itu harus diselesaikan dengan proposal ini. Sebagai contoh, sudah menjadi kasus hari ini bahwa perlu ada beberapa proses untuk membangun kembali file .js
, bahkan dari proyek root itu sendiri. Jadi saya kira akan aman untuk berasumsi bahwa jika itu ada, akan ada juga sesuatu untuk membangun kembali dependensi. Bisa berupa sekumpulan tsc
paralel untuk setiap paket, bisa berupa tsbuild
, bisa berupa IDE pintar dengan compileOnSave
-seperti perilaku, dll.
@pgonzal @michaelaird https://github.com/spion/typescript-workspace-plugin tidak hanya itu - memulihkan pergi ke definisi dan menemukan semua referensi untuk-tsconfig multi-benang / Lerna / etc ruang kerja proyek.
Menarik... Aku ingin tahu apakah kita bisa membuat ini bekerja dengan Rush. Kami akan melihat.
FYI alat sederhana lain yang kami buat sebagai bagian dari upaya ini adalah wsrun
Mirip dengan lerna run
, ia menjalankan perintah untuk semua paket di ruang kerja.
Karena dependensi TypeScript perlu dikompilasi secara berurutan, wsrun mampu menjalankan perintah paket dalam urutan topologi berdasarkan dependensi package.json
. Ini mendukung paralelisme selama pembuatan. Memang tidak paralel secara optimal, tapi itu bisa diperbaiki nanti.
Sekedar catatan, oao adalah alat monorepo lain untuk benang. Baru-baru ini menambahkan dukungan untuk pemesanan perintah 'topologis' juga.
Saya hanya ingin memposting kata "refactoring" di sini karena ini adalah tujuan penting bagi kami, meskipun mungkin bersinggungan dengan proposal saat ini (https://github.com/Microsoft/TypeScript/issues/3469#issuecomment-341317069) dan tidak disebutkan dalam masalah ini sangat sering.
Kasus penggunaan kami adalah monorepo dengan beberapa proyek TS, pada dasarnya dapat direduksi menjadi common-library
ditambah beberapa aplikasi: app1
dan app2
. Saat bekerja di IDE, itu harus diperlakukan sebagai satu proyek, misalnya, rename refactoring harus bekerja di ketiga modul, tetapi app1
dan app2
juga merupakan dua target build yang terpisah. Meskipun saya setuju bahwa build umumnya merupakan masalah yang terpisah, kenyataannya adalah bahwa aplikasi kami cukup kecil dan melakukan sesuatu seperti cd app1 && tsc
akan baik-baik saja bagi kami.
Jika TypeScript muncul dengan cara yang baik untuk mendukung ini, itu akan luar biasa.
Untuk refactoring/referensi lintas proyek monorepo, saya menemukan pengaturan ini berfungsi untuk saya jika Anda bekerja di vscode:
root tsconfig:
"compilerOptions": {
"baseUrl": ".",
// global types are different per project
"types": [],
"paths": {
"lib": ["packages/lib/src"],
"xyz1": ["packages/xyz1/src"],
"xyz2": ["packages/xyz2/src"],
}
},
"include": ["./stub.ts"], // empty file with export {} to stop vscode complaining about no input files
"exclude": ["node_modules"]
paket/xyz1/tsconfig.json
{
"extends": "../../tsconfig",
"compilerOptions": {
"types": ["node"],
},
"include": ["src/**/*"]
}
paket/xyz2/tsconfig.json
{
"extends": "../../tsconfig",
"compilerOptions": {
"types": ["webpack-env"]
},
"include": ["src/**/*"]
}
paket/lib/tsconfig.json
{
"extends": "../../tsconfig",
"compilerOptions": { ... },
"include": ["src/**/*"],
// special file to load referenced projects when inside in lib package, without it they won't be
// visible until you open some file in these projects
"files": ["./references.ts"],
}
paket/lib/tsconfig-build.json
{
"extends": "./tsconfig",
// exclude referenced projects when building
"files": []
}
package/lib/references.ts
import "xyz1";
import "xyz2";
export {};
Anda memerlukan properti main
dalam paket package.json
dan mungkin types
bahkan untuk paket tanpa lib, misalnya:
"main": "src/main.tsx",
"types": "src/main.tsx",
Dengan cara ini memfaktorkan ulang/mengganti nama sesuatu di lib
juga akan memfaktorkan ulang referensi di xyz1
dan xyz2
. Juga proyek dapat memiliki global/target lib yang berbeda dengan cara ini.
Di Gradle, mereka hanya menyebutnya - composite build .
Omong-omong, dapatkah saya memulai jika saya ingin berkontribusi pada kompiler TypeScript? Saya telah mengkloning repo dan itu bukan masalah kecil (saya biasa membaca sumber: angular, ionic, express ketika saya tidak bisa mendapatkannya dari dokumen atau jauh dari internet ...) Saya sangat membutuhkan bantuan dari satu untuk menunjukkan saya jalan untuk pergi, silakan.
Terima kasih!
Masa depan cerah untuk TypeScript.
Saya memiliki prototipe yang ingin saya coba jika mereka menggunakan jalur modul relatif. Ada contoh repo di https://github.com/RyanCavanaugh/project-references-demo yang menguraikan skenario dasar dan menunjukkan cara kerjanya.
Untuk mencoba secara lokal:
git clone https://github.com/RyanCavanaugh/TypeScript
git checkout pr-lkg
npm install
npm run build
npm link
Kemudian di folder Anda yang lain:
npm link typescript
Saya akan menjaga tag pr-lkg
menunjuk pada komit kerja terbaru saat semuanya berubah. Selanjutnya tentang todos saya:
@RyanCavanaugh Saya tidak dapat benar-benar membangunnya karena kesalahan seperti kehilangan modul del
atau Error: Cannot find module 'C:\github\TypeScript\built\local\tsc.js'
(mungkin jalur lokal Anda?) tetapi secara keseluruhan, strukturnya tampak hebat.
Apakah ini tsc
-saja atau akankah ini juga memperhitungkan refactoring seluruh proyek di VSCode dengan server bahasa?
...juga tag pr-lkg
tidak ada.
Tag ada di sana (bukan cabang). Lihat https://github.com/RyanCavanaugh/TypeScript/tree/pr-lkg
references
di tsconfig.json
adalah keikutsertaan per-dependensi, bukankah lebih masuk akal untuk diterapkan pada semua yang diselesaikan di luar rootDir
?
Saya membayangkan sesuatu seperti properti sandbox
yang bisa terlihat seperti:
# tsconfig.json
{
"compilerOptions": {
"outDir": "lib",
"sandbox": "."
},
"include": ["src/index.ts"]
}
Sandbox juga akan menyetel rootDir
ke nilai yang sama. Alih-alih secara eksplisit memberikan jalur ke direktori yang berisi tsconfig.json
, resolusi modul normal akan diterapkan, dan Anda dapat mencari pohon FS untuk menemukan tsconfig.json
secara otomatis.
# package.json
{
"name": "animals",
"module": "src",
"typings": "lib",
"dependencies": {
"core": "*"
}
}
Cara ini:
references
dan dependencies
).@RyanCavanaugh , sejauh yang saya mengerti, saya hanya dapat bekerja secara lokal dengan perubahan ini dan saya tidak akan dapat mengirim proyek tersebut untuk pengujian, misalnya, di travis-ci.org. Benar?
Catatan dari pertemuan hari ini dengan @billti / @mhegazy
Sidebar: Ganti nama ini tidak berfungsi hari ini
function f() {
if (Math.random() > 0.5) {
return { foo: 10 };
} else {
return { foo: 20 };
}
// rename foo here doesn't rename *both* instances in the function body
f().foo;
Terima kasih Ryan, Mohamed, dan Bill. Membuat skenario Find References/Rename bekerja di seluruh proyek adalah salah satu kasus penggunaan inti yang ada dalam pikiran saya ketika saya mengajukan keluhan awal tentang TypeScript yang tidak mendukung proyek berukuran sedang. Proyek berukuran sedang bersifat modular tetapi tidak besar. Proposal dan pekerjaan yang saya lihat di sini sejauh ini terasa lebih seperti permainan skalabilitas. Ini sangat penting untuk kesehatan TypeScript jangka panjang, tetapi sebagian besar bermanfaat untuk proyek besar, bukan menengah. Hal-hal yang saya dengar dalam komentar dari Ryan ini terdengar lebih sejalan dengan apa yang dibutuhkan untuk meningkatkan ergonomi pengembangan proyek berukuran sedang di TypeScript.
Seperti biasa, terima kasih banyak kepada seluruh tim TypeScript atas upaya Anda! Anda melakukan pekerjaan yang luar biasa.
Ada trik dengan ruang kerja lerna/benang yang akan membuat hidup Anda lebih mudah.
Arahkan entri main
dan types
di package.json Anda dari subproyek ke file src/index. ts , dan skenario Temukan Referensi/Ganti Nama akan berfungsi.
Dan Anda akan dapat mengkompilasi seluruh proyek Anda dengan menjalankan satu tsc.
Anda dapat melakukannya untuk beberapa paket Anda, Anda dapat melakukannya untuk semua. panggilanmu.
Ada beberapa kelemahan dan jebakan (Jika Anda memiliki augmentasi dalam satu paket, atau mengimpor simbol global apa pun, itu akan mencemari seluruh program Anda), tetapi secara umum itu bekerja dengan sangat baik.
Saat Anda ingin mempublikasikan ke NPM, Anda cukup mengatur main & types ke nilai yang sesuai (sebagai bagian dari build Anda, atau lebih)
Dengan pengaturan di atas, saya mendapatkan kurang lebih semua fitur yang diharapkan
inilah trik dengan ruang kerja lerna/benang yang akan membuat hidup Anda lebih mudah.
Arahkan entri main dan types di package.json Anda dari sub proyek ke file src/index.ts Anda, dan skenario Find References/Rename akan bekerja.
Dalam pengalaman saya, masalah dengan pengaturan itu adalah TypeScript akan mulai memperlakukan file ts dari paket _external_ seolah-olah itu adalah _sumber_ dari paket yang membutuhkannya, bukan sebagai perpustakaan eksternal. Hal ini menyebabkan sejumlah masalah.
Paket eksternal dikompilasi beberapa kali, setiap kali menggunakan tsconfig dari paket _requiring_. Jika paket yang membutuhkan memiliki tsconfig yang berbeda (misalnya lib yang berbeda), hal ini dapat menyebabkan kesalahan kompilasi palsu muncul pada paket yang diperlukan hingga paket tersebut dikompilasi lagi.
Paket yang diperlukan juga dikompilasi lebih lambat karena menyertakan lebih banyak file daripada yang diperlukan.
rootDir
dari semua paket menjadi direktori tingkat atas, berpotensi memungkinkan penyertaan langsung file TS apa pun dari paket apa pun, alih-alih hanya menyertakan dari index
. Jika pengembang tidak berhati-hati, mereka dapat melewati API paket yang diperlukan. Juga, jika proses pembuatannya tidak kuat, paket yang diperlukan mungkin akan berisi kode duplikat dari paket yang diperlukan yang dimaksudkan untuk menjadi eksternal.
Dalam proyek kami, kami telah mengesampingkan tergantung pada file TS karena kekurangannya. Semua dependensi antar-paket ada di file index.d.ts , jadi kompiler memperlakukannya sebagai eksternal dan semuanya baik-baik saja.
Tentu saja tergantung pada .d.ts
memiliki masalah memerlukan pembangunan multi-langkah (tidak mungkin out-of-the-box dengan alat seperti webpack) dan masalah pengalaman IDE yang buruk (mengganti nama, referensi tidak melintasi batas paket ).
Saya setuju dengan beberapa sentimen lain - TypeScript adalah kompiler, bukan sistem build. Kami membutuhkan alat kami untuk mendukung pembangunan multi proyek yang lebih baik. Saya tahu ada beberapa opsi di komunitas yang mulai melakukan ini. Sebagai contoh, C# memiliki compiler bernama Roslyn dan alat build bernama MSBuild.
Diskusi hari ini dengan @mhegazy tentang cara membuat rename bekerja dengan sedikit rasa sakit dan praktis.
Kasus terburuk yang tidak merosot untuk penggantian nama terlihat seperti ini:
// alpha.ts
const v = { a: 1 };
export function f() { return v; }
export function g() { return v; }
// alpha.d.ts (generated)
export function f(): { a: number };
export function g(): { a: number };
// beta.ts (in another project)
import { f } from '../etc/alpha';
f().a;
// gamma.ts (in yet another project)
import { g } from '../etc/alpha';
g().a;
Pengamatan utama adalah bahwa tidak mungkin untuk mengetahui bahwa mengganti nama f().a
harus mengubah nama g().a
kecuali Anda dapat melihat alpha.ts
untuk menghubungkan keduanya.
Sketsa kasar rencana implementasi:
@RyanCavanaugh akan pergi ke definisi/menemukan semua referensi akan bekerja dengan model ini?
Catatan dari diskusi sebelumnya dengan Anders dan Mohamed seputar sejumlah besar pertanyaan terbuka
prepend
juga berlaku untuk .d.ts
? Ya@internal
di cabang dogfood? Kita perlu menyimpan deklarasi internal di file .d.ts lokal tetapi tidak ingin mereka muncul di versi keluaran--stripInternal
remove-internal
(selesai)@internal
@types
?noEmitOnError
wajib? Ya.referenceTarget
-> composable
tsbuild
atau yang setara dapat memeriksa untuk melihat kepatuhan mereka terhadap persyaratan yang tidak relevan dengan hulu composable
{ path: "../blah", circular: true }
jika Anda ingin melakukan iniVaria
Aku sudah kalah. Saya kebanyakan hanya ingin menjaga interpretasi peta sumber dari kompiler (tanggung jawab terpisah untuk alat terpisah) tetapi ketika Anda pergi, saya tetap bekerja untuk menambahkannya (karena tampaknya mulus masuk ke def diinginkan).
@RyanCavanaugh
Haruskah mengganti nama/menemukan semua referensi berfungsi di seluruh proyek yang direferensikan setelah menggabungkan #23944 ? Juga haruskah kita menggunakan composite: true
dan projectReferences: []
jika hanya layanan bahasa (tetapi bukan itu) yang diperlukan?
Haruskah mengganti nama/menemukan semua referensi berfungsi di seluruh proyek yang direferensikan setelah menggabungkan #23944 ?
belum. tapi kami sedang mengerjakan ini selanjutnya.
Juga haruskah kita menggunakan composite: true dan projectReferences: [] jika hanya layanan bahasa (tetapi bukan itu) yang diperlukan?
tidak yakin saya mengerti pertanyaannya .. apa maksud Anda "layanan bahasa" dan bukan "membangun"?
tidak yakin saya mengerti pertanyaannya .. apa maksud Anda "layanan bahasa" dan bukan "membangun"?
Saya hanya tertarik pada dukungan editor (ganti nama/temukan semua referensi/dll...) di beberapa proyek di monorepo, bukan pada alat build baru (alias build mode
) (#22997) karena saya menggunakan babel untuk kompilasi saya.
Itu hanya harus bekerja. build adalah fitur opt-in, Anda tidak perlu menggunakannya jika Anda tidak ingin.. mirip dengan bagaimana tsc
tidak diperlukan untuk pengalaman layanan bahasa Anda di VSCode misalnya.
Anda mungkin perlu membangun dengan deklarasi dan peta deklarasi, untuk menghasilkan metadata yang diperlukan agar referensi lintas proyek berfungsi.
Saya tidak yakin apakah saya memahami semua aspek proposal dengan benar, tetapi apakah mungkin untuk tidak meminta proyek individu merujuk orang lain melalui jalur, tetapi dengan nama? Proyek ruang kerja harus memiliki cara untuk menentukan setiap jalur proyek, mirip dengan ruang kerja benang melalui gumpalan, atau mungkin dengan mencantumkan setiap nama proyek individu:
Pada dasarnya, alih-alih:
"dependencies": [
"../common",
"../util"
],
Bisakah kita memiliki?
"dependencies": [
"common",
"util"
],
dan memiliki ruang kerja tsconfig.json
"workspace": {
"common": "packages/common",
"util": "packages/util"
}
Atau lebih baik lagi, sintaks jalur:
"workspace": {
"*":"packages/*"
}
Manfaat:
Atau paling tidak, bisakah kita memiliki nama non-jalur (yang tidak dimulai dengan './' atau '../') dicadangkan untuk penggunaan di masa mendatang...
Saya tidak yakin seberapa besar hubungannya, tetapi Benang 1.7 memperkenalkan konsep "ruang kerja terfokus" baru-baru ini, lihat posting blog ini .
Apakah ada orang di sini cukup akrab dengan kedua ruang kerja dan pekerjaan @RyanCavanaugh melakukan sekitar naskah modus referensi proyek / build untuk mungkin menjatuhkan komentar menjelaskan jika mereka berhubungan sama sekali? Perasaan saya adalah bahwa _somewhere_ antara ruang kerja Benang (npm akan mendapatkannya juga tahun ini) dan versi TypeScript yang akan datang merupakan dukungan yang baik untuk monorepo dengan banyak proyek dan perpustakaan bersama. (Kami merasakan sakitnya, saat ini.)
Saya sangat ingin mendapatkan pembaruan tentang kemajuan fitur ini. Kami berencana untuk memindahkan Aurelia vNext ke monorepo sekitar bulan depan. Versi baru kami adalah 100% TypeScript dan kami ingin menggunakan sistem proyek TS resmi daripada Lerna, jika kami bisa. Kami juga senang menjadi pengguna awal/penguji fitur baru :)
Dukungan inti dan goto def menggunakan dukungan tsc --b
untuk dukungan build sudah ada dan terikat untuk TS 3.0. Basis kode TypeScript telah pindah untuk menggunakannya. Kami sedang menguji dukungan ini menggunakan repo TypeScript.
Apa yang masih perlu dilakukan saat ini: 1. get find all references/rename to work on multi project scenarios. 2. menangani pembaruan file .d.ts di latar belakang editor, dan 3. dukungan --watch
untuk skenario multi-proyek. juga banyak dan banyak pengujian.
Tiket ini telah dia pesan selama 3 tahun. Masih 3/6 item yang beredar?
@claudeduguay Ini adalah perubahan mendasar untuk proyek apa yang didukung TypeScript, waktunya untuk merayakan bukan? Saya sangat senang untuk ini!
@mhegazy Ini adalah berita bagus. Saya sangat senang mendengar bahwa tim TS juga melakukan dogfood pada proyek mereka sendiri. Menunggu beberapa hal terakhir selesai dan menjadikan ini sebagai opsi untuk Aurelia :) Segera setelah ada beberapa dokumentasi tentang pengaturannya, kami akan memindahkan vNext kami ke sistem proyek baru. Tidak sabar!
@mhegazy Bisakah Anda menjelaskan bagaimana semua ini akan bekerja dengan file dan proyek package.json berdasarkan modul ES2015? Sebagai contoh, di Aurelia vNext, kita memiliki paket seperti @aurelia/kernel
, @aurelia/runtime
, @aurelia/jit
, dll. Itulah nama-nama modul yang akan digunakan di import
pernyataan di seluruh berbagai proyek. Bagaimana kompiler TS memahami bahwa nama modul ini dipetakan ke berbagai folder yang direferensikan? Apakah akan mengambil file package.json yang ditempatkan di setiap folder yang direferensikan? Bagaimana ini akan berbeda dari Lerna atau Yarn Workspaces? Pandangan awal saya ke tautan di atas membuat saya berpikir saya perlu menggunakan proyek TS (build) dalam kombinasi dengan Lerna (dep linking dan penerbitan) untuk mendapatkan solusi yang berfungsi, tetapi saya tidak melihat bagaimana TS akan membangun dengan benar jika tidak dapat berintegrasi dengan package.json dan node_modules. Sumber repo TS sangat berbeda dari proyek Lerna rata-rata Anda (tidak ada yang benar-benar seperti itu), jadi saya mulai bertanya-tanya apakah ini akan dapat memenuhi kebutuhan kita. Informasi lebih lanjut yang dapat Anda berikan, dan khususnya. pengaturan solusi demo yang berfungsi mirip dengan yang saya jelaskan di sini, akan sangat membantu. Terima kasih!
Saya berbagi pertanyaan yang sama dengan @EisenbergEffect. Secara khusus saya juga berharap ini akan bekerja dengan baik dengan lerna
-managed monorepo.
Dua skenario monorepo untuk dipertimbangkan
Mari kita mulai dengan pengaturan di mana Anda telah menghubungkan semuanya dengan lerna:
/packages
/a
/node_modules
/b -> symlink to b with package.json "types" pointing to dist/index.d.ts
/b
/dist
/index.d.ts -> built output of entry point declaration file
Hal utama yang kita inginkan terjadi di sini adalah untuk membangun kembali b
kita bangun a
jika a
sudah kedaluwarsa. Jadi kami akan menambahkan "references": [ { "path": "../b" } ]
ke a
's tsconfig.json
dan menjalankan tsc --build
di a
untuk mendapatkan build upstream yang benar dari b
. Di dunia ini, referensi proyek hanya berfungsi sebagai representasi dari grafik build dan memungkinkan untuk membangun kembali peningkatan yang lebih cerdas. Idealnya lerna dan TS dapat bekerja sama di sini dan mencerminkan dependensi package.json
menjadi tsconfig.json
jika sesuai.
Skenario lain (mungkin kurang umum) adalah jika Anda tidak menghubungkan tetapi masih ingin "bertindak seolah-olah" Anda sedang mengerjakan serangkaian paket langsung. Anda dapat melakukannya hari ini dengan beberapa pemetaan jalur yang cukup membosankan, dan beberapa orang melakukannya. Referensi proyek di sini juga akan membantu dengan pemesanan build, tetapi akan sangat diinginkan untuk memiliki dukungan untuk properti di file tsconfig referensi untuk secara otomatis membuat pemetaan jalur kapan pun itu direferensikan; misalnya jika Anda punya
{
"compilerOptions": { "outDir": "bin" },
"package": "@RyanCavanaugh/coolstuff"
}
kemudian menambahkan "references": [{ "path": "../cool" }]
akan secara otomatis menambahkan pemetaan jalur dari @RyanCavanaugh/coolstuff
-> ../cool/bin/
. Kami belum menambahkan ini tetapi dapat melihat ke dalamnya jika ternyata menjadi skenario yang lebih umum.
Idealnya lerna dan TS dapat bekerja sama di sini dan mencerminkan dependensi package.json ke tsconfig.json jika sesuai
Daripada mengandalkan alat eksternal, kami dapat memilih untuk membaca package.json
(asalkan ada di samping tsconfig Anda) sebagai referensi potensial jika composite: true
disetel (periksa untuk melihat apakah setiap paket yang diselesaikan memiliki tsconfig.json
, jika ada, anggap itu sebagai simpul proyek yang dapat dibangun dan berulang). Karena semuanya terhubung ke tempatnya, kita bahkan tidak perlu mengubah resolusi (banyak? ada?) untuk menangani ruang kerja. Lerna tidak benar-benar mengatur hal-hal khusus ts (atau khusus bangunan) seperti afaik, itu hanya menghubungkan semuanya ke tempatnya dan mengelola pembuatan versi. Ini akan menjadi optimasi atas apa yang kita lakukan hari ini, yaitu memuat file ts
(karena kita lebih memilih itu daripada deklarasi) dan mengkompilasi ulang semuanya terlepas dari kedaluwarsa.
@RyanCavanaugh Ini terdengar sangat menarik. Adakah ide apakah itu akan bekerja dengan strategi symlinking Rush ? Singkatnya, Rush membuat paket sintetis common/temp/package.json yang berisi superset dari semua dependensi untuk semua paket dalam repo. Kemudian kami menggunakan pnpm untuk melakukan operasi instalasi tunggal untuk paket sintetis ini. (PNPM menggunakan symlink untuk membuat grafik berarah-asiklik alih-alih struktur pohon NPM, yang menghilangkan contoh perpustakaan yang diduplikasi). Kemudian Rush membuat folder node_modules untuk setiap proyek di repo, terbuat dari symlink yang menunjuk ke folder yang sesuai di bawah common/temp . Hasilnya sepenuhnya kompatibel dengan TypeScript dan algoritma resolusi NodeJS standar. Ini sangat cepat karena ada satu file shrinkwrap dan satu persamaan versi untuk seluruh repo, sambil tetap mengizinkan setiap paket untuk menentukan dependensinya sendiri.
Kami tidak memasukkan sesuatu yang istimewa di tsconfig.json
untuk model ini. Jika beberapa konfigurasi TypeScript khusus diperlukan untuk fitur goto-definition, kami idealnya ingin membuat otomatis selama instalasi daripada menyimpannya di Git.
@pgonzal Terima kasih atas tautan ke Rush! Saya belum melihat itu. Aku akan memeriksanya malam ini.
@RyanCavanaugh Terima kasih atas penjelasannya. Skenario pertama Anda dengan lerna paling dekat dengan apa yang kita miliki. Inilah repo UX kami dengan TS dan lerna sebagai contoh dari sesuatu yang kami ingin gunakan dukungan proyek baru di https://github.com/aurelia/ux
@weswigham Kedengarannya seperti yang Anda gambarkan akan sesuai dengan skenario kami juga. Contoh repo di atas.
Sekedar catatan bahwa dalam kasus ruang kerja benang, modul tidak disinkronkan di setiap direktori paket individual, melainkan disinkronkan di ruang kerja tingkat atas node_modules
.
Itulah mengapa saya berpikir bahwa referensi yang tidak dimulai dengan titik ('./' atau '../') harus dicadangkan untuk masa mendatang. Mudah-mudahan itu akan berakhir menjadi "referensi bernama", ditangani melalui strategi resolusi modul aktif alih-alih diperlakukan sebagai jalur relatif.
@spion kami hanya akan menggunakan nama properti selain path
untuk itu jika diperlukan (misalnya "references": [ { "module": "@foo/baz" } ]
); Saya tidak ingin menimbulkan kebingungan dimana "bar"
dan "./bar"
arti yang sama di files
tetapi hal yang berbeda di references
Dokumen/posting blog sedang dalam proses di bawah (akan mengedit ini berdasarkan umpan balik)
Saya akan mendorong siapa pun yang mengikuti utas ini untuk mencobanya. Saya sedang mengerjakan skenario monorepo sekarang untuk memperbaiki bug/fitur terakhir di sana dan akan segera mendapatkan panduan tentangnya
Referensi proyek adalah fitur baru di TypeScript 3.0 yang memungkinkan Anda untuk menyusun program TypeScript Anda menjadi bagian yang lebih kecil.
Dengan melakukan ini, Anda dapat sangat meningkatkan waktu pembuatan, menerapkan pemisahan logis antar komponen, dan mengatur kode Anda dengan cara baru dan lebih baik.
Kami juga memperkenalkan mode baru untuk tsc
, flag --build
, yang bekerja bersama dengan referensi proyek untuk memungkinkan pembuatan TypeScript yang lebih cepat.
Mari kita lihat program yang cukup normal dan lihat bagaimana referensi proyek dapat membantu kita mengaturnya dengan lebih baik.
Bayangkan Anda memiliki proyek dengan dua modul, converter
dan units
, dan file pengujian yang sesuai untuk masing-masing:
/src/converter.ts
/src/units.ts
/test/converter-tests.ts
/test/units-tests.ts
/tsconfig.json
File pengujian mengimpor file implementasi dan melakukan beberapa pengujian:
// converter-tests.ts
import * as converter from "../converter";
assert.areEqual(converter.celsiusToFahrenheit(0), 32);
Sebelumnya, struktur ini agak canggung untuk digunakan jika Anda menggunakan satu file tsconfig:
test
dan src
bersamaan tanpa src
muncul di nama folder keluaran, yang mungkin tidak Anda inginkanAnda dapat menggunakan beberapa file tsconfig untuk menyelesaikan beberapa masalah tersebut, tetapi yang baru akan muncul:
tsc
dua kalitsc
dua kali menimbulkan lebih banyak overhead waktu startuptsc -w
tidak dapat dijalankan pada beberapa file konfigurasi sekaligusReferensi proyek dapat menyelesaikan semua masalah ini dan banyak lagi.
File tsconfig.json
memiliki properti tingkat atas baru, references
. Ini adalah array objek yang menentukan proyek untuk referensi:
{
"compilerOptions": {
// The usual
},
"references": [
{ "path": "../src" }
]
}
Properti path
dari setiap referensi dapat menunjuk ke direktori yang berisi file tsconfig.json
, atau ke file konfigurasi itu sendiri (yang mungkin memiliki nama apa pun).
Saat Anda mereferensikan sebuah proyek, hal-hal baru terjadi:
.d.ts
)outFile
, deklarasi file .d.ts
file output akan terlihat dalam proyek iniDengan memisahkan menjadi beberapa proyek, Anda dapat sangat meningkatkan kecepatan pengecekan dan kompilasi, mengurangi penggunaan memori saat menggunakan editor, dan meningkatkan penegakan pengelompokan logis program Anda.
composite
Proyek yang direferensikan harus mengaktifkan setelan composite
.
Pengaturan ini diperlukan untuk memastikan TypeScript dapat dengan cepat menentukan di mana menemukan output dari proyek yang direferensikan.
Mengaktifkan flag composite
mengubah beberapa hal:
rootDir
, jika tidak disetel secara eksplisit, default ke direktori yang berisi file tsconfig
include
atau terdaftar dalam larik files
. Jika batasan ini dilanggar, tsc
akan memberi tahu Anda file mana yang tidak ditentukandeclaration
harus diaktifkandeclarationMaps
Kami juga telah menambahkan dukungan untuk peta sumber deklarasi .
Jika Anda mengaktifkan --declarationMap
, Anda akan dapat menggunakan fitur editor seperti "Buka Definisi" dan Ganti Nama untuk menavigasi dan mengedit kode secara transparan melintasi batas proyek di editor yang didukung.
prepend
dengan outFile
Anda juga dapat mengaktifkan prepending output dari dependensi menggunakan opsi prepend
dalam referensi:
"references": [
{ "path": "../utils", "prepend": true }
]
Memulai proyek akan mencakup keluaran proyek di atas keluaran proyek saat ini.
Ini berfungsi untuk file .js
dan file .d.ts
, dan file peta sumber juga akan dipancarkan dengan benar.
tsc
hanya akan pernah menggunakan file yang ada di disk untuk melakukan proses ini, jadi dimungkinkan untuk membuat proyek di mana file output yang benar tidak dapat dihasilkan karena beberapa output proyek akan ada lebih dari sekali dalam file yang dihasilkan .
Sebagai contoh:
^ ^
/ \
B C
^ ^
\ /
D
Dalam situasi ini, penting untuk tidak menambahkan di setiap referensi, karena Anda akan mendapatkan dua salinan A
dalam output D
- ini dapat menyebabkan hasil yang tidak diharapkan.
Referensi proyek memiliki beberapa trade-off yang harus Anda ketahui.
Karena proyek dependen menggunakan file .d.ts
yang dibuat dari dependensinya, Anda harus memeriksa keluaran build tertentu atau membangun proyek setelah mengkloningnya sebelum Anda dapat menavigasi proyek di editor tanpa melihat yang palsu kesalahan.
Kami sedang mengerjakan proses pembuatan .d.ts di balik layar yang seharusnya dapat mengurangi hal ini, tetapi untuk saat ini kami menyarankan untuk memberi tahu pengembang bahwa mereka harus membangun setelah kloning.
Selain itu, untuk menjaga kompatibilitas dengan alur kerja build yang ada, tsc
tidak akan secara otomatis membangun dependensi kecuali dipanggil dengan sakelar --build
.
Mari pelajari lebih lanjut tentang --build
.
Fitur yang telah lama ditunggu-tunggu adalah build inkremental cerdas untuk proyek TypeScript.
Di 3.0 Anda dapat menggunakan flag --build
dengan tsc
.
Ini secara efektif merupakan titik masuk baru untuk tsc
yang berperilaku lebih seperti orkestra build daripada kompiler sederhana.
Menjalankan tsc --build
( singkatnya tsc -b
) akan melakukan hal berikut:
Anda dapat memberikan tsc -b
dengan beberapa jalur file konfigurasi (misalnya tsc -b src test
).
Sama seperti tsc -p
, menentukan nama file konfigurasi itu sendiri tidak perlu jika bernama tsconfig.json
.
tsc -b
Baris PerintahAnda dapat menentukan sejumlah file konfigurasi:
> tsc -b # Build the tsconfig.json in the current directory
> tsc -b src # Build src/tsconfig.json
> tsc -b foo/release.tsconfig.json bar # Build foo/release.tsconfig.json and bar/tsconfig.json
Jangan khawatir tentang memesan file yang Anda berikan pada baris perintah - tsc
akan memesan ulang jika diperlukan sehingga dependensi selalu dibangun terlebih dahulu.
Ada juga beberapa flag khusus untuk tsc -b
:
--verbose
: Mencetak log verbose untuk menjelaskan apa yang terjadi (dapat digabungkan dengan flag lain)--dry
: Menunjukkan apa yang akan dilakukan tetapi tidak benar-benar membangun apa pun--clean
: Menghapus output dari proyek yang ditentukan (dapat digabungkan dengan --dry
)--force
: Bertindak seolah-olah semua proyek sudah ketinggalan zaman--watch
: Mode tontonan (tidak boleh digabungkan dengan bendera apa pun kecuali --verbose
)Biasanya, tsc
akan menghasilkan output ( .js
dan .d.ts
) dengan adanya sintaks atau kesalahan ketik, kecuali noEmitOnError
aktif.
Melakukan ini dalam sistem pembangunan inkremental akan sangat buruk - jika salah satu dependensi Anda yang kedaluwarsa mengalami kesalahan baru, Anda hanya akan melihatnya sekali karena pembangunan berikutnya akan melewatkan pembangunan proyek yang sekarang diperbarui.
Untuk alasan ini, tsc -b
secara efektif bertindak seolah-olah noEmitOnError
diaktifkan untuk semua proyek.
Jika Anda memeriksa keluaran build apa pun ( .js
, .d.ts
, .d.ts.map
, dll.), Anda mungkin perlu menjalankan build --force
setelah kontrol sumber tertentu operasi tergantung pada apakah alat kontrol sumber Anda mempertahankan peta waktu antara salinan lokal dan salinan jarak jauh.
Jika Anda memiliki proyek msbuild, Anda dapat mengaktifkan mode build dengan menambahkan
<TypeScriptBuildMode>true</TypeScriptBuildMode>
ke file proj Anda. Ini akan memungkinkan pembuatan inkremental otomatis serta pembersihan.
Perhatikan bahwa seperti halnya tsconfig.json
/ -p
, properti proyek TypeScript yang ada tidak akan dihormati - semua pengaturan harus dikelola menggunakan file tsconfig Anda.
Beberapa tim telah menyiapkan alur kerja berbasis msbuild di mana file tsconfig memiliki urutan grafik implisit yang sama dengan proyek terkelola yang dipasangkan dengan mereka.
Jika solusi Anda seperti ini, Anda dapat terus menggunakan msbuild
dengan tsc -p
bersama dengan referensi proyek; ini sepenuhnya dapat dioperasikan.
Dengan lebih banyak file tsconfig.json
, Anda biasanya ingin menggunakan warisan file Konfigurasi untuk memusatkan opsi kompiler umum Anda.
Dengan cara ini Anda dapat mengubah pengaturan dalam satu file daripada harus mengedit banyak file.
Praktik baik lainnya adalah memiliki file tsconfig.json
"solusi" yang hanya memiliki references
untuk semua proyek simpul daun Anda.
Ini menyajikan titik masuk sederhana; misalnya dalam repo TypeScript kita cukup menjalankan tsc -b src
untuk membangun semua titik akhir karena kita mencantumkan semua subproyek di src/tsconfig.json
Perhatikan bahwa mulai dari 3.0, tidak ada lagi kesalahan untuk memiliki array files
kosong jika Anda memiliki setidaknya satu reference
dalam file tsconfig.json
.
Anda dapat melihat pola ini di repo TypeScript - lihat src/tsconfig_base.json
, src/tsconfig.json
, dan src/tsc/tsconfig.json
sebagai contoh utama.
Secara umum, tidak banyak yang diperlukan untuk mentransisikan repo menggunakan modul relatif.
Cukup tempatkan file tsconfig.json
di setiap subdirektori dari folder induk yang diberikan, dan tambahkan reference
s ke file konfigurasi ini agar sesuai dengan lapisan program yang diinginkan.
Anda perlu menyetel outDir
ke subfolder eksplisit dari folder output, atau menyetel rootDir
ke root umum semua folder proyek.
Tata letak untuk kompilasi menggunakan outFile
lebih fleksibel karena jalur relatif tidak terlalu penting.
Satu hal yang perlu diingat adalah bahwa Anda biasanya tidak ingin menggunakan prepend
hingga proyek "terakhir" - ini akan meningkatkan waktu pembuatan dan mengurangi jumlah I/O yang dibutuhkan dalam setiap bangunan.
Repo TypeScript sendiri adalah referensi yang bagus di sini - kami memiliki beberapa proyek "perpustakaan" dan beberapa proyek "titik akhir"; proyek "titik akhir" disimpan sekecil mungkin dan hanya menarik perpustakaan yang mereka butuhkan.
TODO: Eksperimen lebih banyak dan cari tahu ini. Rush dan Lerna tampaknya memiliki model berbeda yang menyiratkan hal berbeda di pihak kami
Juga mencari umpan balik di #25164
@RyanCavanaugh Tulisan yang sangat bagus, dan fitur luar biasa, akan sangat menyenangkan untuk dicoba, khususnya. setelah saya menghabiskan berhari-hari mengatur proyek besar kami menjadi sub-proyek dengan referensi file konfigurasi.
Saya punya beberapa catatan:
gulp watch
dan tsc -b -w
secara paralel?@vvs a monorepo adalah kumpulan paket NPM yang biasanya dikelola oleh alat seperti Rush atau Lerna
Jika Anda menggunakan gulp, Anda ingin menggunakan loader yang memahami referensi proyek secara asli untuk mendapatkan pengalaman terbaik. @rbuckton telah melakukan beberapa pekerjaan di sini karena kami memiliki beberapa pengembang yang menggunakan gulpfile secara internal; mungkin dia bisa mempertimbangkan seperti apa pola yang bagus di sana
@RyanCavanaugh Ini terlihat bagus. Saya sangat tertarik dengan bimbingan Lerna :)
@RyanCavanaugh ini tampak hebat, saat ini saya sedang berusaha mencobanya dengan lerna monorepo kami.
Satu-satunya hal yang tidak jelas bagi saya dalam tulisan Anda adalah opsi prepend
. Saya tidak begitu mengerti masalah apa yang ditanganinya, dalam situasi apa Anda ingin menggunakannya, dan apa yang terjadi jika Anda tidak menggunakannya.
Ini luar biasa! Saya bekerja pada ts-loader dan proyek terkait. Apakah perubahan mungkin diperlukan untuk mendukung ini dalam proyek yang menggunakan LanguageServiceHost
/ WatchHost
TypeScript?
(Lihat https://github.com/TypeStrong/ts-loader/blob/master/src/servicesHost.ts untuk contoh dari apa yang saya maksud.)
Jika demikian, semua bimbingan / PR diterima dengan senang hati! Bahkan jika Anda ingin ini diuji di dunia webpack, saya akan dengan senang hati membantu mendorong versi ts-loader yang mendukung ini.
Tentu saja jika itu "berhasil" itu lebih baik :senyum:
Kerja bagus!
@yortus @EisenbergEffect Saya telah menyiapkan contoh lerna repo di https://github.com/RyanCavanaugh/learn-a dengan README yang menguraikan langkah-langkah yang saya ambil untuk membuatnya berfungsi.
Jika saya mengerti dengan benar, tsc -b X
tidak akan melakukan apa-apa jika semuanya (X dan semua dependensinya dan dependensi transitif) mutakhir? Ingin tahu apakah itu sesuatu yang bisa kita dapatkan bahkan tanpa flag -b
untuk masing-masing proyek tanpa referensi? (dikurangi dependensi dalam kasus itu, tentu saja)
Ini cukup keren. Saya cenderung menggunakan konfigurasi Lerna seperti ini (untuk memisahkan mono repo berdasarkan fungsi). Saya kira itu akan bekerja dengan baik.
{
"lerna": "2.11.0",
"paket": [
"paket/komponen/ ","paket/perpustakaan/ ",
"paket/kerangka/ ","paket/aplikasi/ ",
"paket/alat/*"
],
"versi": "0.0.0"
}
Jadi ini tersedia di typescript@next
?
Saya akan menguji ini dengan repo ruang kerja benang kami. Kita harus menggunakan nohoist
untuk beberapa modul yang belum mendukung ruang kerja jadi akan menyenangkan untuk melihat bagaimana menanganinya.
@RyanCavanaugh saya mengambil repo untuk uji coba malam ini. Saya membuka masalah pada repo untuk melaporkan beberapa masalah yang saya miliki. Terima kasih lagi untuk menempatkan ini bersama-sama. Saya tidak sabar untuk segera menggunakannya.
Sangat menarik! Saat ini di perusahaan saya, kami menggunakan alat saya sendiri yang disebut mtsc untuk mendukung mode menonton beberapa proyek secara bersamaan. Kami memiliki sekitar 5 proyek yang perlu dikompilasi dan ditonton dalam repo yang sama.
Proyek memiliki konfigurasi yang berbeda seperti; Penargetan ECMA (es5, es6), jenis (node, lelucon, DOM dll), memancarkan (beberapa menggunakan webpack dan beberapa mengkompilasi ke js sendiri). Mereka semua berbagi satu hal, dan itu adalah plugin tslint , sisanya bisa berbeda. Alat saya juga menjalankan tslint setelah kompilasi proyek (per proyek dan berhenti jika proyek dikompilasi ulang sebelum tslint selesai).
Perhatian utama saya dengan proposal saat ini adalah Anda tidak dapat mengatakan proyek mana yang berbagi sumber daya mana. Kami memiliki server dan proyek klien, yang keduanya menggunakan folder utilitas khusus, tetapi kami tidak ingin melihat kesalahan kompilasi dua kali. Tapi itu bisa diperbaiki dengan filter, jadi itu bukan masalah besar :)
Saya telah mencoba mode --build
dengan lerna monorepo kami, yang saat ini terdiri dari 17 paket yang saling bergantung. Butuh beberapa saat untuk membuat semuanya berfungsi, tetapi sekarang semuanya berfungsi, dan mampu membangun secara bertahap adalah peningkatan besar bagi kami.
Saya memang mengalami beberapa masalah yang saya jelaskan di bawah ini. Saya harap ini adalah umpan balik yang berguna untuk tim TS dan dapat membantu orang lain untuk membuat mode --build
bekerja untuk proyek mereka.
tsc --build
Saya mendapat pesan ini untuk setiap paket di setiap build, jadi setiap build menjadi build ulang penuh meskipun tidak ada yang diubah. Saya perhatikan @RyanCavanaugh telah memperbaiki ini di #25281, jadi tidak masalah lagi jika Anda memperbarui ke 20180628
atau lebih baru setiap malam. Masalah berikut mengasumsikan Anda telah memperbarui setidaknya 20180628
setiap malam.
EDIT: dilaporkan di #25337.
Untuk mereproduksi masalah ini, atur repo sampel learn-a
@RyanCavanaugh sesuai instruksinya . Jalankan tsc -b packages --verbose
untuk melihat semuanya dibangun pertama kali. Sekarang ubah baris 1 di pkg1/src/index.ts
menjadi import {} from "./foo";
dan simpan. Jalankan tsc -b packages --verbose
lagi. Build untuk pkg2
dilewati, meskipun pkg1
diubah sedemikian rupa sehingga merusak source pkg2
. Anda sekarang dapat melihat coretan merah di pkg2/src/index.ts
. Bangun lagi dengan tsc -b packages --force
dan kesalahan pembuatan ditampilkan. Masalah berikut mengasumsikan membangun dengan --force
untuk mengatasi ini.
.d.ts
dihasilkan menyebabkan kesalahan pembuatan 'Pengidentifikasi duplikat' dalam paket hilirEDIT: dilaporkan di #25338.
Untuk mereproduksi masalah ini, atur repo sampel learn-a
@RyanCavanaugh sesuai instruksinya . Sekarang jalankan lerna add @types/node
untuk menambahkan pengetikan Node.js ke ketiga paket. Jalankan tsc -b packages --force
untuk mengonfirmasi bahwa itu masih berfungsi dengan baik. Sekarang tambahkan kode berikut ke pkg1/src/index.ts
:
// CASE1 - no build errors in pkg1, but 'duplicate identifier' build errors in pkg2
// import {parse} from 'url';
// export const bar = () => parse('bar');
// CASE2 - no build errors in pkg1 or in downstream packages
// import {parse, UrlWithStringQuery} from 'url';
// export const bar = (): UrlWithStringQuery => parse('bar');
// CASE3 - no build errors in pkg1 or in downstream packages
// export declare const bar: () => import("url").UrlWithStringQuery;
// CASE4 - no build errors in pkg1, but 'duplicate identifier' build errors in pkg2
// import {parse} from 'url';
// type UrlWithStringQuery = import("url").UrlWithStringQuery;
// export const bar = (): UrlWithStringQuery => parse('bar');
Batalkan komentar satu per satu dan jalankan tsc -b packages --force
. Kasus 1 dan 4 menyebabkan banjir kesalahan build di pkg2
. Dengan kasus 2 dan 3, tidak ada kesalahan pembuatan. Perbedaan penting dengan kasus 1 dan 4 tampaknya menjadi baris pertama dalam pkg1/lib/index.d.ts
dihasilkan :
/// <reference path="../node_modules/@types/node/index.d.ts" />
Kasus 2 dan 3 tidak menghasilkan baris ini. Ketika pkg2
dibuat dalam kasus 1 dan 4, itu mencakup dua salinan identik dari deklarasi @types/node
di jalur yang berbeda, dan itu menyebabkan kesalahan 'pengidentifikasi duplikat'.
Mungkin ini dirancang karena kasus 2 dan 3 berfungsi. Namun tampaknya cukup membingungkan. Tidak ada kesalahan atau peringatan build di pkg1
untuk salah satu dari 4 kasus ini, tetapi perilaku build downstream sangat sensitif terhadap gaya yang tepat dari deklarasi yang diekspor. Saya pikir (a) pkg1
harus error untuk kasus 1 & 4, atau (b) keempat kasus harus memiliki perilaku build hilir yang sama, atau (c) harus ada panduan yang jelas dari tim TS tentang bagaimana menulis deklarasi untuk menghindari masalah ini.
import
jenis di dihasilkan .d.ts
file ketika menggunakan ruang kerja benangKetika mencoba untuk mendapatkan modus membangun kerja dengan 17 paket monorepo kami, saya bekerja melalui sejumlah kesalahan membangun disebabkan oleh path relatif di import
jenis di dihasilkan .d.ts
file. Saya akhirnya menemukan bahwa masalah yang terkait dengan pengangkatan modul. Yaitu, ketika menggunakan ruang kerja benang, semua modul yang diinstal diangkat ke direktori monorepo-root node_modules
, termasuk symlink untuk semua paket di monorepo. Saya mengubah monorepo untuk menggunakan properti packages
di lerna.json
, yang menyebabkan lerna
menggunakan algoritma bootstrap non-hoisting sendiri, dan itu memecahkan masalah. Bagaimanapun, ini adalah pendekatan yang lebih baik/aman, meskipun lebih lambat.
Saya tidak yakin apakah TS bermaksud untuk mendukung pengaturan yang mengangkat modul, jadi saya belum mengembangkan repro untuk masalah yang saya temui, tetapi saya dapat mencoba membuatnya jika ada minat. Saya pikir masalahnya mungkin beberapa build mendapatkan tipe yang sama melalui direktori packages
(sesuai pengaturan tsconfig) dan direktori node_modules
(sesuai import
dalam file .d.ts
dihasilkan). Ini terkadang berfungsi karena pengetikan struktural, tetapi gagal untuk hal-hal seperti simbol unik yang diekspor.
Menyiapkan monorepo untuk menggunakan lerna pada dasarnya hanya membutuhkan meletakkan sesuatu seperti "packages": ["packages/*"]
di lerna.json
. Lerna mengerjakan daftar paket yang tepat dengan memperluas globstars, dan kemudian mengerjakan grafik dependensi yang tepat dengan melihat dependensi yang dideklarasikan dalam package.json
setiap paket. Anda dapat menambah dan menghapus paket dan dependensi sesuka hati, dan lerna
terus berjalan tanpa perlu menyentuh konfigurasinya.
Mode TypeScript --build
melibatkan sedikit lebih banyak upacara. Pola Glob tidak diakui, sehingga semua paket harus secara eksplisit terdaftar dan dipelihara (misalnya di packages/tsconfig.json
) di @RyanCavanaugh 's learn-a
repo sampel. Mode build tidak melihat dependensi package.json
, jadi setiap paket harus mempertahankan daftar paket lain yang bergantung pada file package.json
(di bawah "dependencies"
) serta itu adalah file tsconfig.json
(di bawah "references"
).
Ini adalah ketidaknyamanan kecil, tetapi saya memasukkannya di sini karena saya menemukan omong kosong yang terlihat dibandingkan dengan pendekatan lerna's
.
tsc
crash dengan augmentasi modul globalEDIT: dilaporkan di #25339.
Untuk mereproduksi masalah ini, siapkan repo sampel learn-a
@RyanCavanaugh sesuai instruksinya . Sekarang jalankan lerna add @types/multer
untuk menambahkan pengetikan multer
ke ketiga paket. Jalankan tsc -b packages --force
untuk mengonfirmasi bahwa itu masih berfungsi dengan baik. Sekarang tambahkan baris berikut ke pkg1/src/index.ts
:
export {Options} from 'multer';
Jalankan tsc -b packages --force
lagi. Kompiler lumpuh karena pernyataan yang dilanggar. Saya melihat secara singkat jejak dan pernyataan tumpukan, dan tampaknya ada hubungannya dengan augmentasi global dari namespace Express
.
terima kasih @yortus atas umpan baliknya. mengandalkan menghargainya. untuk 3, saya pikir itu https://github.com/Microsoft/TypeScript/issues/25278 .
Untuk 4, saya tidak terbiasa dengan modul mengangkat sebagai sebuah konsep. dapatkah Anda menguraikan, dan/atau membagikan repro?
@mhegazy banyak yang menggunakan lerna dan benang menggunakan ruang kerja (termasuk saya sendiri). Info lebih lanjut di sini: https://yarnpkg.com/lang/en/docs/workspaces/
Saat ini saya menggunakan ruang kerja benang, lerna, tsconfig yang diperluas di mana tsconfig dasar menyatakan paths
dibagikan untuk semua paket dengan modul hoisted yang ditemukan di bawah root/node_modules
. Ketika saya mendengar yarn
dan monorepo
, saya berpikir workspaces
karena itulah maksud dari fitur ini - untuk memudahkan penggunaan dan mengurangi duplikasi. Saya mengharapkan perubahan ini akan dengan mudah menghapus paths
saya yang panjang/menyakitkan yang dideklarasikan di tsconfig.
Berikut adalah contoh tsconfig monorepo root kami (jika ada bantuan):
{
"extends": "./packages/build/tsconfig.base.json",
"compilerOptions": {
"baseUrl": "./packages",
"paths": {
"@alienfast/build/*": ["./build/src/*"],
"@alienfast/common-node/*": ["./common-node/src/*"],
"@alienfast/common/*": ["./common/src/*"],
"@alienfast/concepts/*": ["./concepts/src/*"],
"@alienfast/faas/*": ["./faas/src/*"],
"@alienfast/math/*": ["./math/src/*"],
"@alienfast/notifications/*": ["./notifications/src/*"],
"@alienfast/ui/*": ["./ui/src/*"],
"@alienfast/build": ["./build/src"],
"@alienfast/common-node": ["./common-node/src"],
"@alienfast/common": ["./common/src"],
"@alienfast/concepts": ["./concepts/src"],
"@alienfast/faas": ["./faas/src"],
"@alienfast/math": ["./math/src"],
"@alienfast/notifications": ["./notifications/src"],
"@alienfast/ui": ["./ui/src"],
}
},
"include": ["./typings/**/*", "./packages/*/src/**/*"],
"exclude": ["node_modules", "./packages/*/node_modules"]
}
Saya akan mencoba forking untuk sampel:
https://github.com/RyanCavanaugh/learn-a
Ini adalah PR yang tidak dapat digabungkan ke repo
https://github.com/RyanCavanaugh/learn-a/pull/3/files
Kami juga menggunakan modul hoisting di Jupyterlab , dengan lerna dan benang. Hal ini memungkinkan kita untuk pada dasarnya berbagi dependensi terinstal di antara semua paket kita, jadi mereka hanya ada sekali di sistem file, di proyek root.
Saya memahami ruang kerja sedikit lebih bersih daripada harus menggunakan perintah link
antara semua paket sehingga mereka dapat mengakses satu sama lain (atau setidaknya mengakses dependensinya).
Seperti di atas, pengangkatan modul memindahkan semua dependensi ke direktori root node_modules
. Ini mengambil keuntungan dari fakta bahwa resolusi modul node akan selalu melintasi pohon direktori dan mencari melalui semua direktori node_modules
sampai menemukan modul yang diperlukan. Modul individual di monorepo Anda kemudian disinkronkan di root ini node_modules
dan semuanya berfungsi. Posting blog benang mungkin menjelaskannya lebih baik daripada yang saya bisa.
Pengangkatan tidak dijamin akan terjadi. Jika Anda memiliki versi yang tidak cocok dari paket yang sama, mereka tidak akan diangkat. Juga, banyak alat yang ada tidak mendukung pengangkatan karena mereka membuat asumsi tentang di mana node_modules
akan berada atau mereka tidak mengikuti resolusi modul node dengan benar. Karena itu ada pengaturan nohoist
yang dapat menonaktifkan pengangkatan untuk modul atau dependensi tertentu.
Saya menambahkan item keenam ke umpan balik saya tsc
lumpuh dalam skenario yang dijelaskan di sana.
@mhegazy Saya tidak yakin item 3 terkait dengan #25278. #25278 menjelaskan emisi deklarasi yang tidak valid. File deklarasi yang saya hasilkan valid secara sintaksis dan semantik, tetapi menyebabkan proyek hilir dibangun dengan dua salinan pengetikan simpul, menghasilkan kesalahan 'pengidentifikasi duplikat'.
Seperti di atas, pengangkatan modul memindahkan semua dependensi ke direktori root node_modules. Ini mengambil keuntungan dari fakta bahwa resolusi modul node akan selalu melintasi pohon direktori dan mencari melalui semua direktori node_modules sampai menemukan modul yang diperlukan.
Btw ada kelemahan model ini, yang mengarah ke "ketergantungan hantu" di mana sebuah proyek dapat mengimpor ketergantungan yang tidak secara eksplisit dideklarasikan dalam file package.json-nya. Saat Anda menerbitkan perpustakaan Anda, ini dapat menyebabkan masalah seperti (1) versi dependensi yang berbeda yang diinstal dari apa yang diuji/diharapkan, atau (2) dependensi hilang sepenuhnya karena diangkat dari proyek yang tidak terkait yang tidak diinstal pada konteks ini. PNPM dan Rush keduanya memiliki pilihan arsitektur yang dimaksudkan untuk melindungi dari ketergantungan hantu.
Saya memiliki pertanyaan umum tentang tsc --build
: Apakah kompiler TypeScript berusaha mengambil alih peran mengatur pembangunan untuk proyek dalam monorepo? Biasanya toolchain akan memiliki seluruh jalur tugas, hal-hal seperti:
Biasanya sistem seperti Gulp atau Webpack mengelola saluran ini, dan kompiler hanya satu langkah di tengah rantai. Terkadang alat sekunder juga menjalankan pembangunan dengan cara lain, misalnya Jest+ts-jest untuk jest --watch
.
Apakah tsc
bertujuan untuk mengelola hal-hal ini sendiri? Dan jika tidak, apakah ada cara bagi orkestra pembangunan konvensional untuk memecahkan grafik ketergantungan itu sendiri, dan misalnya berulang kali memanggil tsc di setiap folder proyek dalam urutan yang benar (setelah prapemrosesan diperbarui)?
Atau, jika desainnya adalah untuk memproses seluruh monorepo dalam satu lintasan (sedangkan hari ini kita membangun setiap proyek dalam proses NodeJs yang terpisah), saya juga ingin tahu bagaimana tugas pembangunan lainnya akan berpartisipasi: Misalnya, apakah kita akan menjalankan webpack di semua proyek sekaligus? (Di masa lalu yang menyebabkan masalah kehabisan memori.) Apakah kita akan kehilangan kemampuan untuk mengeksploitasi konkurensi multi-proses?
Ini bukan kritik BTW. Saya hanya mencoba memahami gambaran besar dan penggunaan yang dimaksudkan.
@pgonzal benar, ada banyak bagian non-tsc untuk membangun monorepo dunia nyata. Untuk lerna monorepo kami, saya mengambil pendekatan berikut:
prebuild
dan/atau skrip postbuild
dalam package.json
. Ini berisi aspek non-tsc dari build.package.json
monorepo, ada skrip ini:
"prebuild": "lerna run prebuild",
"build": "tsc --build monorepo.tsconfig.json --verbose",
"postbuild": "lerna run postbuild",
yarn build
pada level monorepo menjalankan skrip prebuild
untuk setiap paket yang mendefinisikannya, kemudian menjalankan langkah tsc --build
, kemudian menjalankan semua postbuild
skrip. (Dengan konvensi di npm dan benang, mengeksekusi npm run foo
kira-kira sama dengan npm run prefoo && npm run foo && npm run postfoo
.)Bagaimana Anda menangani jest --watch
atau webpack-dev-server
? Misalnya ketika file sumber dimodifikasi, apakah langkah-langkah prebuild/postbuild berjalan lagi?
Apakah ini memiliki implikasi pada ts-node
dan alur kerja terkait? Beberapa aplikasi pembantu kami berjalan "langsung" dari TypeScript, seperti "start": "ts-node ./src/app.ts"
atau "start:debug": "node -r ts-node/register --inspect-brk ./src/app.ts"
.
Melaporkan masalah lain dengan mode build di #25355.
Terima kasih atas semua umpan balik dan investigasi yang luar biasa sejauh ini. Saya sangat menghargai semua orang yang meluangkan waktu untuk mencoba berbagai hal dan menendang ban.
@yortus kembali https://github.com/Microsoft/TypeScript/issues/3469#issuecomment -400439520
Besar write-up, terima kasih lagi untuk menyediakan ini. Masalah Anda berurutan -
--build
AFAICT. Ini adalah pernyataan baru yang kami tambahkan baru-baru ini; Nathan sedang menyelidiki@rosskevin untuk PR di repo learn-a
! Saya akan menggabungkannya menjadi cabang sehingga kita dapat membandingkan dan membedakan dengan lebih baik.
@pgonzal kembali https://github.com/Microsoft/TypeScript/issues/3469#issuecomment -401577442
Saya punya pertanyaan umum tentang tsc --build: Apakah kompiler TypeScript berusaha mengambil alih peran mengatur build untuk proyek dalam monorepo?
Pertanyaan bagus; Saya ingin menjawab yang ini dengan sangat jelas: pasti tidak .
Jika Anda senang hari ini menggunakan tsc
untuk membangun proyek Anda, kami ingin Anda bahagia besok menggunakan tsc -b
untuk membangun proyek multi-bagian Anda. Jika Anda senang hari ini menggunakan gulp
untuk membangun proyek Anda, kami ingin Anda bahagia besok menggunakan gulp
untuk membangun proyek multi-bagian Anda. Kami memiliki kendali atas skenario pertama, tetapi membutuhkan pembuat alat dan plugin untuk membantu kami dengan skenario kedua, itulah sebabnya bahkan tsc -b
hanyalah pembungkus tipis atas API terbuka yang dapat digunakan oleh pembuat alat untuk membantu referensi proyek bermain dengan baik dalam model bangunan mereka.
Konteks yang lebih luas adalah bahwa ada perdebatan internal yang cukup kuat mengenai apakah tsc -b
bahkan harus ada, atau sebagai gantinya menjadi alat / titik masuk yang terpisah - membangun orkestra bangunan tujuan umum adalah tugas yang sangat besar dan bukan tugas kami. mendaftar untuk. Untuk repo kami sendiri, kami menggunakan tsc
dengan kerangka kerja pelari tugas ringan dan sekarang menggunakan tsc -b
dengan pelari tugas yang sama, dan saya berharap orang lain yang bermigrasi juga mempertahankan rantai pembangunan yang ada di tempatnya dengan hanya tweak kecil.
@borekb kembali https://github.com/Microsoft/TypeScript/issues/3469#issuecomment -401593804
Apakah ini memiliki implikasi pada ts-node dan alur kerja terkait? Beberapa aplikasi pembantu kami berjalan "langsung" dari TypeScript
Untuk skrip file tunggal, yang secara implisit tidak dapat memiliki referensi proyek, tidak ada dampak sama sekali.
@EisenbergEffect memiliki beberapa pertanyaan di repo learn-a
tentang penggantian nama lintas proyek dan fitur layanan bahasa lainnya. Pertanyaan besar yang terbuka di sini adalah apakah kita bisa mendapatkan fitur ini dalam keadaan yang dapat digunakan untuk 3.0 atau tidak. Jika demikian, maka penggantian nama lintas-proyek akan "hanya berfungsi", tunduk pada peringatan bahwa jelas tidak mungkin bagi kami untuk secara meyakinkan menemukan semua proyek hilir dan memperbaruinya - ini akan menjadi "upaya terbaik" berdasarkan beberapa heuristik untuk mencari yang lain proyek.
Jika menurut kami penggantian nama lintas proyek tidak dapat diterima stabil+lengkap untuk 3.0, kami kemungkinan akan memblokir operasi penggantian nama hanya ketika simbol yang diganti namanya ada di file keluaran .d.ts dari proyek lain - memungkinkan Anda melakukan ini sangat membingungkan karena file .d.ts akan diperbarui pada build berikutnya dari proyek upstream setelah proyek upstream telah dimodifikasi, yang berarti dapat dengan mudah berhari-hari antara saat Anda membuat penggantian nama lokal dan ketika Anda menyadari bahwa kode yang dideklarasikan belum benar-benar diperbarui.
Untuk fitur seperti Go to Definition, ini berfungsi hari ini di VS Code dan akan berfungsi di luar kotak di versi Visual Studio yang akan datang. Semua fitur ini memerlukan file .d.ts.map untuk diaktifkan (aktifkan declarationMap
). Ada beberapa pekerjaan per-fitur untuk menerangi ini, jadi jika Anda melihat sesuatu tidak berfungsi seperti yang diharapkan, lakukan log bug karena kami mungkin melewatkan beberapa kasus.
Buka masalah yang saya lacak saat ini:
learn-a
yang menggunakan yarn
, dan versi lain yang menggunakan pnpm
, dan versi lain yang menggunakan salah satunya dalam mode hoistedPertanyaan-pertanyaan terbuka
package.json
s untuk menyimpulkan referensi proyek? Tercatat #25376.d.ts.map
memancarkan secara implisit untuk proyek composite
?@RyanCavanaugh untuk ditambahkan ke
Buka masalah yang saya lacak saat ini
Kami juga telah menyebutkan memiliki cache keluaran tambahan, terpisah dari lokasi keluaran proyek nyata, untuk menangani hal-hal seperti memperbarui deklarasi di latar belakang di LS (hari ini, perubahan tidak menyebar melintasi batas proyek di editor sampai Anda membangun), stripInternal
, dan mengubah proses build (di mana output build kami dimutasi di tempatnya sehingga tidak cocok untuk operasi LS).
maaf untuk pertanyaan bodoh, karena sudah diperiksa di peta jalan, bagaimana cara mengaktifkan fitur ini?
@aleksey-bykov Anda dapat menggunakannya di TypeScript@next.
Saya baru saja mencoba ini pada monorepo bertenaga ruang kerja benang kami dan itu bekerja dengan baik.
Satu hal yang saya perhatikan adalah tsc --build --watch
melaporkan kesalahan tetapi kemudian tidak mengeluarkan apa pun untuk mengatakan bahwa build sekarang sudah diperbaiki. Mode jam standar tsc
di 2.9 telah mulai memberikan hitungan kesalahan dan senang melihat angka nol di sana sehingga Anda tahu bahwa pembangunan telah selesai.
saya memiliki folder yang penuh dengan *.d.ts dan tidak ada lagi yang harus saya lakukan:
@timfish umpan balik itu cocok dengan yang lain yang pernah saya dengar; login #25562
@aleksey-bykov https://github.com/Microsoft/TypeScript/issues/3469#issuecomment -400439520 akan membantu menjelaskan beberapa konsep
@RyanCavanaugh sepertinya referensi proyek hanya berfungsi untuk resolusi modul commonjs dan node, bukan?
pada kamu contoh:
import * as p1 from "@ryancavanaugh/pkg1";
import * as p2 from "@ryancavanaugh/pkg2";
p1.fn();
p2.fn4();
@ryancavanaugh
, apakah ada hubungannya dengan bagaimana TS menyelesaikan modul?outFile
diperlukan agar definisi dapat ditemukan?saya punya 2 proyek sederhana essentials
dan common
dan kesamaan tidak dapat menyelesaikan hal-hal yang dikompilasi dalam hal-hal penting:
@aleksey-bykov
Jika Anda memiliki sampel repo atau sesuatu, saya dapat mendiagnosis mengapa Anda mendapatkan kesalahan itu
@RyanCavanaugh tolong lakukan
contoh.zip
@RyanCavanaugh , sepertinya tsc --build --watch
awalnya tidak menampilkan file apa pun sampai ia melihat modifikasi file sumber.
Utas terlalu panjang (dalam ruang dan waktu); yuk ikuti pembahasannya di lucky issue nomor 100*2^8 : #25600
Komentar yang paling membantu
Dokumen/posting blog sedang dalam proses di bawah (akan mengedit ini berdasarkan umpan balik)
Saya akan mendorong siapa pun yang mengikuti utas ini untuk mencobanya. Saya sedang mengerjakan skenario monorepo sekarang untuk memperbaiki bug/fitur terakhir di sana dan akan segera mendapatkan panduan tentangnya
Referensi Proyek
Referensi proyek adalah fitur baru di TypeScript 3.0 yang memungkinkan Anda untuk menyusun program TypeScript Anda menjadi bagian yang lebih kecil.
Dengan melakukan ini, Anda dapat sangat meningkatkan waktu pembuatan, menerapkan pemisahan logis antar komponen, dan mengatur kode Anda dengan cara baru dan lebih baik.
Kami juga memperkenalkan mode baru untuk
tsc
, flag--build
, yang bekerja bersama dengan referensi proyek untuk memungkinkan pembuatan TypeScript yang lebih cepat.Contoh Proyek
Mari kita lihat program yang cukup normal dan lihat bagaimana referensi proyek dapat membantu kita mengaturnya dengan lebih baik.
Bayangkan Anda memiliki proyek dengan dua modul,
converter
danunits
, dan file pengujian yang sesuai untuk masing-masing:File pengujian mengimpor file implementasi dan melakukan beberapa pengujian:
Sebelumnya, struktur ini agak canggung untuk digunakan jika Anda menggunakan satu file tsconfig:
test
dansrc
bersamaan tanpasrc
muncul di nama folder keluaran, yang mungkin tidak Anda inginkanAnda dapat menggunakan beberapa file tsconfig untuk menyelesaikan beberapa masalah tersebut, tetapi yang baru akan muncul:
tsc
dua kalitsc
dua kali menimbulkan lebih banyak overhead waktu startuptsc -w
tidak dapat dijalankan pada beberapa file konfigurasi sekaligusReferensi proyek dapat menyelesaikan semua masalah ini dan banyak lagi.
Apa itu Referensi Proyek?
File
tsconfig.json
memiliki properti tingkat atas baru,references
. Ini adalah array objek yang menentukan proyek untuk referensi:Properti
path
dari setiap referensi dapat menunjuk ke direktori yang berisi filetsconfig.json
, atau ke file konfigurasi itu sendiri (yang mungkin memiliki nama apa pun).Saat Anda mereferensikan sebuah proyek, hal-hal baru terjadi:
.d.ts
)outFile
, deklarasi file.d.ts
file output akan terlihat dalam proyek iniDengan memisahkan menjadi beberapa proyek, Anda dapat sangat meningkatkan kecepatan pengecekan dan kompilasi, mengurangi penggunaan memori saat menggunakan editor, dan meningkatkan penegakan pengelompokan logis program Anda.
composite
Proyek yang direferensikan harus mengaktifkan setelan
composite
.Pengaturan ini diperlukan untuk memastikan TypeScript dapat dengan cepat menentukan di mana menemukan output dari proyek yang direferensikan.
Mengaktifkan flag
composite
mengubah beberapa hal:rootDir
, jika tidak disetel secara eksplisit, default ke direktori yang berisi filetsconfig
include
atau terdaftar dalam larikfiles
. Jika batasan ini dilanggar,tsc
akan memberi tahu Anda file mana yang tidak ditentukandeclaration
harus diaktifkandeclarationMaps
Kami juga telah menambahkan dukungan untuk peta sumber deklarasi .
Jika Anda mengaktifkan
--declarationMap
, Anda akan dapat menggunakan fitur editor seperti "Buka Definisi" dan Ganti Nama untuk menavigasi dan mengedit kode secara transparan melintasi batas proyek di editor yang didukung.prepend
denganoutFile
Anda juga dapat mengaktifkan prepending output dari dependensi menggunakan opsi
prepend
dalam referensi:Memulai proyek akan mencakup keluaran proyek di atas keluaran proyek saat ini.
Ini berfungsi untuk file
.js
dan file.d.ts
, dan file peta sumber juga akan dipancarkan dengan benar.tsc
hanya akan pernah menggunakan file yang ada di disk untuk melakukan proses ini, jadi dimungkinkan untuk membuat proyek di mana file output yang benar tidak dapat dihasilkan karena beberapa output proyek akan ada lebih dari sekali dalam file yang dihasilkan .Sebagai contoh:
Dalam situasi ini, penting untuk tidak menambahkan di setiap referensi, karena Anda akan mendapatkan dua salinan
A
dalam outputD
- ini dapat menyebabkan hasil yang tidak diharapkan.Peringatan untuk Referensi Proyek
Referensi proyek memiliki beberapa trade-off yang harus Anda ketahui.
Karena proyek dependen menggunakan file
.d.ts
yang dibuat dari dependensinya, Anda harus memeriksa keluaran build tertentu atau membangun proyek setelah mengkloningnya sebelum Anda dapat menavigasi proyek di editor tanpa melihat yang palsu kesalahan.Kami sedang mengerjakan proses pembuatan .d.ts di balik layar yang seharusnya dapat mengurangi hal ini, tetapi untuk saat ini kami menyarankan untuk memberi tahu pengembang bahwa mereka harus membangun setelah kloning.
Selain itu, untuk menjaga kompatibilitas dengan alur kerja build yang ada,
tsc
tidak akan secara otomatis membangun dependensi kecuali dipanggil dengan sakelar--build
.Mari pelajari lebih lanjut tentang
--build
.Membangun Mode untuk TypeScript
Fitur yang telah lama ditunggu-tunggu adalah build inkremental cerdas untuk proyek TypeScript.
Di 3.0 Anda dapat menggunakan flag
--build
dengantsc
.Ini secara efektif merupakan titik masuk baru untuk
tsc
yang berperilaku lebih seperti orkestra build daripada kompiler sederhana.Menjalankan
tsc --build
( singkatnyatsc -b
) akan melakukan hal berikut:Anda dapat memberikan
tsc -b
dengan beberapa jalur file konfigurasi (misalnyatsc -b src test
).Sama seperti
tsc -p
, menentukan nama file konfigurasi itu sendiri tidak perlu jika bernamatsconfig.json
.tsc -b
Baris PerintahAnda dapat menentukan sejumlah file konfigurasi:
Jangan khawatir tentang memesan file yang Anda berikan pada baris perintah -
tsc
akan memesan ulang jika diperlukan sehingga dependensi selalu dibangun terlebih dahulu.Ada juga beberapa flag khusus untuk
tsc -b
:--verbose
: Mencetak log verbose untuk menjelaskan apa yang terjadi (dapat digabungkan dengan flag lain)--dry
: Menunjukkan apa yang akan dilakukan tetapi tidak benar-benar membangun apa pun--clean
: Menghapus output dari proyek yang ditentukan (dapat digabungkan dengan--dry
)--force
: Bertindak seolah-olah semua proyek sudah ketinggalan zaman--watch
: Mode tontonan (tidak boleh digabungkan dengan bendera apa pun kecuali--verbose
)Peringatan
Biasanya,
tsc
akan menghasilkan output (.js
dan.d.ts
) dengan adanya sintaks atau kesalahan ketik, kecualinoEmitOnError
aktif.Melakukan ini dalam sistem pembangunan inkremental akan sangat buruk - jika salah satu dependensi Anda yang kedaluwarsa mengalami kesalahan baru, Anda hanya akan melihatnya sekali karena pembangunan berikutnya akan melewatkan pembangunan proyek yang sekarang diperbarui.
Untuk alasan ini,
tsc -b
secara efektif bertindak seolah-olahnoEmitOnError
diaktifkan untuk semua proyek.Jika Anda memeriksa keluaran build apa pun (
.js
,.d.ts
,.d.ts.map
, dll.), Anda mungkin perlu menjalankan build--force
setelah kontrol sumber tertentu operasi tergantung pada apakah alat kontrol sumber Anda mempertahankan peta waktu antara salinan lokal dan salinan jarak jauh.msbuild
Jika Anda memiliki proyek msbuild, Anda dapat mengaktifkan mode build dengan menambahkan
ke file proj Anda. Ini akan memungkinkan pembuatan inkremental otomatis serta pembersihan.
Perhatikan bahwa seperti halnya
tsconfig.json
/-p
, properti proyek TypeScript yang ada tidak akan dihormati - semua pengaturan harus dikelola menggunakan file tsconfig Anda.Beberapa tim telah menyiapkan alur kerja berbasis msbuild di mana file tsconfig memiliki urutan grafik implisit yang sama dengan proyek terkelola yang dipasangkan dengan mereka.
Jika solusi Anda seperti ini, Anda dapat terus menggunakan
msbuild
dengantsc -p
bersama dengan referensi proyek; ini sepenuhnya dapat dioperasikan.Panduan
Struktur Keseluruhan
Dengan lebih banyak file
tsconfig.json
, Anda biasanya ingin menggunakan warisan file Konfigurasi untuk memusatkan opsi kompiler umum Anda.Dengan cara ini Anda dapat mengubah pengaturan dalam satu file daripada harus mengedit banyak file.
Praktik baik lainnya adalah memiliki file
tsconfig.json
"solusi" yang hanya memilikireferences
untuk semua proyek simpul daun Anda.Ini menyajikan titik masuk sederhana; misalnya dalam repo TypeScript kita cukup menjalankan
tsc -b src
untuk membangun semua titik akhir karena kita mencantumkan semua subproyek disrc/tsconfig.json
Perhatikan bahwa mulai dari 3.0, tidak ada lagi kesalahan untuk memiliki array
files
kosong jika Anda memiliki setidaknya satureference
dalam filetsconfig.json
.Anda dapat melihat pola ini di repo TypeScript - lihat
src/tsconfig_base.json
,src/tsconfig.json
, dansrc/tsc/tsconfig.json
sebagai contoh utama.Penataan untuk modul relatif
Secara umum, tidak banyak yang diperlukan untuk mentransisikan repo menggunakan modul relatif.
Cukup tempatkan file
tsconfig.json
di setiap subdirektori dari folder induk yang diberikan, dan tambahkanreference
s ke file konfigurasi ini agar sesuai dengan lapisan program yang diinginkan.Anda perlu menyetel
outDir
ke subfolder eksplisit dari folder output, atau menyetelrootDir
ke root umum semua folder proyek.Penataan untuk outFiles
Tata letak untuk kompilasi menggunakan
outFile
lebih fleksibel karena jalur relatif tidak terlalu penting.Satu hal yang perlu diingat adalah bahwa Anda biasanya tidak ingin menggunakan
prepend
hingga proyek "terakhir" - ini akan meningkatkan waktu pembuatan dan mengurangi jumlah I/O yang dibutuhkan dalam setiap bangunan.Repo TypeScript sendiri adalah referensi yang bagus di sini - kami memiliki beberapa proyek "perpustakaan" dan beberapa proyek "titik akhir"; proyek "titik akhir" disimpan sekecil mungkin dan hanya menarik perpustakaan yang mereka butuhkan.
Penataan untuk monorepos
TODO: Eksperimen lebih banyak dan cari tahu ini. Rush dan Lerna tampaknya memiliki model berbeda yang menyiratkan hal berbeda di pihak kami