Bahasa Indonesia

Panduan komprehensif resolusi modul TypeScript, mencakup strategi resolusi modul classic dan node, baseUrl, paths, serta praktik terbaik mengelola jalur impor.

Resolusi Modul TypeScript: Mengungkap Strategi Jalur Impor

Sistem resolusi modul TypeScript adalah aspek penting dalam membangun aplikasi yang skalabel dan mudah dipelihara. Memahami bagaimana TypeScript menemukan modul berdasarkan jalur impor sangat penting untuk mengatur basis kode Anda dan menghindari kesalahan umum. Panduan komprehensif ini akan membahas seluk-beluk resolusi modul TypeScript, mencakup strategi resolusi modul classic dan node, peran baseUrl dan paths di tsconfig.json, serta praktik terbaik untuk mengelola jalur impor secara efektif.

Apa itu Resolusi Modul?

Resolusi modul adalah proses di mana kompiler TypeScript menentukan lokasi modul berdasarkan pernyataan impor dalam kode Anda. Ketika Anda menulis import { SomeComponent } from './components/SomeComponent';, TypeScript perlu mengetahui di mana modul SomeComponent sebenarnya berada di sistem file Anda. Proses ini diatur oleh serangkaian aturan dan konfigurasi yang menentukan bagaimana TypeScript mencari modul.

Resolusi modul yang salah dapat menyebabkan kesalahan kompilasi, kesalahan runtime, dan kesulitan dalam memahami struktur proyek. Oleh karena itu, pemahaman yang kuat tentang resolusi modul sangat penting bagi setiap pengembang TypeScript.

Strategi Resolusi Modul

TypeScript menyediakan dua strategi resolusi modul utama, yang dikonfigurasi melalui opsi kompiler moduleResolution di tsconfig.json:

Resolusi Modul Classic

Strategi resolusi modul classic adalah yang lebih sederhana dari keduanya. Ia mencari modul dengan cara yang lugas, menelusuri pohon direktori ke atas dari file pengimpor.

Cara kerjanya:

  1. Dimulai dari direktori yang berisi file pengimpor.
  2. TypeScript mencari file dengan nama dan ekstensi yang ditentukan (.ts, .tsx, .d.ts).
  3. Jika tidak ditemukan, ia akan pindah ke direktori induk dan mengulangi pencarian.
  4. Proses ini berlanjut hingga modul ditemukan atau akar sistem file tercapai.

Contoh:

Pertimbangkan struktur proyek berikut:


project/
├── src/
│   ├── components/
│   │   ├── SomeComponent.ts
│   │   └── index.ts
│   └── app.ts
├── tsconfig.json

Jika app.ts berisi pernyataan impor import { SomeComponent } from './components/SomeComponent';, strategi resolusi modul classic akan:

  1. Mencari ./components/SomeComponent.ts, ./components/SomeComponent.tsx, atau ./components/SomeComponent.d.ts di direktori src.
  2. Jika tidak ditemukan, ia akan pindah ke direktori induk (root proyek) dan mengulangi pencarian, yang kemungkinan besar tidak akan berhasil dalam kasus ini karena komponen berada di dalam folder src.

Keterbatasan:

Kapan Menggunakannya:

Strategi resolusi modul classic umumnya hanya cocok untuk proyek yang sangat kecil dengan struktur direktori sederhana dan tanpa dependensi eksternal. Proyek TypeScript modern hampir selalu harus menggunakan strategi resolusi modul node.

Resolusi Modul Node

Strategi resolusi modul node meniru algoritma resolusi modul yang digunakan oleh Node.js. Ini menjadikannya pilihan yang lebih disukai untuk proyek yang menargetkan Node.js atau menggunakan paket npm, karena memberikan perilaku resolusi modul yang konsisten dan dapat diprediksi.

Cara kerjanya:

