javascript - Belirli bir modülün CommonJS modülü mü yoksa ES6 modülü mü olduğunu nasıl anlayabilirim?


NodeJS kullanan bir Azure Function'ım var ve başka bir ekip tarafından yayınlanmış bir npm modülünü kullanmaya çalışıyorum. İlgili modülü npm ile ekledikten sonra, şu şekilde kullanmayı deniyorum:

import * as Model from "@thing/app-model";
...
const appModel: Model.TheModel = new Model.TheModel([]);

Ancak, Azure Function'ı çalıştırmaya çalıştığımda bu hatayı alıyorum:

[error] Worker was unable to load function pump: 'SyntaxError: Unexpected token export'

Çevrimiçi olarak bulabildiğim o hata mesajıyla ilgili sonuçlar, bu hatanın genellikle bir ES6 modülünü kullanmaya çalıştığımı gösterdiğini söylüyor, bu Node'un desteklemediği bir şey (bundan dolayı bir CommonJS modülünü kullanmam gerekiyor). Zor olan şey ise modülün ASLINDA bir CommonJS modülü olduğunu düşünmemdi. Modülü üreten projenin tsconfig.json dosyasında, compilerOptions bölümünde şu satır bulunuyor:

"module": "commonjs"

ES6 ile CommonJS sorununu doğrulamak veya elemek için, Azure Function'ımın node_modules dizininde ithal edilen modüle bakarsam, ona bakarak bunun bir ES6 modülü mü yoksa bir CommonJS modülü mü olduğunu anlamanın bir yolu var mı?

Teşekkürler!

Cevap #1

Node'daki modüller yalnızca bir ay öncesine göre çok farklı ve 18-20 ay öncesine göre çok daha farklı. HAZİRAN 2022 itibarıyla bu, bir TS-Node paketini incelemek ve paketin modül türünü çıkarsamak için en güncel yöntemdir.

Denetlenen paket, cjs, esm veya her ikisi (cjs ve esm) olabilir

Artık TypeScript kullanarak bir CJS modülü ve tek bir TS-Node kod tabanından (veya isterseniz proje) bir ESM modülü oluşturmak mümkün. Aslında, her iki modül türünü de sürdürecekseniz, bir transpilere sahip olmak neredeyse bir gerekliliktir (ne yazık ki bu konuyu daha detaylı anlatamam, çünkü böyle bir konu orijinal sorunun kapsamını aşıyor).

Dikkate Alınmalıdır: Bir TS-Node paketinden bir modül türünü nasıl çıkaracağını bilmek, TS-Node paketlerini farklı modül türleri olarak nasıl yapılandıracağını bilmeye yakın bir bilgidir.

Bir TS-Node Paketinin Modül Türü 2 Dosyadan Çıkarılabilir

  1. The package.json
  2. tsconfig.json
package.json Dosyasında

..."type" özelliği, modül türünün tanımlandığı yerdir. Burada önemli olan nokta, Node.js'in modülün türünü ve proje içindeki modüllerin nasıl çözülmesi gerektiğini de buradan çıkaracağıdır. TypeScript, Çalışma Zamanında mevcut değildir; Node.js ise Çalışma Zamanı Ortamıdır. Node.js ÇRO olduğu için package.json'a bakıp modül türünü buradan çıkarmak biraz daha somut olsa da, hikâye burada bitmemektedir. JavaScript Modülleri artık karmaşık bir konu hâline gelmiştir.

Devam etmeden önce, bir ESM yapılandırması için bir package.json dosyasına bakalım. :

ESM Yapılandırılmış package.json
// FILE: "./package.json"

  {
    "name": "foo-pkg-bar"
    "version": "1.23.4",
    "type": "module", // <-- You're Looking for this K/V pair
    "license": "MIT",
    "desc": "some description here...", 
    /* 
        ...rest of the JSON-file's properties... 
    */
  }

Modül bir ES-Module veya (ESM) olduğunda, package.json özelliği "module" olarak ayarlanmış olacaktır.

Bir CommonJS Modülü (veya CJS Modülü) içinde yapılandırmanın açık olması gerekmez. Bu, package.json dosyasındaki "type" özelliğinin tamamen bırakılabileceği anlamına gelir ve bu oldukça yaygın durumda modül türü varsayılan olarak CJS olur. Ancak, "type" özelliği modül türünü CJS olarak açık bir şekilde belirtmek için yapılandırılabilir, bu durumda "type" özelliği şöyle görünür:

{
   name: "foobar-foofoo-head",
   version: 1.23.4,
   type: "commonjs"
}

Birden Fazla Package.json Dosyası

Çoğu zaman, ve çift modül tipli paketlerde (hem ESM hem de CJS ortamlarını destekleyecek şekilde oluşturulmuş paketler), birden fazla package.json dosyası olabilir. Çift modül tipli bir pakette, ESM derlemesinin, aşağıda gösterildiği gibi tek bir özellik eklenmiş bir package.json dosyası olacaktır.

// package.json for the ESM build
{
  "type": "module"
}

CJS ayrıca kendi type package.json dosyasına sahip olacak ve buna tek bir özellik eklenecek (aşağıya bakın).

// package.json for the CJS build
{
  "type": "commonjs"
}

package.json dosyasının geri kalanı ROOT-package.json dosyasında olacak. Böyle bir durumda dosya yapısı şöyle görünecek.

