Node.JS'de yüklediğim bir modülün yolunu nasıl alabilirim ki * benim değil * (yani bazı düğüm_modüllerinde)


94

Npm aracılığıyla kurulmuş bir modüle ihtiyacım var. Bu modüle bağlı bir .js dosyasına erişmek istiyorum (böylece içindeki bir Oluşturucu yöntemini alt sınıflara ayırabilirim). Modülün kodunu değiştiremiyorum (pekala, istemiyorum), bu yüzden onun __dirname'sini çıkarmak için bir yerim yok.

Aşağıdaki sorunun farkındayım, ancak bu, üzerinde kod kontrolü olan bir modülün yolunu almakla ilgilidir (dolayısıyla __dirname çözümdür): Node.js'de "this" modülünün yolunu nasıl söyleyebilirim?

~~~

Daha da iyisi, modülün yüklü modül bilgilerini almaktır


modülü herhangi bir hatasız olarak gereksinim ('modulename') ile nereye yükleyebilirsiniz?
Futur

daha iyi açıklayabilir misin? bazı kodlar?
Gabriel Llamas

Yanıtlar:


130

Sorunuzu doğru anladıysam , require.resolve () kullanmalısınız :

Bir modülün konumunu aramak için dahili require () makinesini kullanın, ancak modülü yüklemek yerine çözümlenmiş dosya adını döndürün.

Misal: var pathToModule = require.resolve('module');


13
Bu yanıt, tüm düğüm modüllerinde güvenilir bir şekilde çalışmaz. Cevabımı gör.
Jason

62

need.resolve () kısmi bir cevaptır. Kabul edilen cevap birçok düğüm modülü için işe yarayabilir, ancak hepsi için işe yaramayacaktır.

require.resolve("moduleName")size modülün kurulu olduğu dizini vermez; mainmodülün özniteliğinde tanımlanan dosyanın konumunu verir package.json.

Bu olabilir moduleName/index.jsveya olabilir moduleName/lib/moduleName.js. İkinci durumda, path.dirname(require.resolve("moduleName"))istemeyebileceğiniz veya beklemeyebileceğiniz bir dizini döndürür:node_modules/moduleName/lib

Belirli bir modülün tam yolunu elde etmenin doğru yolu dosya adını çözmektir:

let readmePath = require.resolve("moduleName/README.md");

Eğer sadece modülün dizinini istiyorsanız (belki çok fazla path.join()arama yapacaksınız ), o package.jsonzaman - ki bu her zaman projenin kökünde olmalıdır - ve şuna geçin path.dirname():

let packagePath = path.dirname(require.resolve("moduleName/package.json"));

1
package.jsondosyayı algılayarak çok akıllıca bir cevap . path.join('moduleName', 'package.json')Windows uyumlu olmanız gerekmez mi ?
João Pimentel Ferreira

2
@ JoãoPimentelFerreira require.resolve, tıpkı requirekullanılması gerekmediği gibi platformdan bağımsızdırpath.join
Gopikrishna S

1
Kullanmadan const path = require('path');önce eklemeyi unutmayın path.dirname.
GOTO 0

Bu cevabın tamamen doğru olmasını dilerdim! require.resolve('@scope/module')Bana benzer bir şeyi veren gibi bir şeyi başarıyla çözebilirim /path/to/@scope/module/dist/index.js, ancak çalıştırmayı require.resolve('@scope/module/package.json')denersem bir MODULE_NOT_FOUNDhata atar . Düğüm 14.4.0'deyim ve çözmeye çalıştığım modül "type": "module", package.json'da exportsiçermeyen bir alana sahip package.json. Bunun bununla bir ilgisi olup olmadığından emin değilim ...
trusktr

Sorunu buldum: bir modül olduğunda type: module, görünüşe göre sahada package.jsonaçıkça açığa çıkması gerekiyor exports. Node'un yeni ESM özelliğinin requireher zamanki gibi yolları çözmeyi engellemediğini düşündüm , ama öyle görünüyor.
trusktr

3

Bilginize, require.resolvemodül tanımlayıcısını CommonJS'ye göre döndürür. Node.js'de bu dosya adıdır. Gelen WebPack bu bir sayıdır.

Web paketi durumunda, modül yolunu bulmak için benim çözümüm:

const pathToModule = require.resolve('module/to/require');
console.log('pathToModule is', pathToModule); // a number, eg. 8
console.log('__webpack_modules__[pathToModule] is', __webpack_modules__[pathToModule]);

Sonra __webpack_modules__[pathToModule]şöyle bir bilgi aldım:

