ใน node.jS ฉันจะหาเส้นทางของโมดูลที่ฉันโหลดผ่านต้องการได้อย่างไรซึ่งก็คือ * ไม่ใช่ * ของฉัน (เช่นในบาง node_module)


94

ฉันต้องการโมดูลที่ติดตั้งผ่าน npm ฉันต้องการเข้าถึงไฟล์. js ย่อยของโมดูลนั้น (ดังนั้นฉันสามารถซับคลาสวิธีการสร้างตัวสร้างได้) ฉันไม่สามารถ (ดีไม่ต้องการ) แก้ไขโค้ดของโมดูลดังนั้นจึงไม่มีที่สำหรับแยก __dirname

ฉันทราบคำถามต่อไปนี้ แต่เกี่ยวกับการรับเส้นทางของโมดูลที่มีการควบคุมโค้ด (ด้วยเหตุนี้ __dirname จึงเป็นวิธีแก้ปัญหา): ใน Node.js ฉันจะบอกเส้นทางของโมดูล "นี้" ได้อย่างไร

~~~

ที่ดีไปกว่านั้นคือการรับข้อมูลโมดูลที่โหลดของโมดูล


คุณสามารถโหลดโมดูลโดยไม่มีข้อผิดพลาดใด ๆ ด้วย require ('modulename')?
Futur

อธิบายให้ดีกว่านี้ได้ไหม โค้ดบ้าง?
Gabriel Llamas

คำตอบ:


130

หากฉันเข้าใจคำถามของคุณอย่างถูกต้องคุณควรใช้require.resolve () :

ใช้เครื่องจักรภายใน require () เพื่อค้นหาตำแหน่งของโมดูล แต่แทนที่จะโหลดโมดูลให้ส่งคืนชื่อไฟล์ที่แก้ไขแล้ว

ตัวอย่าง: var pathToModule = require.resolve('module');


13
คำตอบนี้ใช้ไม่ได้กับโมดูลโหนดทั้งหมดอย่างน่าเชื่อถือ ดูคำตอบของฉัน
Jason

62

need.resolve ()เป็นคำตอบบางส่วน คำตอบที่ยอมรับอาจใช้ได้กับโมดูลโหนดจำนวนมาก แต่จะใช้ไม่ได้กับทุกโมดูล

require.resolve("moduleName")ไม่ให้ไดเร็กทอรีที่ติดตั้งโมดูล จะช่วยให้คุณตำแหน่งของไฟล์ที่กำหนดไว้ในแอตทริบิวต์ในโมดูลmainpackage.json

นั่นอาจเป็นmoduleName/index.jsหรืออาจเป็นได้moduleName/lib/moduleName.jsได้ ในกรณีหลังนี้path.dirname(require.resolve("moduleName"))จะส่งคืนไดเร็กทอรีที่คุณอาจไม่ต้องการหรือคาดหวัง:node_modules/moduleName/lib

วิธีที่ถูกต้องในการรับพา ธ ที่สมบูรณ์ไปยังโมดูลเฉพาะคือการแก้ไขชื่อไฟล์:

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

หากคุณต้องการไดเร็กทอรีสำหรับโมดูล (บางทีคุณอาจจะpath.join()โทรpackage.jsonบ่อยมาก) ให้แก้ไข- ซึ่งจะต้องอยู่ในรูทของโปรเจ็กต์เสมอ - และส่งไปที่path.dirname():

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

1
คำตอบที่ชาญฉลาดมากโดยการตรวจจับpackage.jsonไฟล์ คุณไม่ควรใช้path.join('moduleName', 'package.json')เพื่อให้เข้ากันได้กับ Windows?
João Pimentel Ferreira

2
@ JoãoPimentelFerreira require.resolveเป็นแพลตฟอร์มที่ไม่เชื่อเรื่องพระเจ้าเช่นเดียวกับที่requireไม่จำเป็นต้องใช้path.join
Gopikrishna S

1
อย่าลืมที่จะเพิ่มก่อนที่จะใช้const path = require('path'); path.dirname
GOTO 0

ฉันหวังว่าคำตอบนี้จะเป็นจริง! ฉันสามารถแก้ไขบางสิ่งบางอย่างrequire.resolve('@scope/module')ที่ทำให้ฉัน/path/to/@scope/module/dist/index.jsได้สำเร็จ แต่ถ้าฉันพยายามเรียกใช้require.resolve('@scope/module/package.json')มันจะเกิดMODULE_NOT_FOUNDข้อผิดพลาด ผมอยู่ในโหนด 14.4.0 และโมดูลฉันพยายามที่จะแก้ปัญหาที่มี"type": "module"ใน package.json ของมันที่มีข้อมูลที่ไม่รวมexports package.jsonไม่แน่ใจว่าจะเกี่ยวข้องกับมันหรือไม่ ...
trusktr

ฉันพบปัญหา: เมื่อมีโมดูลtype: moduleแล้วpackage.jsonจะต้องเปิดเผยอย่างชัดเจนในexportsสนาม ฉันคิดว่าคุณสมบัติ ESM ใหม่ของ Node ไม่ได้ปิดกั้นrequireจากการแก้ไขเส้นทางเหมือนปกติ แต่เห็นได้ชัด
trusktr

3