Strategi resolusi modul node mengikuti serangkaian aturan yang lebih kompleks, memprioritaskan pencarian di dalam node_modules dan menangani ekstensi file yang berbeda:

  1. Impor non-relatif: Jika jalur impor tidak dimulai dengan ./, ../, atau /, TypeScript mengasumsikan itu merujuk ke modul yang terletak di node_modules. Ia akan mencari modul di lokasi berikut:
    • node_modules di direktori saat ini.
    • node_modules di direktori induk.
    • ...dan seterusnya, hingga ke akar sistem file.
  2. Impor relatif: Jika jalur impor dimulai dengan ./, ../, atau /, TypeScript menganggapnya sebagai jalur relatif dan mencari modul di lokasi yang ditentukan, dengan mempertimbangkan hal berikut:
    • Ia pertama-tama mencari file dengan nama dan ekstensi yang ditentukan (.ts, .tsx, .d.ts).
    • Jika tidak ditemukan, ia mencari direktori dengan nama yang ditentukan dan file bernama index.ts, index.tsx, atau index.d.ts di dalam direktori itu (mis., ./components/index.ts jika impornya adalah ./components).

Contoh:

Pertimbangkan struktur proyek berikut dengan dependensi pada pustaka lodash:


project/
├── src/
│   ├── utils/
│   │   └── helpers.ts
│   └── app.ts
├── node_modules/
│   └── lodash/
│       └── lodash.js
├── tsconfig.json

Jika app.ts berisi pernyataan impor import * as _ from 'lodash';, strategi resolusi modul node akan:

  1. Mengenali bahwa lodash adalah impor non-relatif.
  2. Mencari lodash di direktori node_modules di dalam root proyek.
  3. Menemukan modul lodash di node_modules/lodash/lodash.js.

Jika helpers.ts berisi pernyataan impor import { SomeHelper } from './SomeHelper';, strategi resolusi modul node akan:

  1. Mengenali bahwa ./SomeHelper adalah impor relatif.
  2. Mencari ./SomeHelper.ts, ./SomeHelper.tsx, atau ./SomeHelper.d.ts di direktori src/utils.
  3. Jika tidak ada file-file tersebut, ia akan mencari direktori bernama SomeHelper dan kemudian mencari index.ts, index.tsx, atau index.d.ts di dalam direktori itu.

Keuntungan:

Kapan Menggunakannya:

Strategi resolusi modul node adalah pilihan yang direkomendasikan untuk sebagian besar proyek TypeScript, terutama yang menargetkan Node.js atau menggunakan paket npm. Ini menyediakan sistem resolusi modul yang lebih fleksibel dan kuat dibandingkan dengan strategi classic.

Mengonfigurasi Resolusi Modul di tsconfig.json

File tsconfig.json adalah file konfigurasi pusat untuk proyek TypeScript Anda. Ini memungkinkan Anda untuk menentukan opsi kompiler, termasuk strategi resolusi modul, dan menyesuaikan bagaimana TypeScript menangani kode Anda.

Berikut adalah file tsconfig.json dasar dengan strategi resolusi modul node:


{
  "compilerOptions": {
    "moduleResolution": "node",
    "target": "es5",
    "module": "commonjs",
    "esModuleInterop": true,
    "strict": true,
    "outDir": "dist",
    "sourceMap": true
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules"
  ]
}

Kunci compilerOptions terkait resolusi modul:

baseUrl dan paths: Mengontrol Jalur Impor

Opsi kompiler baseUrl dan paths menyediakan mekanisme yang kuat untuk mengontrol bagaimana TypeScript menyelesaikan jalur impor. Mereka dapat secara signifikan meningkatkan keterbacaan dan pemeliharaan kode Anda dengan memungkinkan Anda menggunakan impor absolut dan membuat pemetaan jalur kustom.

baseUrl

Opsi baseUrl menentukan direktori dasar untuk menyelesaikan nama modul non-relatif. Ketika baseUrl diatur, TypeScript akan menyelesaikan jalur impor non-relatif relatif terhadap direktori dasar yang ditentukan alih-alih direktori kerja saat ini.