(function(module, exports, __webpack_require__) {

    eval("module.exports = (__webpack_require__(6))(85);\n\n//////////////////\n// 
    WEBPACK FOOTER\n// delegated ./node_modules/echarts/lib/echarts.js from dll-reference vendor_da75d351571a5de37e2e\n// module id = 8\n// module chunks = 0\n\n//# sourceURL=webpack:///delegated_./node_modules/echarts/lib/echarts.js_from_dll-reference_vendor_da75d351571a5de37e2e?");

    /***/
})

Güncellenen modül dosyamın beklediğim gibi çalışmaması için önceki dll oluşturma dosyasından (daha hızlı derleme hızı için) eski komut dosyalarına ihtiyacım olduğu ortaya çıktı. Sonunda dll dosyamı yeniden oluşturdum ve sorunumu çözdüm.

Referans: Çözümlenmiş dosya yolunu (düğüm) almak için kullanmarequire.resolve


2

Umarım ihtiyaçlarınızı doğru anlarım: bazı modüllerin giriş noktası dosyasını almak için. Diyelim ki jugglingdbmodülün giriş noktasını almak istiyorsunuz :

node
> require('module')._resolveFilename('jugglingdb')
'/usr/local/lib/node_modules/jugglingdb/index.js'

Gördüğünüz gibi, bu modül hakkında bu tür bilgileri almanın "resmi" yolu değildir, bu nedenle bu işlevin davranışı sürümden sürüme değişebilir. Düğüm kaynağında buldum: https://github.com/joyent/node/blob/master/lib/module.js#L280


2

@Anatoliy çözümüne göre, MacOS XI'de arama yollarını yapıyor bulduk

require('module')._resolveLookupPaths('myModule')

bu yüzden çözülmüş arama yollarını alıyorum

[ 'myModule',
  [ '/Users/admin/.node_modules',
    '/Users/admin/.node_libraries',
    '/usr/local/lib/node' ] ]

oysa

require('module')._resolveFilename('myModule')

zaten aradığım modülü çözmeyecek, aslında çılgınca olan şey _loadmodülü çözmeyecek olmasıdır:

> require('module')._load('myModule')
Error: Cannot find module 'myModule'
    at Function.Module._resolveFilename (module.js:440:15)
    at Function.Module._load (module.js:388:25)
    at repl:1:19
    at sigintHandlersWrap (vm.js:32:31)
    at sigintHandlersWrap (vm.js:96:12)
    at ContextifyScript.Script.runInContext (vm.js:31:12)
    at REPLServer.defaultEval (repl.js:308:29)
    at bound (domain.js:280:14)
    at REPLServer.runBound [as eval] (domain.js:293:12)
    at REPLServer.<anonymous> (repl.js:489:10)

requirevasiyet sırasında :

> require('myModule')

ama bu modül bende yok

myProject/node_modules/
myProject/node_modules/@scope/
/usr/local/lib/node_modules/
/usr/local/lib/node_modules/@scope
/usr/local/lib/node_modules/npm/node_modules/
/usr/local/lib/node_modules/npm/node_modules/@scope
$HOME/.npm/
$HOME/.npm/@scope/

peki bu modül nerede ???

Önce bir yapmak zorunda kaldım $ sudo /usr/libexec/locate.updatedb Sonra biraz kahveden sonra yaptım locate myModuleya da daha iyisilocate myModule/someFile.js

et voilà, projemin üst klasöründe, yani proje kök klasörümün dışında olduğu ortaya çıktı:

$pwd
/Users/admin/Projects/Node/myProject
$ ls ../../node_modules/myModule/

Dolayısıyla da kaçınamaz rm -rf ../../node_modules/myModule/ve taze bir npm install.

Hiç kimsenin npm, çalışmasının beklendiği proje kök klasörümden veya varsayılan modül arama yolundan başka bir yerde modülleri aramak için bilgisayarımı taramasını istemediğini iddia edebilirim .


1

Belki de aradığınız şey budur, kontrol edin:

required.main.filename


1

Jason'ın cevabı, Node.js ESM ve exportssaha ortaya çıkana kadar en iyi cevaptı .

Artık Node , paket yazarı açıkça ifşa etmeye karar vermedikçe dosyaların çözülebilir olmasını önleyen bir exportsalana sahip paketleri desteklediğine göre , Jason'ın cevabındaki hile açıkça açığa çıkmayan paketler için başarısız olacaktır .package.jsonpackage.json

resolve-package-pathHile yapan bir paket var .

İşte nasıl kullanılacağı:

const resolvePkg = require('resolve-package-path')

console.log(resolvePkg('@some/package'))

böyle bir şey çıkaracak

/path/to/@some/package/package.json

paketin exportsalanının ne içerdiğinden bağımsız olarak .


Bir yazar modülün içeriğinin bir kısmını bilinçli olarak dışa aktardığında, daha da sarsıcı bir zeminde olduğunuzu sanıyorum, çünkü artık yazar resmi olarak ortak arayüzünü tanımladı. Bence bu, açıkça ihraç edilmeyen şeylerin daha agresif bir şekilde yeniden düzenlenmesiyle sonuçlanma eğilimindedir, değil mi?
Jason

@Jason Bu kaynak dosyalar için doğru, ancak package.json dosyaları gitmiyor. Bunların içe aktarılmaması için herhangi bir neden görmüyorum.
trusktr
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.