Di node.JS bagaimana saya bisa mendapatkan jalur modul yang telah saya muat melalui Requirement yang * bukan * milik saya (yaitu di beberapa node_module)

94

Saya membutuhkan modul yang diinstal melalui npm. Saya ingin mengakses file .js bawahan ke modul itu (jadi saya bisa membuat subclass metode Konstruktor di dalamnya). Saya tidak bisa (yah, tidak mau) memodifikasi kode modul, jadi tidak punya tempat untuk mengekstrak __dirname-nya.

Saya mengetahui pertanyaan berikut, tetapi ini tentang mendapatkan jalur modul yang memiliki kontrol kode (karenanya, __dirname adalah solusinya): Di Node.js, bagaimana saya dapat mengetahui jalur modul `ini`?

~~~

Bahkan lebih baik mendapatkan info modul yang dimuat modul

Zhami
sumber
di mana Anda dapat memuat modul tanpa kesalahan dengan require ('modulename')?
Futur
bisakah kamu menjelaskannya dengan lebih baik? beberapa kode?
Gabriel Llamas

Jawaban:

130

Jika saya benar-benar memahami pertanyaan Anda, Anda harus menggunakan require.resolve () :

Gunakan mesin require () internal untuk mencari lokasi modul, tetapi alih-alih memuat modul, cukup kembalikan nama file yang telah diselesaikan.

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

Linus Thiel
sumber
13
Jawaban ini tidak dapat diandalkan dengan semua modul node. Lihat jawabanku.
Jason
62

Requirement.resolve () adalah jawaban parsial. Jawaban yang diterima mungkin berfungsi untuk banyak modul node, tetapi tidak akan berfungsi untuk semuanya.

require.resolve("moduleName")tidak memberi Anda direktori tempat modul diinstal; ini memberi Anda lokasi file yang ditentukan dalam mainatribut di modul package.json.

Bisa jadi moduleName/index.jsatau bisa juga moduleName/lib/moduleName.js. Dalam kasus terakhir, path.dirname(require.resolve("moduleName"))akan mengembalikan direktori yang mungkin tidak Anda inginkan atau harapkan:node_modules/moduleName/lib

Cara yang benar untuk mendapatkan jalur lengkap ke modul tertentu adalah dengan menyelesaikan nama file:

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

Jika Anda hanya menginginkan direktori untuk modul (mungkin Anda akan membuat banyak path.join()panggilan), selesaikan package.json- yang harus selalu berada di root proyek - dan teruskan ke path.dirname():

let packagePath = path.dirname(require.resolve("moduleName/package.json"));
Jason
sumber
1
jawaban yang sangat pintar, dengan mendeteksi package.jsonfile tersebut. Tidakkah seharusnya Anda menggunakan path.join('moduleName', 'package.json')karena kompatibel dengan Windows?
João Pimentel Ferreira
2
@ JoãoPimentelFerreira require.resolveadalah platform agnostik, requiresehingga tidak perlu digunakanpath.join
Gopikrishna S
1
Jangan lupa tambahkan const path = require('path');sebelum menggunakan path.dirname.
GOTO 0
Saya berharap jawaban ini sepenuhnya benar! Saya berhasil menyelesaikan sesuatu seperti require.resolve('@scope/module')yang memberi saya sesuatu seperti itu /path/to/@scope/module/dist/index.js, namun jika saya mencoba menjalankannya require.resolve('@scope/module/package.json')akan muncul MODULE_NOT_FOUNDkesalahan. Saya menggunakan Node 14.4.0, dan modul yang saya coba selesaikan ada "type": "module"di package.json dengan exportsbidang yang tidak disertakan package.json. Tidak yakin apakah itu ada hubungannya dengan itu ...
trusktr
Saya menemukan masalah: ketika sebuah modul type: module, tampaknya package.jsonharus diekspos secara eksplisit di exportslapangan. Saya pikir fitur ESM baru Node tidak memblokir requiredari jalur penyelesaian seperti biasa, tetapi ternyata memang demikian.
trusktr
3

