Trong node.JS, làm cách nào để lấy đường dẫn của một mô-đun tôi đã tải qua request đó là * not * mine (tức là trong một số node_module)


94

Tôi yêu cầu một mô-đun đã được cài đặt qua npm. Tôi muốn truy cập tệp .js cấp dưới cho mô-đun đó (vì vậy tôi có thể phân lớp một phương thức Constructor trong đó). Tôi không thể (tốt, không muốn) sửa đổi mã của mô-đun, vì vậy không có nơi để trích xuất __dirname của nó.

Tôi biết câu hỏi sau, nhưng đó là về việc lấy đường dẫn của một mô-đun mà người ta có quyền kiểm soát mã (do đó, __dirname là giải pháp): Trong Node.js, làm cách nào để tôi biết đường dẫn của mô-đun `this`?

~~~

Tốt hơn nữa là lấy thông tin mô-đun đã tải của mô-đun


nơi bạn có thể tải mô-đun mà không gặp bất kỳ lỗi nào với request ('modulename')?
Futur

bạn có thể giải thích nó tốt hơn? một số mã?
Gabriel Llamas

Câu trả lời:


130

Nếu tôi hiểu đúng câu hỏi của bạn, bạn nên sử dụng request.resolve () :

Sử dụng máy móc request () nội bộ để tìm kiếm vị trí của mô-đun, nhưng thay vì tải mô-đun, chỉ cần trả lại tên tệp đã phân giải.

Thí dụ: var pathToModule = require.resolve('module');


13
Câu trả lời này không hoạt động đáng tin cậy với tất cả các mô-đun nút. Hãy xem câu trả lời của tôi.
Jason

61

request.resolve () là một phần câu trả lời. Câu trả lời được chấp nhận có thể hoạt động cho nhiều mô-đun nút, nhưng sẽ không hoạt động cho tất cả chúng.

require.resolve("moduleName")không cung cấp cho bạn thư mục nơi mô-đun được cài đặt; nó cung cấp cho bạn vị trí của tệp được xác định trong mainthuộc tính trong mô-đun của package.json.

Đó có thể là moduleName/index.jshoặc nó có thể được moduleName/lib/moduleName.js. Trong trường hợp sau, path.dirname(require.resolve("moduleName"))sẽ trả về một thư mục mà bạn có thể không muốn hoặc không mong đợi:node_modules/moduleName/lib

Cách chính xác để có được đường dẫn đầy đủ đến một mô-đun cụ thể là giải quyết tên tệp:

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

Nếu bạn chỉ muốn thư mục cho mô-đun (có thể bạn sẽ thực hiện nhiều path.join()cuộc gọi), thì hãy giải quyết package.json- phải luôn có trong thư mục gốc của dự án - và chuyển đến path.dirname():

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

1
câu trả lời rất thông minh, bằng cách phát hiện package.jsontệp. Bạn không nên sử dụng path.join('moduleName', 'package.json')vì tương thích với Windows?
João Pimentel Ferreira

2
@ JoãoPimentelFerreira require.resolvelà nền tảng bất khả tri, giống như requirenó không cần thiết để sử dụngpath.join
Gopikrishna S

1
Đừng quên bổ sung const path = require('path');trước khi sử dụng path.dirname.
GOTO 0

Tôi ước câu trả lời này là hoàn toàn đúng sự thật! Tôi có thể giải quyết thành công một cái gì đó tương tự như require.resolve('@scope/module')vậy /path/to/@scope/module/dist/index.js, nhưng nếu tôi cố gắng chạy require.resolve('@scope/module/package.json')nó sẽ MODULE_NOT_FOUNDgây ra lỗi. Tôi đang ở Node 14.4.0 và mô-đun tôi đang cố gắng giải quyết có "type": "module"trong package.json của nó với một exportstrường không bao gồm package.json. Không chắc liệu điều đó có liên quan gì đến nó ...
trusktr

Tôi phát hiện ra vấn đề: khi một mô-đun có type: module, dường như package.jsonphải được hiển thị rõ ràng trong exportstrường. Tôi nghĩ rằng tính năng ESM mới của Node không chặn phân requiregiải các đường dẫn như bình thường, nhưng rõ ràng là có.
trusktr

3

