У node.JS, як я можу отримати шлях до модуля, який я завантажив через require, який * не * мій (тобто в деякому node_module)


94

Мені потрібен модуль, встановлений через npm. Я хочу отримати доступ до файлу .js, підпорядкованого цьому модулю (щоб я міг підкласувати в ньому метод Constructor). Я не можу (ну, не хочу) змінювати код модуля, тому не маю місця для вилучення його __dirname.

Мені відомо наступне запитання, але мова йде про отримання шляху до модуля, над яким здійснюється контроль коду (отже, __dirname - це рішення): Як я можу визначити шлях до модуля `this` в Node.js?

~~~

Ще краще було б отримати інформацію про завантажений модуль


де ви зможете завантажити модуль без помилок з request ('ім'я модуля')?
Futur

ти можеш пояснити це краще? якийсь код?
Габріель Ламас,

Відповіді:


130

Якщо я правильно розумію ваше запитання, вам слід використовувати require.resolve () :

Використовуйте внутрішній механізм require () для пошуку розташування модуля, але замість того, щоб завантажувати модуль, просто поверніть вирішене ім’я файлу.

Приклад: var pathToModule = require.resolve('module');


13
Ця відповідь не працює надійно з усіма модулями вузлів. Дивіться мою відповідь.
Джейсон

61

require.resolve () - це часткова відповідь. Прийнята відповідь може працювати для багатьох вузлових модулів, але не для всіх.

require.resolve("moduleName")не надає вам каталог, де встановлений модуль; він надає вам розташування файлу, визначеного в mainатрибуті в модулі package.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?
Жоао Піментель Феррейра,

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помилку. Я перебуваю в Node 14.4.0, і модуль, який я намагаюся вирішити, містить "type": "module"у своєму package.json exportsполе, яке не включає package.json. Не впевнений, чи має це щось
спільне

Я виявив проблему: коли модуль має 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 і вирішив свою проблему.

Посилання: Використання 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/

так де цей модуль ???

Спочатку мені довелося зробити a $ 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

Відповідь Джейсона була найкращою, поки не exportsвийшли ESM і Node.js.

Тепер, коли Node підтримує пакети з exportsполем, яке за замовчуванням запобігаєpackage.json розкриванню файлів , якщо автор пакета явно не вирішить їх виставити, фокус у відповіді Джейсона не вдасться для пакетів, які явно не виставляють package.json.

Існує пакет, який називається resolve-package-pathтаким чином.

Ось як ним користуватися:

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

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

який виведе щось на зразок

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

незалежно від того, що exportsмістить поле пакета .


Я підозрюю, що як тільки автор свідомо експортує частину вмісту модуля, ви знаходитесь на ще більш хиткій основі, тому що зараз автор офіційно визначив їх загальнодоступний інтерфейс. Я думаю, це могло б призвести до більш агресивного рефакторингу речей, які явно не експортуються, чи не так?
Джейсон,

@Jason Це справедливо для вихідних файлів, але файли package.json не зникають. Я не бачу жодної причини, яку слід приховувати від імпорту.
trusktr
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.