FYI require.resolveส่งคืนตัวระบุโมดูลตาม CommonJS ใน node.js นี่คือชื่อไฟล์ ในwebpackนี่คือตัวเลข

ในสถานการณ์webpackนี่คือทางออกของฉันในการค้นหาเส้นทางโมดูล:

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

จากนั้น__webpack_modules__[pathToModule]ฉันได้ข้อมูลดังนี้:

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

    /***/
})

ปรากฎว่าฉันต้องการสคริปต์เก่าจากไฟล์บิลด์ dll ก่อนหน้า (เพื่อความเร็วในการสร้างที่เร็วขึ้น) ดังนั้นไฟล์โมดูลที่อัปเดตของฉันจึงไม่ทำงานตามที่ฉันคาดไว้ ในที่สุดฉันก็สร้างไฟล์ dll ของฉันใหม่และแก้ไขปัญหาของฉัน

Ref: การใช้require.resolveเพื่อรับเส้นทางไฟล์ที่แก้ไข (โหนด)


2

ฉันหวังว่าฉันจะเข้าใจความต้องการของคุณอย่างถูกต้อง: เพื่อรับไฟล์จุดเข้าใช้งานของโมดูลบางโมดูล สมมติว่าคุณต้องการรับจุดเริ่มต้นของjugglingdbโมดูล:

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

ดังที่คุณเห็นว่านี่ไม่ใช่วิธี "เป็นทางการ" ในการรับข้อมูลประเภทนี้เกี่ยวกับโมดูลดังนั้นพฤติกรรมของฟังก์ชันนี้อาจเปลี่ยนไปจากเวอร์ชันเป็นเวอร์ชัน ฉันพบมันในแหล่งโหนด: https://github.com/joyent/node/blob/master/lib/module.js#L280


2

ตามโซลูชัน @anatoliy บน MacOS XI พบว่าเส้นทางการค้นหากำลังทำอยู่

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

ดังนั้นฉันจึงได้รับเส้นทางการค้นหาที่แก้ไขแล้ว

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

ในขณะที่

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

จะไม่แก้ไขโมดูลที่ฉันกำลังมองหาอีกต่อไปอันที่จริงสิ่งที่บ้าคลั่งคือการ_loadจะไม่แก้ไขโมดูล:

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

ในขณะที่requireจะ:

> require('myModule')

แต่ฉันไม่มีโมดูลนี้

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/

แล้วโมดูลนี้อยู่ที่ไหน ???

ก่อนอื่นฉันต้องทำ$ sudo /usr/libexec/locate.updatedb หลังจากนั้นหลังจากดื่มกาแฟฉันก็ทำได้locate myModuleดีกว่านี้locate myModule/someFile.js

et voilàปรากฏว่ามันอยู่ในโฟลเดอร์หลักของโปรเจ็กต์ของฉันเช่นนอกโฟลเดอร์รูทโปรเจ็กต์ของฉัน:

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

ดังนั้นคุณจึงไม่สามารถหลีกเลี่ยงการและสดrm -rf ../../node_modules/myModule/npm install

ฉันสามารถโต้แย้งว่าไม่มีใครสั่งnpmให้สแกนคอมพิวเตอร์ของฉันในการค้นหาโมดูลที่อื่นนอกจากโฟลเดอร์รูทโปรเจ็กต์ของฉันซึ่งควรจะทำงานหรือในเส้นทางการค้นหาโมดูลเริ่มต้น



1

คำตอบของ Jason เป็นคำตอบที่ดีที่สุดจนกระทั่ง Node.js ESM และexportsฟิลด์ออกมา

ตอนนี้ที่โหนดสนับสนุนแพคเกจที่มีexportsข้อมูลว่าโดยปกติจะป้องกันไม่ให้ไฟล์เช่นpackage.jsonจากการเป็น resolvableเว้นแต่ผู้เขียนแพคเกจอย่างชัดเจนตัดสินใจที่จะให้พวกเขา, package.jsonเคล็ดลับในคำตอบของเจสันจะล้มเหลวสำหรับแพคเกจที่ไม่ชัดเจนเปิดเผย

มีแพคเกจที่เรียกresolve-package-pathว่าเคล็ดลับ

วิธีการใช้งานมีดังนี้

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

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

ซึ่งจะแสดงผลบางอย่างเช่น

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

ไม่ว่าexportsฟิลด์ของแพ็กเกจจะประกอบด้วยอะไร


ฉันสงสัยว่าเมื่อผู้เขียนส่งออกส่วนหนึ่งของเนื้อหาของโมดูลอย่างมีสติคุณก็จะยิ่งสั่นคลอนเพราะตอนนี้ผู้เขียนได้กำหนดอินเทอร์เฟซสาธารณะอย่างเป็นทางการแล้ว ฉันคิดว่ามีแนวโน้มที่จะส่งผลให้เกิดการปรับโครงสร้างใหม่ในเชิงรุกมากขึ้นสำหรับสิ่งที่ไม่ได้ส่งออกอย่างชัดเจนใช่หรือไม่?
Jason

@ Jason นั่นเป็นความจริงสำหรับไฟล์ต้นฉบับ แต่ไฟล์ package.json จะไม่หายไป ฉันไม่เห็นเหตุผลใด ๆ ที่ควรซ่อนจากการนำเข้า
trusktr
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.