Як зробити так, щоб node.js вимагав абсолютного? (замість відносних)


234

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

Наприклад, якщо ви подивитеся на https://github.com/visionmedia/express/blob/2820f2227de0229c5d7f28009aa432f9f3a7b5f9/examples/downloads/app.js рядок 6, ви побачите

express = require('../../')

Це справді погано ІМО. Уявіть, що я хотів би поставити всі свої приклади ближче до кореня лише на одному рівні. Це було б неможливо, тому що мені довелося б оновлювати більше 30 прикладів і багато разів у кожному прикладі. До цього:

express = require('../')

Моє рішення полягало б у тому, щоб мати спеціальний випадок для кореневої бази: якщо рядок починається з $, то це відносно кореневої папки проекту.

Будь-яка допомога вдячна, дякую

Оновлення 2

Зараз я використовую requ.js, що дозволяє писати одним способом і працює як на клієнті, так і на сервері. Require.js також дозволяє створювати власні шляхи.

Оновлення 3

Тепер я перейшов до webpack + gulp, і я використовую посилений-вимагаю для обробки модулів на стороні сервера. Дивіться тут обґрунтування: http://hackhat.com/p/110/module-loader-webpack-vs-requirejs-vs-browserify/


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

Відповіді:


162

А як щодо:

var myModule = require.main.require('./path/to/module');

Він вимагає файлу так, як ніби він вимагається від головного js-файлу, тому він працює досить добре, доки ваш головний js-файл знаходиться в корені вашого проекту ... і це те, що я ціную.