FYI, require.resolvetrả về định danh mô-đun theo CommonJS. Trong node.js, đây là tên tệp. Trong webpack đây là một con số.

Trong tình huống webpack , đây là giải pháp của tôi để tìm ra đường dẫn mô-đun:

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

Sau đó, __webpack_modules__[pathToModule]tôi nhận được thông tin như sau:

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

    /***/
})

Hóa ra, tôi yêu cầu các tập lệnh cũ từ tệp xây dựng dll trước đó (để có tốc độ xây dựng nhanh hơn), do đó tệp mô-đun cập nhật của tôi không hoạt động như tôi mong đợi. Cuối cùng tôi đã xây dựng lại tệp dll của mình và giải quyết được vấn đề của mình.

Tham khảo: Sử dụng require.resolveđể nhận đường dẫn tệp đã giải quyết (nút)


2

Tôi hy vọng tôi hiểu đúng nhu cầu của bạn: lấy tệp điểm đầu vào của một số mô-đun. Giả sử bạn muốn nhận điểm đầu vào của jugglingdbmô-đun:

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

Như bạn có thể thấy, đây không phải là cách "chính thức" để lấy loại thông tin này về mô-đun, vì vậy hành vi của chức năng này có thể thay đổi từ phiên bản này sang phiên bản khác. Tôi đã tìm thấy nó trong nguồn nút: https://github.com/joyent/node/blob/master/lib/module.js#L280


2

Theo giải pháp @anatoliy, Trên MacOS XI đã tìm thấy các đường dẫn tra cứu đang làm

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

vì vậy tôi nhận được các đường dẫn tra cứu đã giải quyết

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

trong khi

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

sẽ không giải quyết được mô-đun mà tôi đang tìm kiếm, trên thực tế, điều điên rồ là _loadsẽ không giải quyết được mô-đun:

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

trong khi ý requirechí:

> require('myModule')

nhưng tôi không có mô-đun này trong

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/

vậy module này ở đâu ???

Đầu tiên, tôi phải làm $ sudo /usr/libexec/locate.updatedb Sau đó sau một vài ly cà phê, tôi đã làm locate myModulehoặc tốt hơnlocate myModule/someFile.js

et voilà, nó phát ra rằng nó nằm trong thư mục mẹ của dự án của tôi, tức là bên ngoài thư mục gốc dự án của tôi:

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

vì vậy bạn không thể tránh rm -rf ../../node_modules/myModule/và tươi npm install.

Tôi có thể tranh luận rằng không ai hướng dẫn npmquét máy tính của tôi để tìm kiếm mô-đun ở nơi khác ngoài thư mục gốc dự án của tôi, nơi nó được cho là chạy hoặc trong đường dẫn tìm kiếm mô-đun mặc định.


1

Đây có thể là những gì bạn đang tìm kiếm, hãy kiểm tra:

request.main.filename


1

Câu trả lời của Jason là câu trả lời tốt nhất, cho đến khi Node.js ESM và exportslĩnh vực này xuất hiện.

Bây giờ Node hỗ trợ các gói có exportstrường theo mặc định sẽ ngăn không cho các tệp như package.jsoncó thể phân giải được trừ khi tác giả gói quyết định rõ ràng để lộ chúng, mẹo trong câu trả lời của Jason sẽ không thành công đối với các gói không hiển thị rõ ràng package.json.

Có một gói được gọi là resolve-package-paththực hiện thủ thuật.

Đây là cách sử dụng nó:

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

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

mà sẽ xuất ra một cái gì đó giống như

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

bất kể trường của gói exportschứa những gì .


Tôi nghi ngờ rằng một khi tác giả đang xuất một cách có ý thức một phần nội dung của mô-đun, bạn thậm chí còn run hơn, bởi vì bây giờ tác giả đã chính thức xác định giao diện công khai của họ. Tôi nghĩ rằng điều đó sẽ dẫn đến việc tái cấu trúc mạnh mẽ hơn những thứ không được xuất khẩu rõ ràng, phải không?
Jason

@Jason Điều đó đúng với các tệp nguồn, nhưng các tệp package.json sẽ không biến mất. Tôi không thấy bất kỳ lý do nào khiến chúng bị ẩn khỏi quá trình nhập.
trusktr
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.