├── build
│   ├── cjs
│   │   ├── lib
│   │   │   ├── project-stuff.d.ts
│   │   │   └── project-stuff.js
│   │   ├── main.cjs
│   │   ├── main.d.cts
│   │   └── package.json        // <-- CJS "package.json"
│   └── esm
│       ├── lib
│       │   ├── project-stuff.d.ts
│       │   └── project-stuff.js
│       ├── main.d.mts
│       ├── main.mjs
│       └── package.json        // <-- ESM "package.json"
├── package.json                // <-- ROOT "package.json"
├── package-lock.json
├── src
│   ├── lib
│   │   └── project-stuff.ts
│   ├── main.cts
│   └── main.mts
├── tsconfig.base.json
├── tsconfig.cjs.json
└── tsconfig.esm.json


Yukarıdaki aslında kendime her iki modül türüne de nasıl transpile yapacağımı öğretmek için oluşturduğum projeden.

Muhtemelen birçok tsconfig.json dosyasına dikkat etmişsinizdir?

Dürüst olmak gerekirse, eğer o isimlendirme kuralına sahip tsconfig dosyalarını görüyorsanız, daha fazla incelemenize gerek yok, kesinlikle bir CJS veya bir ESM modülü olarak kullanılabilir (çalışan bir paket olduğunu varsayarsak).

Paketteki Modül türü için TSConfig'i İnceleme

TSConfig, herhangi bir TS/Node projesinin hangi modül tipinde olduğunu çıkarsamak için de kullanılabilir. TSConfig'i açın ve Modül & Modül çözümleme özelliklerini arayın.

TS v4.7, Node/TS projelerinde ESM desteğini kolaylaştırdı

TypeScript kullanılarak derlenen Node paketlerinde ESM desteği, tsconfig.json dosyası yapılandırma özelliklerine "module" ve "moduleResolution" için geçerli değerler eklenmesiyle kolaylaştırıldı

"module" ve modül çözümü artık yeni değerleri kabul edebilir
  1. node12 (üst düzey await yok),
  2. node16 (LTS node16 sürümü için uygulanan ESM standardı) &
  3. nodenext(en güncel ESM standardı)

Eğer module ve moduleResolution özelliklerinin bu değerlerde ayarlandığını görüyorsanız, proje bir ES-Module olarak derleniyor demektir.

CJS ve ESM

Modüller hem CJS hem de ESM olabilir. Eğer bir paket CJS ve ESM olarak derleniyorsa, derlemeler için iki ayrı dizin görmelisiniz.

Her yapım için ayrı package.json dosyaları olmalıdır, bu dosyalar package.json dosyalarının yerleştirilebildiği kademeli dosya yapısından (ör. ağaç benzeri hiyerarşi) yararlanır.

  • Bir temel package.json dosyası olmalıdır.
  • Bir package.json dosyasının "type" özelliği module olarak ayarlanmalıdır
  • diğer package.json dosyasının ise "type" özelliği commonjs olarak ayarlanmış olmalıdır

bu, paketin sadece ESM & CJS'yi desteklemekle kalmayıp, aynı zamanda hem ESM & CJS olduğunu da gösteren bir işarettir

tsconfig.json dosyalarını inceleyerek, modül türünü bir kez daha çıkarabilirsiniz.

Ayrıca birden fazla TSConfig dosyası da olacak. TS Konfigürasyon dosyaları ile ilgili olan şey, isimlendirilme veya yapısal olarak ayarlanmalarında tek bir yolun olmamasıdır. Gördüğüm kadarıyla, çoğu tsconfig.base kullanıyor ve ardından bunu iki başka tsconfig.*.json dosyasına genişletiyor.

Böyle bir şey:

  • tsconfig.base.json dosyası olacak (bunu tsconfig-base.json olarak da gördüm)
  • tsconfig.*.json dosyası CJS için olmalıdır
  • O zaman ESM için de bir tsconfig.*.json dosyası olmalı.

İsimlendirme kuralları statik değildir, oldukça yapılandırılabilir ve özelleştirilebilirler (bu da hepimizin TS hakkında sevdiği şey değil mi?). Buna alışmak bazıları için zor olabilir. İlk başta benim için zordu.

Anahtar, her TSConfig dosyasını okumak ve module ile moduleResolution özelliklerinin neye ayarlandığını görmektir. Eğer modül özelliği "commonjs" olarak ayarlanmış bir tsconfig ve başka bir tsconfig dosyasında module özelliği NodeNext olarak ayarlanmışsa, bu, projenin hem ESM hem de CJS modül türlerine derlendiği anlamına gelir.

Cevap #2

Node_modules klasörünüzde npm paketini bulun ve ardından package.json dosyasını açın.

Paket CommonJs ve/veya ES6'yı destekleyebilir, bu yüzden bir kombinasyonunuz olabilir.

Şunun gibi bir şey görmelisin:

  "main": "dist/index.js",
  "module": "dist/my-module.esm.js",

main genellikle CommonJs sürümüne işaret eder ve module ESM sürümüne işaret eder.

Bu genel bir durumdur ve her zaman doğru değildir. Bazen dosya sonu size her ikisini de destekleyip desteklemediğini gösterebilir, örneğin index.cjs.js, index.esm.js

İlgili makaleler