Непогана ідея (: Ви можете потім визначити деякі інші методи, щоб якось перевпорядкувати додаток у вашому модулі Requ.main. Я думаю, ви могли б потім зробити Requ.main.req ('client / someMod'). Хороша ідея, але це буде бути більш докладною, ніж мої поточні Requjs. Також я не думаю, що варто, тому що я також не люблю переглядати веб-переглядачі, оскільки зміни не є миттєвими і не впускають зміни (тому що мій код повинен працювати як у браузері, так і в node.js).
Totty.js

4
Якщо ви вважаєте це занадто багатослівним, просто використовуйте .bind (): var rootReq = Requ.bind (Requ.main); rootReq ('./path/to/module');
cronvel

так, це може бути корисним для того, хто все ще хоче скористатися переглядом для клієнта. Для мене більше немає потреби, але все одно дякую за вашу відповідь (:
Totty.js

6
ЯКЩО ГОЛОВНЕ БУДЕ НА КОРІНІ ВАШОГО ПРОЕКТУ :)
Олександр Міллс

12
Це рішення не працюватиме, якщо код покритий одиничними тестами, такими як Mocha test
alx lark

129

У Посібнику з переглядом є справді цікавий розділ :

уникаючи ../../../../../../ ..

Не все в додатку належним чином належить до загальнодоступних npm, а витрати на налаштування приватного npm або git repo у багатьох випадках все ще досить великі. Ось кілька підходів для уникнення проблеми ../../../../../../../відносних шляхів.

вузли_модулі

Люди іноді заперечують проти введення модулів, що стосуються додатків, у node_modules, оскільки не очевидно, як перевірити свої внутрішні модулі, не перевіряючи сторонні модулі з npm.

Відповідь досить проста! Якщо у вас є .gitignoreфайл, який ігнорує node_modules:

node_modules

Ви можете просто додати виняток !для кожного із своїх внутрішніх модулів додатків:

node_modules/*
!node_modules/foo
!node_modules/bar

Зауважте, що ви не можете ігнорувати підкаталог, якщо батьківський ігнорований. Таким чином , замість того , щоб ігнорувати node_modules, ви повинні ігнорувати всі директорії всередині node_modules з node_modules/*трюком, а потім ви можете додати свої винятки.

Тепер у будь-якій точці вашої програми ви зможете require('foo') або require('bar')не мати дуже великого та крихкого відносного шляху.

Якщо у вас багато модулів і ви хочете, щоб вони були більш відокремленими від сторонніх модулів, встановлених npm, ви можете просто помістити їх під каталог, node_modulesнаприклад node_modules/app:

node_modules/app/foo
node_modules/app/bar

Тепер ви зможете require('app/foo')або require('app/bar') з будь-якого місця вашої програми.

У ваших .gitignore, просто додайте виняток для node_modules/app:

node_modules/*
!node_modules/app

Якщо у вашій програмі були перетворені конфігурації в package.json, вам потрібно буде створити окремий package.json з власним полем перетворення у вашому каталозі node_modules/fooчи node_modules/app/fooкомпонентах, оскільки перетворення не застосовуються через межі модуля. Це зробить ваші модулі більш надійними щодо змін конфігурації у вашій програмі, і буде простіше самостійно використовувати пакети поза вашою програмою.

симпосилання

Ще одна зручна хитрість, якщо ви працюєте над додатком, де ви можете створювати посилання і не потрібно підтримувати Windows, - це посилання на символи lib/ або app/папку node_modules. З кореня проекту виконайте:

ln -s ../lib node_modules/app

і тепер з будь-якого місця вашого проекту ви зможете вимагати файлів lib/, виконуючи require('app/foo.js')завдання lib/foo.js.

власні шляхи

Можливо, ви побачите, що в деяких місцях розмовляють про використання $NODE_PATH змінної середовища або opts.pathsдодають каталоги для вузла та переглядають, щоб знайти модулі.

На відміну від більшості інших платформ, використання масиву стилів оболонок каталогів шляху $NODE_PATHне є настільки сприятливим у вузлі порівняно з ефективним використанням node_modulesкаталогу.

Це пояснюється тим, що ваша програма більш щільно пов'язана з конфігурацією середовища виконання, тому є більше рухомих частин, і ваша програма працюватиме лише тоді, коли ваше середовище налаштовано правильно.

вузол і перегляньте обидві служби підтримки, але перешкоджайте їх використанню $NODE_PATH.


17
Єдиною стороною введення його в node_modulesпапку є те, що це ускладнює запуск nuke ( rm -rf node_modules) папки
Michael

13
@Michael Не так вже й важче: git clean -dx node_modules
Пітер Вілкінсон

3
Або у випадку, якщо ви забули git cleanсинтаксис, завжди rm -rf node_modules && git checkout node_modules- будьте впевнені, git stashякщо у node_modulesпідкаталогах є якісь зміни .
derenio

1
Мені подобається ідея використання node_modules, але не для зберігання вихідного коду, враховуючи, наскільки він може бути мінливим. Чи не було б більше сенсу опублікувати відокремлений модуль і зберегти його як залежність у початковому проекті? Він забезпечує чітке рішення про непостійність каталогу node_modules і покладається лише на npm, а не покладається на git, символічні посилання або рішення $ NODE_PATH.
Кевін Кошіол

1
NODE_PATH виглядає як шлях. "ваша програма працюватиме лише тоді, коли ваше середовище налаштовано правильно", це завжди правда! Чи не простіше отримати налаштування середовища (як правило, в одному файлі), ніж змінити кожен імпорт у кожному файлі?
CpILL

73

Мені подобається створити нову node_modulesпапку для спільного коду, а потім дозволити вузлу і вимагати робити все, що найкраще.

наприклад:

- node_modules // => these are loaded from your package.json
- app
  - node_modules // => add node-style modules
    - helper.js
  - models
    - user
    - car
- package.json
- .gitignore

Наприклад, якщо ви знаходитесь, car/index.jsви можете, require('helper')і вузол знайде!

Як працюють node_modules

у вузлі є розумний алгоритм розв'язання модулів, який є унікальним серед конкуруючих платформ.

Якщо ви require('./foo.js')з /beep/boop/bar.js, вузол шукатиме ./foo.jsв /beep/boop/foo.js. Шляхи, які починаються з ./або ../завжди є локальними для файлу, що викликає require().

Якщо вам потрібне не відносне ім'я, наприклад, require('xyz')від /beep/boop/foo.js, вузол здійснює пошук цих шляхів для того, щоб зупинятись на першій відповідності та створювати помилку, якщо нічого не знайдено:

/beep/boop/node_modules/xyz
/beep/node_modules/xyz
/node_modules/xyz

Для кожного xyzкаталогу, який існує, спершу шукатиме a, xyz/package.jsonщоб побачити, чи "main"існує поле. В "main"поле визначає , який файл повинен взяти на себе відповідальність , якщо вам require()шлях до каталогу.

Наприклад, якщо /beep/node_modules/xyzце перший матч і /beep/node_modules/xyz/package.jsonмає:

{
  "name": "xyz",
  "version": "1.2.3",
  "main": "lib/abc.js"
}

тоді експорт з /beep/node_modules/xyz/lib/abc.jsбуде повернутий require('xyz').

Якщо поля немає package.jsonабо немає "main", index.jsпередбачається:

/beep/node_modules/xyz/index.js

2
відмінне пояснення того, як це працює при завантаженні модуля
goenning

2
Це дуже елегантне рішення, дозволяє уникнути всіх проблем у відповідях вище. Слід врахувати відповідь, імхо.
rodurico

38

Велика картина

Це здається "справді поганим", але дайте час. Насправді це справді добре. Чіткі require()видимості забезпечують повну прозорість та легкість розуміння, що схоже на подих свіжого повітря протягом життєвого циклу проекту.

Подумайте про це так: Ви читаєте приклад, опускаючи пальці ніг у Node.js, і вирішили, що це "дійсно поганий ІМО". Ви лідери спільноти Node.js, які ввійшли більше годин, пишучи та підтримуючи програми Node.js, ніж хто-небудь. Який шанс автор допустив таку помилку-новачка? (І я погоджуюсь, з мого фону Ruby та Python це здається спочатку катастрофою.)

Існує багато шуму та контр-шуму, що оточує Node.js. Але коли пил осяде, ми визнаємо, що явні модулі та "локальні перші" пакети були головним рушієм прийняття.

Поширений випадок

Звичайно, node_modulesз поточного каталогу шукають тоді батьків, потім бабусь і дідусів, прабабусь тощо. Отже , встановлені вами пакети вже працюють таким чином. Зазвичай ви можете require("express")з будь-якого місця вашого проекту, і це прекрасно працює.

Якщо ви виявляєте, що ви завантажуєте загальні файли з кореня свого проекту (можливо, тому, що вони є загальними функціями утиліти), то це є великою підказкою, що настав час зробити пакет. Пакети дуже прості: перемістіть ваші файли node_modules/і покладіть package.json туди. Вуаля! Все, що знаходиться в цьому просторі імен, доступне для всього проекту. Пакети - це правильний спосіб ввести код у глобальний простір імен.

Інші обхідні шляхи

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

Ви можете встановити $NODE_PATHкорінь проекту. Цей каталог буде шукати, коли ви require().

Далі, ви можете піти на компроміс і вимагати загального локального файлу з усіх своїх прикладів. Цей загальний файл просто реекспортує справжній файл у каталог бабусь і дідусів.

example / downloads / app.js (та багато інших, як це подобається)

var express = require('./express')

приклади / завантаження / express.js

module.exports = require('../../')

Тепер, коли ви переселяєте ці файли, найгіршим випадком є ​​виправлення одного модуля shim .


14
Я погоджуюся, що хлопці Node.js, мабуть, вибрали родича, вимагаючи причини. Я просто не бачу його переваг, ні з вашої відповіді. Мені все ще «погано»;)
Адам Шмідег,

21
«Ви лідери спільноти Node.js» - Ті ж лідери вирішили використовувати зворотні дзвінки замість ф'ючерсів / обіцянок. Більшість моїх консультацій з nodejs передбачає прокляття сказаних "лідерів" та переконання людей перейти до JVM. Що набагато простіше після декількох місяців використання nodejs :)
Девід Сергій

8
@nirth, перейти до JVM? Заради Бога, чому?
Іванчо

31
"Ви лідери спільноти Node.js", будь ласка, уникайте цього відлякуючого думки.
atlex2

15
Чорт забирає, що він другий лідер вузона здогадки. Ось так прогресує галузь. Якби хлопці з вузлів не вгадали лідерів, які підкріплювали потокові моделі на основі потоків, у нас не було б вузла.
d512

20

Погляньте на node-rfr .

Це так просто, як це:

var rfr = require('rfr');
var myModule = rfr('projectSubDir/myModule');

я думаю, що другий рядок повинен бути var myModule = rfr ('/ projectSubDir / myModule');
Сікорські

1
З документів: var module2 = rfr ('lib / module2'); // Провідна коса риса може бути опущена.
igelineau

Я спробував це, і це rfr працює добре для виконання з вузлом, але він порушує навігацію з кодом VS Code ... Я не зміг знайти обхід, щоб мати змогу використовувати автозаповнення у VS ...
Alex Mantaut

13

Якщо ви використовуєте пряжу замість npm, ви можете використовувати робочі області .

Скажімо, у мене є папка, яку servicesя хотів би легше вимагати:

.
├── app.js
├── node_modules
├── test
├── services
   ├── foo
   └── bar
└── package.json

Щоб створити робочу область Пряжа, створіть package.jsonфайл усередині services folder:

{
  "name": "myservices",
  "version": "1.0.0"
}

У свій основний package.json додайте:

"private": true,
"workspaces": ["myservices"]

Запустити yarn installз кореня проекту.

Тоді в будь-якому місці коду ви можете:

const { myFunc } = require('myservices/foo')

замість чогось типу:

const { myFunc } = require('../../../../../../services/foo')

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

2
Я трохи відредагував, щоб уточнити. Вибачте за непорозуміння.
cyberwombat

12

IMHO, найпростіший спосіб - це визначити власну функцію як частину GLOBALоб'єкта. Створіть projRequire.jsу корені свого проекту із наступним вмістом:

var projectDir = __dirname;

module.exports = GLOBAL.projRequire = function(module) {
  return require(projectDir + module);
}

У головному файлі перед тим, як використовувати requireбудь-який із модулів, що стосуються проекту:

// init projRequire
require('./projRequire');

Після цього для мене працює наступне:

// main file
projRequire('/lib/lol');

// index.js at projectDir/lib/lol/index.js
console.log('Ok');


@Totty, я придумав інше рішення, яке могло б працювати у випадку, який ви описали в коментарях. Опис буде tl;dr, тому я краще покажу картинку зі структурою мого тестового проекту .


ну, досі це здається найкращим способом зробити це. Я роблю: GLOBAL.requires = вимагаю ('r'). R; у моєму файлі index.js Але в моїх тестах для обітниць у мене проблема, вони не запускають index.js, тому мої тести виходять з ладу, оскільки вимагає, що це не визначено. Так чи інакше, я можу додати GLOBAL.requires = requ ('r'). R; у верхній частині кожного тесту. якась краща ідея? github.com/totty90/production01_server/commit/…
Totty.js

для не тестових файлів: github.com/totty90/production01_server/blob/global-require/… , у кожному тестовому файлі: github.com/totty90/production01_server/blob/global-require/test/…
Totty.js

проблема виникає, коли я перебуваю в "pathes-test / node_modules / other.js", і мені потрібен "pathes-test / node_modules / some.js". Я повинен вимагати ('./ деякий') замість вимагати (". Prj / деякий"). І таким чином все моє додаток було б у dir-модулі node_modules?
Totty.js

@Totty, не проблема , що вимагає prj/someвід prj/other(тільки тестування require('prj/some'). Усі загальні модулі програми можуть перейти туди (наприклад, рівень бази даних). Не має значення, де знаходиться, скажімо, ваше lib. Спробуйте і подивіться, чи підходить це.
Олексій Забродський

Так, я оновив його: github.com/totty90/production01_server/tree/master/node_modules/…, що чудово працювало. Але я можу поставити всі свої файли на один рівень без використання node_modules?
Totty.js

12

Я використовую process.cwd()у своїх проектах. Наприклад:

var Foo = require(process.cwd() + '/common/foo.js');

Можливо, варто відзначити, що це призведе requireдо абсолютного шляху, хоча мені ще не доводиться стикатися з проблемами.


1
Це погана ідея, оскільки CWD не повинен бути тим самим каталогом, де зберігається додаток.
jiwopene

11

Там гарне обговорення цього питання тут .

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

  • змішування прикладних модулів із зовнішніми залежностями або обтяження приватними репортажами npm для коду, що залежить від додатка
  • використання відносних потреб, які ускладнюють рефакторинг та розуміння
  • за допомогою символьних посилань або зміни шляху вузла, що може затьмарювати джерела та не грати добре з керуванням джерелом

Зрештою, я вирішив організувати свій код, використовуючи конвенції іменування файлів, а не каталоги. Структура виглядатиме приблизно так:

  • npm-shrinkwrap.json
  • package.json
  • вузли_модулі
    • ...
  • src
    • app.js
    • app.config.js
    • app.models.bar.js
    • app.models.foo.js
    • app.web.js
    • app.web.routes.js
    • ...

Потім у коді:

var app_config = require('./app.config');
var app_models_foo = require('./app.models.foo');

або просто

var config = require('./app.config');
var foo = require('./app.models.foo');

і зовнішні залежності доступні у node_modules як завжди:

var express = require('express');

Таким чином, весь код програми ієрархічно впорядковується в модулі та доступний для всіх інших кодів щодо кореня програми.

Головний недолік, звичайно, в тому, що в браузері файлів ви не можете розширити / згортати дерево так, ніби воно було фактично організовано в каталоги. Але мені подобається, що це дуже чітко про те, звідки береться весь код, і він не використовує жодної «магії».


З суті, яку ви пов’язали, рішення №7, "Обгортка", досить просте і зручне.
Pier-Luc Gendreau

Я бачу ще одну невелику зручність - "переміщення" файлу в іншу "папку" перейменовується - що простіше, ніж переміщувати файл. Плюс я, як правило, помічаю, що після півгодини роботи над проектом майже все моє дерево додатків все одно розширюється. Додавання 1-го рівня простору папок може зробити велику базу коду керованою і не ввести занадто багато, ../x/xщо вже читається.
Лижі

Ви винаходите папки, використовуючи крапки замість штрихів, щоб подолати явний брак у вузлах.
Симоне Джанні

9

Якщо припустити, що корінь вашого проекту є поточним робочим каталогом, це має працювати:

// require built-in path module
path = require('path');

// require file relative to current working directory
config = require( path.resolve('.','config.js') );

config = require('./config.js');діє також.
цеспон

7
@cespon ні, це лише відносно потрібного файлу.
протомета

8

Я перепробував багато таких рішень. Я додав це до початку мого основного файлу (наприклад, index.js):

process.env.NODE_PATH = __dirname;
require('module').Module._initPaths();

Це додає корінь проекту до NODE_PATH, коли сценарій завантажується. Дозволяє мені вимагати будь-якого файлу в моєму проекті, посилаючись на його відносний шлях від кореня проекту, наприклад var User = require('models/user'). Це рішення має працювати до тих пір, поки ви не запускаєте основний скрипт у корені проекту, перш ніж запускати щось інше у вашому проекті.


8

Деякі з відповідей говорять про те, що найкращим способом є додавання коду до node_module як пакет, я згоден, і його, мабуть, найкращий спосіб втратити ../../../потребу, але жоден з них насправді не дає способу зробити це.

з версії 2.0.0ви можете встановити пакет з локальних файлів, а це означає, що ви можете створити папку в корені з усіма потрібними пакетами,

-modules
 --foo
 --bar 
-app.js
-package.json

тому в package.json ви можете додати modules(або fooі bar) як пакет без публікації або використання зовнішнього сервера, як це:

{
  "name": "baz",
  "dependencies": {
    "bar": "file: ./modules/bar",
    "foo": "file: ./modules/foo"
  }
}

Після цього ви зробите npm installі можете отримати доступ до коду var foo = require("foo"), як і у всіх інших пакунках.

більше інформації можна знайти тут:

https://docs.npmjs.com/files/package.json#local-paths

і ось як створити пакет:

https://docs.npmjs.com/getting-started/creating-node-modules


1
"Ця функція корисна для локальної розробки в режимі офлайн та створення тестів, які вимагають встановлення npm там, де ви не хочете потрапляти на зовнішній сервер, але не слід використовувати при публікації пакетів у державному реєстрі."
Райан Сміт

7

Ви можете використовувати модуль, який я зробив, Undot . Це нічого не просунутого, просто помічник, щоб ви могли просто уникнути цих крапок пекла.

Приклад:

var undot = require('undot');
var User = undot('models/user');
var config = undot('config');
var test = undot('test/api/user/auth');

6

Ви можете визначити щось подібне у своєму app.js:

requireFromRoot = (function(root) {
    return function(resource) {
        return require(root+"/"+resource);
    }
})(__dirname);

і тоді, коли ви хочете щось вимагати від кореня, де б ви не знаходилися, ви просто використовуєте RequFromRoot замість ванілі вимагають. На сьогодні для мене працює досить добре.


Дякую! Я думаю, що це досить розумно і прямо.
Райан

Пробач, батьку, бо я згрішив. Я портував це ES6 і отримав наступне: requireFromRoot = ((root) => (resource) => require(`${root}/${resource}`))(__dirname);. Любіть рішення, але чи справді вам потрібно так пов'язувати __dirname?
Nuck

1
Моя пам'ять з цього приводу трохи туманна, але я вважаю, що __dirname змінює значення залежно від того, який файл він використовується. Тепер може статися так, що оскільки функція визначена в одному місці, але використовується в декількох місцях, значення залишатиметься постійним навіть без цього прив'язки, але я просто зробив це, щоб переконатися, що це насправді так.
користувач1417684

це робило давно, викликає болі при тестуванні оточення тощо. не варто накладних витрат. випадкова нова глобальна ситуація робить нових людей невизначеними:
Dembinski

І як ти requireцю функцію?
Дарко Максимович

5

Ось фактичний спосіб, яким я займаюсь понад 6 місяців. Я використовую папку з іменем node_modules як свою кореневу папку в проекті, таким чином вона завжди буде шукати цю папку звідти, де я називаю абсолютну потребу:

  • вузли_модулі
    • мій проект
      • index.js Я можу вимагати ("myProject / someFolder / hey.js") замість вимагати ("./ someFolder / hey.js")
      • деякий папка, яка містить hey.js

Це корисніше, коли ви вкладаєтесь у папки, і набагато менше роботи змінити розташування файлу, якщо воно встановлено абсолютно. Я використовую лише 2 відносних потреби у всьому своєму додатку .


4
Я використовую подібний підхід, за винятком того, що я додаю місцевий (проект) node_modulesв /src, і залишити /node_modulesдля постачальників , щоб тримати речі окремо. Тож у мене є /src/node_modulesмісцевий код та /node_modulesпостачальники.
Маріус Бальчітіс

33
IMHO папка node_modules призначена саме для node_modules. Недобра практика розміщувати весь проект усередині цієї папки.
McSas

2
@McSas, що б ви запропонували як альтернативу, щоб отримати той же ефект, що і вище?
spieglio

3
@cspiegl Ви можете використовувати NODE_PATHзмінну середовища
Крістофер Таркіні

5

Імхо, найпростіший спосіб досягти цього - створити символічне посилання під час запуску програми node_modules/app(або як би ви це не назвали), на яке вказує ../app. Тоді можна просто зателефонувати require("app/my/module"). Символічні посилання доступні на всіх основних платформах.

Однак ви все-таки повинні розділити свої речі на більш дрібні, ремонтовані модулі, які встановлюються через npm. Ви також можете встановити свої приватні модулі через git-url, тому немає жодної причини мати один, монолітний каталог додатків.


Підтримка Windows вимагає більш поглиблених знань про Node та ОС. Це може обмежити широке використання проекту з відкритим кодом.
Стівен Вачон

Як правило, я не використовував би цей зразок для бібліотеки (що є найбільш відкритими проектами). Однак можна створити ці посилання на гачку npm build, щоб не було поглиблених знань, необхідних користувачеві.
Йоханнес Евальд

Звичайно, але Node.js в Windows не підтримує символьні посилання за замовчуванням.
Стівен Вахон

4

У своєму власному проекті ви можете змінити будь-який файл .js, який використовується в кореневій директорії, і додати його шлях до властивості process.envзмінної. Наприклад:

// in index.js
process.env.root = __dirname;

Після цього ви можете отримати доступ до власності скрізь:

// in app.js
express = require(process.env.root);

4

Ще одна відповідь:

Уявіть цю структуру папок:

  • вузли_модулі
    • лодаш
  • src
    • піддір
      • foo.js
      • bar.js
    • main.js
  • тести

    • test.js

Потім у test.js вам потрібно вимагати такі файли:

const foo = require("../src/subdir/foo");
const bar = require("../src/subdir/bar");
const main = require("../src/main");
const _ = require("lodash");

і в main.js :

const foo = require("./subdir/foo");
const bar = require("./subdir/bar");
const _ = require("lodash");

Тепер ви можете використовувати babel і babel-плагін-модуль-роздільник для цього. файл babelrc для налаштування 2 кореневих папок:

{
    "plugins": [
        ["module-resolver", {
            "root": ["./src", "./src/subdir"]
        }]
    ]
}

Тепер ви можете вимагати файлів однаково в тестах і в src :

const foo = require("foo");
const bar = require("bar");
const main = require("main");
const _ = require("lodash");

і якщо ви хочете використовувати синтаксис модуля es6 :

{
    "plugins": [
        ["module-resolver", {
            "root": ["./src", "./src/subdir"]
        }],
        "transform-es2015-modules-commonjs"
    ]
}

то ви імпортуєте файли в тестах та src так:

import foo from "foo"
import bar from "bar"
import _ from "lodash"


3

Не міг examplesкаталог містити node_modulesсимволічне посилання на корінь проекту, project -> ../../таким чином дозволяючи приклади використовувати require('project'), хоча це не видаляє відображення, воно дозволяє використовувати джерело, require('project')а не використовувати require('../../').

Я перевірив це, і він працює з v0.6.18.

Список projectкаталогів:

$ ls -lR project
project:
drwxr-xr-x 3 user user 4096 2012-06-02 03:51 examples
-rw-r--r-- 1 user user   49 2012-06-02 03:51 index.js

project/examples:
drwxr-xr-x 2 user user 4096 2012-06-02 03:50 node_modules
-rw-r--r-- 1 user user   20 2012-06-02 03:51 test.js

project/examples/node_modules:
lrwxrwxrwx 1 user user 6 2012-06-02 03:50 project -> ../../

Вміст index.jsпризначає значення властивості exportsоб'єкта і викликає console.logповідомлення, в якому зазначено, що це було потрібно. Зміст test.jsIS require('project').


чи можете ви показати, будь ласка, вихідний код свого тесту? ну, і це спрацювало б, якщо мені доведеться вимагати (проект.a) таким чином?
Totty.js

Що ви маєте на увазі під require('project.a')? Я думаю, що це може означати require('project/a'), хоча require('project').aце теж можливо?
Дан Д.

але з вашого прикладу мені потрібно створити ті папки у кожній папці, де є модуль, який потребує потрібного методу. У будь-якому разі вам потрібно подбати про час "../", залежно від папки.
Totty.js

Насправді посилання має бути лише у node_modulesкаталозі у найближчому батьківському обох файлах, і посилання буде однаковим для обох. Дивіться nodejs.org/api/…
Dan D.

І буде відносно з цього місця. Наприклад: project/node_modules/project -> ../.
Dan D.

2

Якщо хтось шукає ще один спосіб подолати цю проблему, ось мій власний внесок у зусилля:

https://www.npmjs.com/package/use-import

Основна ідея: ви створюєте файл JSON у корені проекту, який відображає ваші файлові шляхи до скорочених імен (або використовуйте автомати-автомати, щоб зробити це за вас). Потім ви можете запитати ваші файли / модулі, використовуючи ці імена. Так:

var use = require('use-import');
var MyClass = use('MyClass');

Так ось це.


2

Мені подобається робити те, як для цього завантажується вузол з каталогу node_module.

Якщо спробувати завантажити модуль "річ", можна було б зробити щось подібне

require('thing');

Потім Node буде шукати каталог 'thing' у каталозі 'node_module'.

Оскільки node_module зазвичай знаходиться в корені проекту, ми можемо використовувати цю послідовність. (Якщо node_module не знаходиться в корені, у вас виникають інші головні болі, що спричиняють себе.)

Якщо ми зайдемо в каталог, а потім повернемося з нього, ми можемо отримати послідовний шлях до кореня проекту вузла.

require('thing/../../');

Тоді, якщо ми хочемо отримати доступ до каталогу / happy, ми зробимо це.

require('thing/../../happy');

Хоча це і є трохи хакітним, але я відчуваю, що якщо зміниться функціональність завантаження модулів node_, то виникнуть більші проблеми. Така поведінка повинна залишатися послідовною.

Щоб зрозуміти, я це роблю, тому що назва модуля не має значення.

require('root/../../happy');

Я нещодавно використовував його для angular2. Я хочу завантажити службу з кореня.

import {MyService} from 'root/../../app/services/http/my.service';

Щодо вашої кутової посилання, за допомогою стандартної програми CLI ви можете просто імпортувати src/app/my.service, ви також можете налаштувати VSC для використання не відносного імпорту для файлів машинописів.
Ploppy

2

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

https://github.com/Gaafar/pkg-require

Це працює так

// create an instance that will find the nearest parent dir containing package.json from your __dirname
const pkgRequire = require('pkg-require')(__dirname);

// require a file relative to the your package.json directory 
const foo = pkgRequire('foo/foo')

// get the absolute path for a file
const absolutePathToFoo = pkgRequire.resolve('foo/foo')

// get the absolute path to your root directory
const packageRootPath = pkgRequire.root()

Іноді в основному проекті я маю приватні пакети, цей сценарій буде порушений з цим. На додачу до цього, я не впевнений, що буде добре працювати з webpack (якщо ви користуєтесь webpack з node.js як я)
Totty.js

Якщо ви вклали каталоги з файлами пакунків, кожен dir зможе вимагати лише файли в своєму пакеті. Це не та поведінка, яку ви хочете? Я не тестував веб-пакет.
гафі

Це спрацювало ідеально для простого проекту і набагато простіше, ніж будь-який з інших відповідей.
byxor

2

Просто хочу , щоб стежити за великий відповідь від Paolo Moretti і Browserify. Якщо ви використовуєте транспілятор (наприклад, babel, typecript) і у вас є окремі папки для вихідного та перекладеного коду, наприклад, src/і dist/ви можете використовувати варіанти рішень як

вузли_модулі

З такою структурою каталогу:

app
  node_modules
    ... // normal npm dependencies for app
  src
    node_modules
      app
        ... // source code
  dist
    node_modules
      app
        ... // transpiled code

тоді ви можете дозволити babel і т.д. перекласти srcкаталог в distкаталог.

симпосилання

Використовуючи symlink, ми можемо позбутися деяких рівнів вкладення:

app
  node_modules
    ... // normal npm dependencies for app
  src
    node_modules
      app // symlinks to '..'
    ... // source code
  dist
    node_modules
      app // symlinks to '..'
    ... // transpiled code

Протест з стовпотворіння --copy-файли--copy-files прапор babelне має справу з симлінк добре. Він може продовжувати навігацію в ..симпосилання та рецесивно бачити нескінченні файли. Вирішення проблеми полягає у використанні такої структури каталогів:

app
  node_modules
    app // symlink to '../src'
    ... // normal npm dependencies for app
  src
    ... // source code
  dist
    node_modules
      app // symlinks to '..'
    ... // transpiled code

Таким чином, код під srcдосі буде appвирішений src, тоді як вавилон більше не побачить посилання.


Дякую, але я б не рекомендував робити цю магію. Спочатку ви втратите весь імпорт, вони не будуть обчислені вашим IDE. Якщо ви використовуєте інші інструменти типу типу потоку, він також не працюватиме належним чином.
Totty.js

Насправді потік, здається, працює в моєму випадку, що не дивно, оскільки рішення залежать від стандартної моделі роздільної здатності модуля вузла та символьних посилань. Тому це не дуже магія для розуміння таких інструментів, як потік. Але ІДЕ різні.
користувач716468

2

Я шукав таку ж простоту, щоб вимагати файлів будь-якого рівня, і я знайшов псевдонім модуля .

Просто встановіть:

npm i --save module-alias

Відкрийте файл package.json, тут ви можете додати псевдоніми для своїх шляхів, наприклад,

"_moduleAliases": {
 "@root"      : ".", // Application's root
 "@deep"      : "src/some/very/deep/directory/or/file",
 "@my_module" : "lib/some-file.js",
 "something"  : "src/foo", // Or without @. Actually, it could be any string
}

І використовувати псевдоніми просто:

require('module-alias/register')
const deep = require('@deep')
const module = require('something')


1

Ми збираємось спробувати новий спосіб вирішити цю проблему.

Беручи приклади з інших відомих проектів, таких як spring і guice, ми визначимо об'єкт "контекст", який буде містити всі заяви "вимагати".

Потім цей об’єкт буде переданий всім іншим модулям для використання.

Наприклад

var context = {}

context.module1 = require("./module1")( { "context" : context } )
context.module2 = require("./module2")( { "context" : context } )

Це вимагає, щоб ми писали кожен модуль як функцію, яка отримує опт, що все одно вважає нас найкращою практикою.

module.exports = function(context){ ... }

і тоді ви будете посилатися на контекст замість того, щоб вимагати матеріалів.

var module1Ref = context.moduel1;

Якщо ви хочете, ви можете легко написати цикл для виконання необхідних операторів

var context = {};
var beans = {"module1" : "./module1","module2" : "./module2" }; 
for ( var i in beans ){
    if ( beans.hasOwnProperty(i)){
         context[i] = require(beans[i])(context);
    }
};

Це повинно полегшити життя, коли ви хочете знущатися (тести), а також вирішує вашу проблему попутно, роблячи ваш код багаторазовим використання як пакет.

Ви також можете повторно використовувати код ініціалізації контексту, відокремивши декларацію бобів від неї. наприклад, ваш main.jsфайл може виглядати так

var beans = { ... }; // like before
var context = require("context")(beans); // this example assumes context is a node_module since it is reused.. 

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

Пізніше ми також можемо визначити квасоля як функції - що дозволить нам проводити requireрізні модулі відповідно до оточення - але це виходить за межі цього потоку.


1

У мене виникли проблеми з цим самим питанням, тому я написав пакет, який називається include .

Включіть обробку, розбираючи кореневу папку вашого проекту за допомогою локалізації файлу package.json, а потім передайте аргумент шляху, який ви надаєте його до нативного вимагають (), без усього відносного безладу шляху. Я уявляю це не як заміну для requ (), а інструмент для роботи з непакетованими / сторонніми файлами чи бібліотеками. Щось на зразок

var async = require('async'),
    foo   = include('lib/path/to/foo')

Я сподіваюся, що це може бути корисним.


1

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

npm install --save rootpath

... тоді в самому верху файлу js точки введення додайте:

require('rootpath')();

З цього моменту всі необхідні дзвінки тепер відносяться до кореня проекту - наприклад, require('../../../config/debugging/log'); стає require('config/debugging/log');(де папка конфігурації знаходиться в корені проекту).


1

Простими лініями ви можете викликати власну папку як модуль:

Для цього нам потрібен: глобальний модуль та модуль-додаток-модуль-шлях

тут «Додаток-модуль-шлях» - це модуль, він дозволяє додавати додаткові каталоги в шлях пошуку модуля Node.js. «Глобальним» є те, що все, що ви додаєте до цього об’єкта, буде доступним скрізь у вашому додатку.

Тепер погляньте на цей фрагмент:

global.appBasePath = __dirname;

require('app-module-path').addPath(appBasePath);

__dirname - поточний запущений каталог вузла. Тут ви можете вказати свій власний шлях для пошуку шляху модуля.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.