Projeler genellikle karmaşık, iç içe geçmiş dizin yapılarına dönüşür. Sonuç olarak, içe aktarma yolları daha uzun ve daha kafa karıştırıcı hale gelebilir; bu da kodun görünümünü olumsuz yönde etkileyebilir ve içe aktarılan kodun nereden geldiğinin anlaşılmasını zorlaştırabilir.
Yol takma adlarının kullanılması, önceden tanımlanmış dizinlere göre içe aktarmaların tanımlanmasına izin vererek sorunu çözebilir. Bu yaklaşım yalnızca içe aktarma yollarının anlaşılmasıyla ilgili sorunları çözmekle kalmaz, aynı zamanda yeniden düzenleme sırasında kod taşıma sürecini de basitleştirir.
// Without Aliases import { apiClient } from '../../../../shared/api'; import { ProductView } from '../../../../entities/product/components/ProductView'; import { addProductToCart } from '../../../add-to-cart/actions'; // With Aliases import { apiClient } from '#shared/api'; import { ProductView } from '#entities/product/components/ProductView'; import { addProductToCart } from '#features/add-to-cart/actions';
Node.js'de yol takma adlarını yapılandırmak için alias-hq ve tsconfig-paths gibi birden fazla kitaplık mevcuttur. Ancak Node.js belgelerini incelerken üçüncü taraf kitaplıklara güvenmek zorunda kalmadan yol takma adlarını yapılandırmanın bir yolunu keşfettim.
Üstelik bu yaklaşım, takma adların oluşturma adımı gerektirmeden kullanılmasına olanak sağlar.
Bu makalede Node.js Alt Yol İçe Aktarmalarını ve onu kullanarak yol takma adlarının nasıl yapılandırılacağını tartışacağız. Ayrıca ön uç ekosistemindeki desteklerini de araştıracağız.
Node.js v12.19.0'dan itibaren geliştiriciler, bir npm paketi içindeki yol takma adlarını bildirmek için Alt Yol İçe Aktarmalarını kullanabilir. Bu, package.json
dosyasındaki imports
alanı aracılığıyla yapılabilir. Paketin npm'de yayınlanmasına gerek yoktur.
Herhangi bir dizinde package.json
dosyası oluşturmak yeterlidir. Dolayısıyla bu yöntem özel projeler için de uygundur.
İşte ilginç bir gerçek: Node.js, 2020 yılında " node.js'de Çıplak Modül Belirleyici Çözünürlüğü " adı verilen RFC aracılığıyla imports
alanı için destek başlattı. Bu RFC esas olarak npm paketleri için giriş noktalarının bildirilmesine izin veren exports
alanı için tanınırken, exports
ve imports
alanları, benzer adlara ve sözdizimine sahip olsalar bile tamamen farklı görevleri ele alır.
Yol takma adları için yerel desteğin teoride aşağıdaki avantajları vardır:
Projelerimde yol takma adlarını yapılandırmaya çalıştım ve bu ifadeleri pratikte test ettim.
Örnek olarak aşağıdaki dizin yapısına sahip bir projeyi ele alalım:
my-awesome-project ├── src/ │ ├── entities/ │ │ └── product/ │ │ └── components/ │ │ └── ProductView.js │ ├── features/ │ │ └── add-to-cart/ │ │ └── actions/ │ │ └── index.js │ └── shared/ │ └── api/ │ └── index.js └── package.json
Yol takma adlarını yapılandırmak için package.json
dosyasına belgelerde açıklandığı gibi birkaç satır ekleyebilirsiniz. Örneğin, src
dizinine göre içe aktarmalara izin vermek istiyorsanız aşağıdaki imports
alanını package.json
dosyasına ekleyin:
{ "name": "my-awesome-project", "imports": { "#*": "./src/*" } }
Yapılandırılmış takma adı kullanmak için içe aktarmalar şu şekilde yazılabilir:
import { apiClient } from '#shared/api'; import { ProductView } from '#entities/product/components/ProductView'; import { addProductToCart } from '#features/add-to-cart/actions';
Kurulum aşamasından itibaren ilk sınırlamayla karşı karşıyayız: imports
alanındaki girişler #
simgesiyle başlamalıdır. Bu onların @
gibi paket belirticilerden ayırt edilmesini sağlar.
Bu sınırlamanın yararlı olduğuna inanıyorum çünkü geliştiricilerin içe aktarmada bir yol takma adının ne zaman kullanılacağını ve takma ad yapılandırmalarının nerede bulunabileceğini hızlı bir şekilde belirlemesine olanak tanıyor.
Yaygın olarak kullanılan modüllere daha fazla yol takma adı eklemek için içe imports
alanı aşağıdaki gibi değiştirilebilir:
{ "name": "my-awesome-project", "imports": { "#modules/*": "./path/to/modules/*", "#logger": "./src/shared/lib/logger.js", "#*": "./src/*" } }
Makaleyi "geri kalan her şey kutudan çıktığı gibi çalışacak" ifadesiyle bitirmek ideal olacaktır. Ancak gerçekte imports
alanını kullanmayı planlıyorsanız bazı zorluklarla karşılaşabilirsiniz.
CommonJS modülleriyle yol takma adları kullanmayı planlıyorsanız size kötü haberlerim var: Aşağıdaki kod çalışmayacaktır.
const { apiClient } = require('#shared/api'); const { ProductView } = require('#entities/product/components/ProductView'); const { addProductToCart } = require('#features/add-to-cart/actions');
Node.js'de yol takma adlarını kullanırken ESM dünyasındaki modül çözümleme kurallarına uymalısınız. Bu, hem ES modülleri hem de CommonJS modülleri için geçerlidir ve karşılanması gereken iki yeni gereksinimle sonuçlanır:
Dosya uzantısı da dahil olmak üzere dosyanın tam yolunu belirtmek gerekir.
Bir dizine giden yolu belirtmeye ve bir index.js
dosyasını içe aktarmayı beklemeye izin verilmez. Bunun yerine index.js
dosyasının tam yolunun belirtilmesi gerekir.
Node.js'nin modülleri doğru şekilde çözümleyebilmesini sağlamak için içe aktarma işlemlerinin aşağıdaki şekilde düzeltilmesi gerekir:
const { apiClient } = require('#shared/api/index.js'); const { ProductView } = require('#entities/product/components/ProductView.js'); const { addProductToCart } = require('#features/add-to-cart/actions/index.js');
Bu sınırlamalar, birçok CommonJS modülü bulunan bir projede imports
alanını yapılandırırken sorunlara yol açabilir. Ancak halihazırda ES modüllerini kullanıyorsanız kodunuz tüm gereksinimleri karşılıyor demektir.
Ayrıca, bir paketleyici kullanarak kod oluşturuyorsanız bu sınırlamaları atlayabilirsiniz. Bunu nasıl yapacağımızı aşağıda tartışacağız.
Tür denetimi amacıyla içe aktarılan modülleri doğru şekilde çözümlemek için TypeScript'in imports
alanını desteklemesi gerekir. Bu özellik 4.8.1 sürümünden itibaren desteklenir , ancak yalnızca yukarıda listelenen Node.js sınırlamaları karşılanırsa desteklenir.
Modül çözümlemesi amacıyla imports
alanını kullanmak için tsconfig.json
dosyasında birkaç seçeneğin yapılandırılması gerekir.
{ "compilerOptions": { /* Specify what module code is generated. */ "module": "esnext", /* Specify how TypeScript looks up a file from a given module specifier. */ "moduleResolution": "nodenext" } }
Bu yapılandırma, imports
alanının Node.js'dekiyle aynı şekilde çalışmasını sağlar. Bu, modül içe aktarma işlemine bir dosya uzantısı eklemeyi unutursanız TypeScript'in sizi bu konuda uyaran bir hata oluşturacağı anlamına gelir.
// OK import { apiClient } from '#shared/api/index.js'; // Error: Cannot find module '#src/shared/api/index' or its corresponding type declarations. import { apiClient } from '#shared/api/index'; // Error: Cannot find module '#src/shared/api' or its corresponding type declarations. import { apiClient } from '#shared/api'; // Error: Relative import paths need explicit file extensions in EcmaScript imports when '--moduleResolution' is 'node16' or 'nodenext'. Did you mean './relative.js'? import { foo } from './relative';
Projelerimin çoğu kod oluşturmak için bir paketleyici kullandığından ve modülleri içe aktarırken hiçbir zaman dosya uzantıları eklemediğimden, tüm içe aktarma işlemlerini yeniden yazmak istemedim. Bu sınırlamayı aşmak için projeyi aşağıdaki gibi yapılandırmanın bir yolunu buldum:
{ "name": "my-awesome-project", "imports": { "#*": [ "./src/*", "./src/*.ts", "./src/*.tsx", "./src/*.js", "./src/*.jsx", "./src/*/index.ts", "./src/*/index.tsx", "./src/*/index.js", "./src/*/index.jsx" ] } }
Bu yapılandırma, uzantıları belirtmeye gerek kalmadan modüllerin olağan şekilde içe aktarılmasına olanak tanır. Bu, bir içe aktarma yolu bir dizine işaret ettiğinde bile işe yarar.
// OK import { apiClient } from '#shared/api/index.js'; // OK import { apiClient } from '#shared/api/index'; // OK import { apiClient } from '#shared/api'; // Error: Relative import paths need explicit file extensions in EcmaScript imports when '--moduleResolution' is 'node16' or 'nodenext'. Did you mean './relative.js'? import { foo } from './relative';
Göreli bir yol kullanarak içe aktarmayla ilgili geriye kalan bir sorunumuz var. Bu sorun yol takma adlarıyla ilgili değildir. TypeScript, modül çözümlemesini nodenext
modunu kullanacak şekilde yapılandırdığımız için bir hata veriyor.
Neyse ki, son TypeScript 5.0 sürümüne, içe aktarma işlemlerinin tam yolunu belirtme ihtiyacını ortadan kaldıran yeni bir modül çözünürlük modu eklendi. Bu modu etkinleştirmek için tsconfig.json
dosyasında birkaç seçeneğin yapılandırılması gerekir.
{ "compilerOptions": { /* Specify what module code is generated. */ "module": "esnext", /* Specify how TypeScript looks up a file from a given module specifier. */ "moduleResolution": "bundler" } }
Kurulum tamamlandıktan sonra göreceli yollar için içe aktarma işlemleri her zamanki gibi çalışacaktır.
// OK import { apiClient } from '#shared/api/index.js'; // OK import { apiClient } from '#shared/api/index'; // OK import { apiClient } from '#shared/api'; // OK import { foo } from './relative';
Artık, içe aktarma yollarının nasıl yazılacağına ilişkin herhangi bir ek sınırlama olmaksızın, imports
alanı aracılığıyla yol takma adlarını tam olarak kullanabiliriz.
tsc
derleyicisini kullanarak kaynak kodu oluştururken ek yapılandırma gerekli olabilir. TypeScript'in sınırlamalarından biri, imports
alanı kullanılırken CommonJS modülü biçiminde bir kod oluşturulamamasıdır.
Bu nedenle Node.js'de derlenmiş kodun çalıştırılabilmesi için kodun ESM formatında derlenmesi ve package.json
dosyasına type
alanının eklenmesi gerekmektedir.
{ "name": "my-awesome-project", "type": "module", "imports": { "#*": "./src/*" } }
Kodunuz build/
gibi ayrı bir dizinde derlendiyse, yol takma adı src/
gibi orijinal konumu işaret edeceğinden modül Node.js tarafından bulunamayabilir. Bu sorunu çözmek için package.json
dosyasında koşullu içe aktarma yolları kullanılabilir.
Bu, önceden oluşturulmuş kodun src/
dizini yerine build/
dizininden içe aktarılmasına olanak tanır.
{ "name": "my-awesome-project", "type": "module", "imports": { "#*": { "default": "./src/*", "production": "./build/*" } } }
Belirli bir içe aktarma koşulunu kullanmak için Node.js'nin --conditions
bayrağıyla başlatılması gerekir.
node --conditions=production build/index.js
Kod paketleyicileri genellikle Node.js'de yerleşik olan yerine kendi modül çözümleme uygulamalarını kullanır. Bu nedenle imports
alanına yönelik destekleri hayata geçirmeleri önemli.
Projelerimde Webpack, Rollup ve Vite ile yol takma adlarını test ettim ve bulgularımı paylaşmaya hazırım.
Paketleyicileri test etmek için kullandığım yol takma adı yapılandırmasını burada bulabilirsiniz. İçe aktarılan dosyaların tam yolunu belirtmek zorunda kalmamak için TypeScript ile aynı yöntemi kullandım.
{ "name": "my-awesome-project", "type": "module", "imports": { "#*": [ "./src/*", "./src/*.ts", "./src/*.tsx", "./src/*.js", "./src/*.jsx", "./src/*/index.ts", "./src/*/index.tsx", "./src/*/index.js", "./src/*/index.jsx" ] } }
Webpack v5.0'dan itibaren imports
alanını desteklemektedir . Yol takma adları herhangi bir ek yapılandırma gerekmeden çalışır. TypeScript ile bir test projesi oluşturmak için kullandığım Webpack yapılandırması:
const config = { mode: 'development', devtool: false, entry: './src/index.ts', module: { rules: [ { test: /\.tsx?$/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-typescript'], }, }, }, ], }, resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx'], }, }; export default config;
Vite 4.2.0 sürümüne imports
alanı desteği eklendi . Ancak 4.3.3 sürümünde önemli bir hata giderildiğinden en azından bu sürümün kullanılması öneriliyor. Vite'ta yol takma adları, hem dev
hem de build
modlarında ek yapılandırmaya ihtiyaç duymadan çalışır.
Bu nedenle tamamen boş konfigürasyona sahip bir test projesi oluşturdum.
Vite'ın içinde Rollup kullanılmasına rağmen içe imports
alanı kutunun dışında çalışmıyor. Etkinleştirmek için @rollup/plugin-node-resolve
eklentisinin 11.1.0 veya üzeri sürümünü yüklemeniz gerekir. İşte örnek bir yapılandırma:
import { nodeResolve } from '@rollup/plugin-node-resolve'; import { babel } from '@rollup/plugin-babel'; export default [ { input: 'src/index.ts', output: { name: 'mylib', file: 'build.js', format: 'es', }, plugins: [ nodeResolve({ extensions: ['.ts', '.tsx', '.js', '.jsx'], }), babel({ presets: ['@babel/preset-typescript'], extensions: ['.ts', '.tsx', '.js', '.jsx'], }), ], }, ];
Maalesef bu yapılandırmayla yol takma adları yalnızca Node.js sınırlamaları dahilinde çalışır. Bu, uzantı dahil olmak üzere tam dosya yolunu belirtmeniz gerektiği anlamına gelir. Toplama dizideki yalnızca ilk yolu kullandığından içe imports
alanı içinde bir dizi belirtmek bu sınırlamayı atlamaz.
Bu sorunu Rollup eklentilerini kullanarak çözmenin mümkün olduğuna inanıyorum, ancak Rollup'ı öncelikle küçük kütüphaneler için kullandığım için bunu yapmayı denemedim. Benim durumumda proje boyunca içe aktarma yollarını yeniden yazmak daha kolaydı.
Test çalıştırıcıları, büyük ölçüde modül çözümleme mekanizmasına bağlı olan başka bir geliştirme araçları grubudur. Genellikle kod paketleyicilere benzer şekilde kendi modül çözümleme uygulamalarını kullanırlar. Sonuç olarak, imports
alanının beklendiği gibi çalışmama ihtimali vardır.
Neyse ki test ettiğim araçlar iyi çalışıyor. Yol takma adlarını Jest v29.5.0 ve Vite v0.30.1 ile test ettim. Her iki durumda da yol takma adları, herhangi bir ek kurulum veya sınırlama olmaksızın sorunsuz bir şekilde çalıştı. Jest, v29.4.0 sürümünden beri imports
alanını destekliyor .
Vitest'teki destek düzeyi yalnızca en az v4.2.0 olması gereken Vite sürümüne bağlıdır.
Popüler kütüphanelerdeki imports
alanı şu anda iyi desteklenmektedir. Peki ya kod editörleri? Yol takma adlarını kullanan bir projede kod gezinmesini, özellikle "Tanımlamaya Git" işlevini test ettim. Kod düzenleyicilerde bu özelliğe yönelik desteğin bazı sorunları olduğu ortaya çıktı.
VS Code söz konusu olduğunda TypeScript sürümü çok önemlidir. TypeScript Dil Sunucusu, JavaScript ve TypeScript kodunu analiz etmekten ve bunlar arasında gezinmekten sorumludur.
Ayarlarınıza bağlı olarak VS Code, TypeScript'in yerleşik sürümünü veya projenizde yüklü olanı kullanacaktır.
VS Code v1.77.3'teki imports
alanı desteğini TypeScript v5.0.4 ile birlikte test ettim.
VS Code'da yol takma adlarıyla ilgili aşağıdaki sorunlar vardır:
TypeScript, modül çözünürlüğü ayarı nodenext
veya bundler
olarak ayarlanana kadar imports
alanını kullanmaz. Bu nedenle VS Code'da kullanmak için projenizde modül çözünürlüğünü belirtmeniz gerekmektedir.
IntelliSense şu anda imports
alanını kullanarak içe aktarma yolları önerilmesini desteklemiyor. Bu soruna yönelik açık bir konu var.
Her iki sorunu da atlamak için tsconfig.json
dosyasındaki bir yol takma adı yapılandırmasını çoğaltabilirsiniz. TypeScript kullanmıyorsanız aynısını jsconfig.json
dosyasında da yapabilirsiniz.
// tsconfig.json OR jsconfig.json { "compilerOptions": { "baseUrl": "./", "paths": { "#*": ["./src/*"] } } } // package.json { "name": "my-awesome-project", "imports": { "#*": "./src/*" } }
2021.3 sürümünden beri (2022.3.4'te test ettim), WebStorm imports
alanını desteklemektedir . WebStorm kendi kod analizcisini kullandığından bu özellik TypeScript sürümünden bağımsız olarak çalışır. Ancak WebStorm'un yol takma adlarını desteklemeyle ilgili ayrı bir dizi sorunu vardır:
Düzenleyici, yol takma adlarının kullanımı konusunda Node.js tarafından uygulanan kısıtlamalara sıkı sıkıya uyar. Dosya uzantısı açıkça belirtilmezse kodda gezinme çalışmaz. Aynı durum, index.js
dosyasıyla dizinlerin içe aktarılması için de geçerlidir.
WebStorm'da imports
alanında bir dizi yol kullanılmasını engelleyen bir hata var. Bu durumda kod gezintisi tamamen çalışmayı durdurur.
{ "name": "my-awesome-project", // OK "imports": { "#*": "./src/*" }, // This breaks code navigation "imports": { "#*": ["./src/*", "./src/*.ts", "./src/*.tsx"] } }
Neyse ki VS Code'daki tüm sorunları çözen aynı numarayı kullanabiliriz. Özellikle, bir yol takma adı yapılandırmasını tsconfig.json
veya jsconfig.json
dosyasında çoğaltabiliriz. Bu, yol takma adlarının herhangi bir sınırlama olmaksızın kullanılmasına olanak tanır.
Çeşitli projelerde imports
alanını kullanma deneyimlerime ve deneyimlerime dayanarak, farklı türdeki projeler için en iyi yol takma adı yapılandırmalarını belirledim.
Bu yapılandırma, kaynak kodunun Node.js'de ek derleme adımları gerektirmeden çalıştığı projeler için tasarlanmıştır. Kullanmak için şu adımları izleyin:
imports
alanını package.json
dosyasında yapılandırın. Bu durumda çok temel bir konfigürasyon yeterlidir.
Kod gezinmesinin kod düzenleyicilerde çalışması için jsconfig.json
dosyasında yol takma adlarının yapılandırılması gerekir.
// jsconfig.json { "compilerOptions": { "baseUrl": "./", "paths": { "#*": ["./src/*"] } } } // package.json { "name": "my-awesome-project", "imports": { "#*": "./src/*" } }
Bu yapılandırma, kaynak kodunun TypeScript'te yazıldığı ve tsc
derleyicisi kullanılarak oluşturulduğu projeler için kullanılmalıdır. Bu yapılandırmada aşağıdakilerin yapılandırılması önemlidir:
package.json
dosyasındaki içe imports
alanı. Bu durumda, Node.js'nin derlenmiş kodu doğru şekilde çözümlediğinden emin olmak için koşullu yol takma adlarının eklenmesi gerekir.
TypeScript, imports
alanını kullanırken kodu yalnızca ESM biçiminde derleyebildiğinden, package.json
dosyasında ESM paket biçiminin etkinleştirilmesi gereklidir.
Bir tsconfig.json
dosyasında ESM modül biçimini ve moduleResolution
ayarlayın. Bu, TypeScript'in içe aktarma sırasında unutulan dosya uzantılarını önermesine olanak tanır. Bir dosya uzantısı belirtilmezse derleme sonrasında kod Node.js'de çalışmayacaktır.
Kod düzenleyicilerinde kod gezinmesini düzeltmek için yol takma adlarının bir tsconfig.json
dosyasında tekrarlanması gerekir.
// tsconfig.json { "compilerOptions": { "module": "esnext", "moduleResolution": "nodenext", "baseUrl": "./", "paths": { "#*": ["./src/*"] }, "outDir": "./build" } } // package.json { "name": "my-awesome-project", "type": "module", "imports": { "#*": { "default": "./src/*", "production": "./build/*" } } }
Bu yapılandırma, kaynak kodunun paketlendiği projeler için tasarlanmıştır. Bu durumda TypeScript gerekli değildir. Mevcut değilse tüm ayarlar bir jsconfig.json
dosyasında yapılabilir.
Bu yapılandırmanın ana özelliği, içe aktarma sırasında dosya uzantılarının belirlenmesine ilişkin Node.js sınırlamalarını atlamanıza izin vermesidir.
Aşağıdakileri yapılandırmak önemlidir:
imports
alanını package.json
dosyasında yapılandırın. Bu durumda, her takma ada bir dizi yol eklemeniz gerekir. Bu, paketleyicinin dosya uzantısının belirtilmesine gerek kalmadan içe aktarılan modülü bulmasına olanak tanır.
Kod düzenleyicilerinde kod gezinmesini düzeltmek için tsconfig.json
veya jsconfig.json
dosyasındaki yol takma adlarını tekrarlamanız gerekir.
// tsconfig.json { "compilerOptions": { "baseUrl": "./", "paths": { "#*": ["./src/*"] } } } // package.json { "name": "my-awesome-project", "imports": { "#*": [ "./src/*", "./src/*.ts", "./src/*.tsx", "./src/*.js", "./src/*.jsx", "./src/*/index.ts", "./src/*/index.tsx", "./src/*/index.js", "./src/*/index.jsx" ] } }
Yol takma adlarını imports
alanı aracılığıyla yapılandırmanın, üçüncü taraf kitaplıklar aracılığıyla yapılandırmaya kıyasla hem avantajları hem de dezavantajları vardır. Bu yaklaşım ortak geliştirme araçlarıyla desteklense de (Nisan 2023 itibarıyla) sınırlamaları da vardır.
Bu yöntem aşağıdaki faydaları sunar:
package.json
dosyası) yapılandırılmasını destekler.
Ancak geliştirme araçları geliştikçe ortadan kaldırılacak geçici dezavantajlar da vardır:
imports
alanını destekleme konusunda sorunları vardır. Bu sorunları önlemek için jsconfig.json
dosyasını kullanabilirsiniz. Ancak bu, yol takma adı yapılandırmasının iki dosyada çoğaltılmasına yol açar.
imports
alanıyla birlikte çalışmayabilir. Örneğin, Rollup ek eklentilerin kurulumunu gerektirir.
imports
alanının kullanılması, içe aktarma yollarına yeni kısıtlamalar ekler. Bu kısıtlamalar ES modülleriyle aynıdır ancak imports
alanını kullanmaya başlamayı daha zor hale getirebilirler.
Peki yol takma adlarını yapılandırmak için içe imports
alanını kullanmaya değer mi? Yeni projeler için evet, üçüncü taraf kütüphaneler yerine bu yöntemin kullanılmaya değer olduğuna inanıyorum.
imports
alanı, geleneksel yapılandırma yöntemleriyle karşılaştırıldığında önemli avantajlar sunduğundan, önümüzdeki yıllarda birçok geliştirici için yol takma adlarını yapılandırmanın standart bir yolu haline gelme şansına sahip.
Ancak, yapılandırılmış yol takma adlarına sahip bir projeniz zaten varsa, imports
alanına geçiş yapmak önemli bir fayda sağlamayacaktır.
Umarım bu makaleden yeni bir şeyler öğrenmişsinizdir. Okuduğunuz için teşekkürler!
Burada da yayınlandı