Contoh:

Pertimbangkan struktur proyek berikut:


project/
├── src/
│   ├── components/
│   │   ├── SomeComponent.ts
│   │   └── index.ts
│   └── app.ts
├── tsconfig.json

Jika tsconfig.json berisi sebagai berikut:


{
  "compilerOptions": {
    "moduleResolution": "node",
    "baseUrl": "./src"
  }
}

Maka, di app.ts, Anda dapat menggunakan pernyataan impor berikut:


import { SomeComponent } from 'components/SomeComponent';

Alih-alih:


import { SomeComponent } from './components/SomeComponent';

TypeScript akan menyelesaikan components/SomeComponent relatif terhadap direktori ./src yang ditentukan oleh baseUrl.

Manfaat menggunakan baseUrl:

paths

Opsi paths memungkinkan Anda mengonfigurasi pemetaan jalur kustom untuk modul. Ini menyediakan cara yang lebih fleksibel dan kuat untuk mengontrol bagaimana TypeScript menyelesaikan jalur impor, memungkinkan Anda membuat alias untuk modul dan mengarahkan impor ke lokasi yang berbeda.

Opsi paths adalah sebuah objek di mana setiap kunci mewakili pola jalur, dan setiap nilai adalah larik penggantian jalur. TypeScript akan mencoba mencocokkan jalur impor dengan pola jalur dan, jika ditemukan kecocokan, mengganti jalur impor dengan jalur pengganti yang ditentukan.

Contoh:

Pertimbangkan struktur proyek berikut:


project/
├── src/
│   ├── components/
│   │   ├── SomeComponent.ts
│   │   └── index.ts
│   └── app.ts
├── libs/
│   └── my-library.ts
├── tsconfig.json

Jika tsconfig.json berisi sebagai berikut:


{
  "compilerOptions": {
    "moduleResolution": "node",
    "baseUrl": "./src",
    "paths": {
      "@components/*": ["components/*"],
      "@mylib": ["../libs/my-library.ts"]
    }
  }
}

Maka, di app.ts, Anda dapat menggunakan pernyataan impor berikut:


import { SomeComponent } from '@components/SomeComponent';
import { MyLibraryFunction } from '@mylib';

TypeScript akan menyelesaikan @components/SomeComponent menjadi components/SomeComponent berdasarkan pemetaan jalur @components/*, dan @mylib menjadi ../libs/my-library.ts berdasarkan pemetaan jalur @mylib.

Manfaat menggunakan paths:

Kasus Penggunaan Umum untuk paths:

Praktik Terbaik untuk Mengelola Jalur Impor

Manajemen jalur impor yang efektif sangat penting untuk membangun aplikasi TypeScript yang skalabel dan mudah dipelihara. Berikut adalah beberapa praktik terbaik yang harus diikuti:

Memecahkan Masalah Resolusi Modul

Masalah resolusi modul bisa membuat frustrasi saat melakukan debug. Berikut adalah beberapa masalah umum dan solusinya:

Contoh Dunia Nyata di Berbagai Kerangka Kerja

Prinsip-prinsip resolusi modul TypeScript berlaku di berbagai kerangka kerja JavaScript. Berikut adalah cara mereka umum digunakan:

Kesimpulan

Sistem resolusi modul TypeScript adalah alat yang kuat untuk mengatur basis kode Anda dan mengelola dependensi secara efektif. Dengan memahami berbagai strategi resolusi modul, peran baseUrl dan paths, serta praktik terbaik untuk mengelola jalur impor, Anda dapat membangun aplikasi TypeScript yang skalabel, mudah dipelihara, dan mudah dibaca. Mengonfigurasi resolusi modul dengan benar di tsconfig.json dapat secara signifikan meningkatkan alur kerja pengembangan Anda dan mengurangi risiko kesalahan. Bereksperimenlah dengan konfigurasi yang berbeda dan temukan pendekatan yang paling sesuai dengan kebutuhan proyek Anda.