FYI, require.resolvemengembalikan pengenal modul sesuai dengan CommonJS. Di node.js ini adalah nama file. Di webpack ini adalah angka.

Dalam situasi webpack , berikut adalah solusi saya untuk mengetahui jalur modul:

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]);

Kemudian dari __webpack_modules__[pathToModule]saya mendapat informasi seperti ini:

(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?");

    /***/
})

Ternyata saya membutuhkan skrip lama dari file dll build sebelumnya (untuk kecepatan build lebih cepat), sehingga file modul yang saya perbarui tidak berfungsi seperti yang saya harapkan. Akhirnya saya membangun kembali file dll saya dan memecahkan masalah saya.

Ref: Menggunakan require.resolveuntuk menyelesaikan jalur file (node)

Alexee
sumber
2

Saya harap saya benar-benar memahami kebutuhan Anda: untuk mendapatkan file titik masuk dari beberapa modul. Katakanlah Anda ingin mendapatkan titik masuk jugglingdbmodul:

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

Seperti yang Anda lihat, ini bukan cara "resmi" untuk mendapatkan informasi semacam ini tentang modul, jadi perilaku fungsi ini dapat berubah dari versi ke versi. Saya telah menemukannya di sumber node: https://github.com/joyent/node/blob/master/lib/module.js#L280

Anatoliy
sumber
2

Menurut solusi @anatoliy, Di MacOS XI telah menemukan jalur pencarian yang dilakukan

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

jadi saya mendapatkan jalur pencarian terselesaikan

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

sedangkan

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

tidak akan menyelesaikan modul yang saya cari, pada kenyataannya yang gila adalah bahwa _loadmodul tidak akan menyelesaikan:

> 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)

sedangkan requirekeinginan:

> require('myModule')

tapi saya tidak memiliki modul ini

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/

jadi dimana modul ini ???

Pertama saya harus melakukan a. $ sudo /usr/libexec/locate.updatedb Kemudian setelah minum kopi saya lakukan locate myModuleatau lebih baiklocate myModule/someFile.js

et voilà, ternyata itu ada di folder induk proyek saya yaitu di luar folder root proyek saya:

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

sehingga Anda tidak dapat menghindari rm -rf ../../node_modules/myModule/dan segar npm install.

Saya dapat berargumen bahwa tidak ada yang menginstruksikan npmuntuk memindai komputer saya untuk mencari modul di tempat lain selain folder root proyek saya yang seharusnya dijalankan atau di jalur pencarian modul default.

loretoparisi
sumber
1

Ini mungkin yang Anda cari, periksa:

Requirement.main.filename

IvanM
sumber
1

Jawaban Jason adalah jawaban terbaik, sampai Node.js ESM dan exportsfield keluar.

Sekarang Node mendukung paket dengan exportsbidang yang secara default akan mencegah file seperti package.jsondapat diatasi kecuali pembuat paket secara eksplisit memutuskan untuk mengekspos mereka, trik dalam jawaban Jason akan gagal untuk paket yang tidak secara eksplisit mengekspos package.json.

Ada sebuah paket bernama resolve-package-pathyang melakukan trik.

Berikut cara menggunakannya:

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

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

yang akan menghasilkan sesuatu seperti

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

terlepas dari isi exportsbidang paket .

trusktr.dll
sumber
Saya menduga bahwa begitu seorang penulis secara sadar mengekspor sebagian dari isi modul, Anda berada di tempat yang lebih goyah, karena sekarang penulis telah secara resmi mendefinisikan antarmuka publik mereka. Itu akan, menurut saya, cenderung menghasilkan pemfaktoran ulang yang lebih agresif pada hal-hal yang tidak diekspor secara eksplisit, bukan?
Jason
@Jason Itu benar untuk file sumber, tetapi file package.json tidak akan hilang. Saya tidak melihat alasan mengapa mereka harus disembunyikan dari impor.
trusktr