Как сделать так, чтобы node.js требовал абсолютного? (вместо относительного)

234

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

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

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

Это действительно плохое ИМО. Представьте, что я хотел бы поместить все мои примеры ближе к корню только на один уровень. Это было бы невозможно, потому что мне пришлось бы обновлять более 30 примеров и много раз в каждом примере. К этому:

express = require('../')

Мое решение состоит в том, чтобы иметь особый случай для основанного на root: если строка начинается с $, то это относительно корневой папки проекта.

Любая помощь приветствуется, спасибо

Обновление 2

Сейчас я использую require.js, который позволяет писать одним способом и работает как на клиенте, так и на сервере. Require.js также позволяет создавать собственные пути.

Обновление 3

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

Totty.js
источник
Если вы когда-нибудь решите использовать явную корневую константу / переменную пути, этот ответ работает для этого . Решение использует крошечный модуль github для определения корневого пути.
steampowered

Ответы:

162

И что насчет:

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

Он требует файл, как если бы он был необходим из основного файла js, поэтому он работает довольно хорошо, пока ваш основной файл js находится в корне вашего проекта ... и это то, что я ценю.

cronvel
источник
Неплохая идея (: Затем вы можете определить некоторые другие методы, чтобы каким-то образом переназначить приложение в вашем модуле require.main. Я думаю, что вы могли бы затем сделать require.main.req ('client / someMod'). Хорошая идея, но это быть более многословным, чем мои текущие requirejs. Также я не думаю, что это стоит, потому что я также не люблю browserify, потому что изменения не мгновенные и пропускают изменения (потому что мой код должен работать как в browser, так и в node.js).
Totty.js
4
Если вы находите это слишком многословным, просто используйте .bind (): var rootReq = require.bind (require.main); rootReq ('./path/to/module');
cronvel
да, это может быть полезно для тех, кто все еще хочет использовать browserify на стороне клиента. Для меня это больше не нужно, но все равно спасибо за ваш ответ (:
Totty.js
6
ЕСЛИ ГЛАВНАЯ В КОРНЕ ВАШЕГО ПРОЕКТА :)
Александр Миллс
12
Это решение не будет работать, если код, покрытый модульными тестами, такими как тест Mocha
alx lark
129

В Руководстве Browserify есть действительно интересный раздел :

избегая ../../../../../../ ..

Не все в приложении должным образом принадлежит общедоступному npm, и накладные расходы на настройку частного npm или git-репо все еще довольно велики во многих случаях. Вот несколько подходов, позволяющих избежать ../../../../../../../проблемы относительных путей.

node_modules

Иногда люди возражают против помещения модулей приложения в 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 со своим собственным полем transform в вашем каталоге node_modules/fooили node_modules/app/fooкаталоге компонентов, потому что преобразования не применяются через границы модуля. Это сделает ваши модули более устойчивыми к изменениям конфигурации в вашем приложении, и будет проще самостоятельно повторно использовать пакеты за пределами вашего приложения.

символическая

Еще одна удобная уловка, если вы работаете с приложением, в котором вы можете создавать символические ссылки и вам не требуется поддержка окон, - это создать символическую ссылку на папку 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каталога.

Это связано с тем, что ваше приложение более тесно связано с конфигурацией среды выполнения, поэтому имеется больше движущихся частей, и ваше приложение будет работать только при правильной настройке среды.

узел и browserify оба поддерживают, но препятствуют использованию $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')from /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
Это очень элегантное решение, позволяющее избежать всех проблем в ответах выше. Следует рассмотреть ответ, имхо.
родурико
38

Большая картинка

Это кажется "действительно плохим", но дайте ему время. На самом деле это действительно хорошо. Явные require()s дают полную прозрачность и простоту понимания, что похоже на глоток свежего воздуха в течение жизненного цикла проекта.

Подумайте об этом так: вы читаете пример, погружая свои пальцы в Node.js, и вы решили, что это «действительно плохое ИМО». Вы - второстепенные лидеры сообщества Node.js, люди, которые записывают больше часов на написание и поддержку приложений Node.js, чем кто-либо. Какова вероятность того, что автор совершил такую ​​ошибку новичка? (И я согласен, из моего опыта работы с Ruby и Python это поначалу кажется катастрофой.)

Вокруг Node.js. есть много ажиотажа и контрафакта. Но когда пыль осядет, мы признаем, что явные модули и пакеты «сначала локальные» были основным фактором принятия.

Общий случай

Конечно, node_modulesиз текущего каталога, затем ищется родитель, потом дедушка, прадедушка и т. Д. Поэтому установленные вами пакеты уже работают таким образом. Обычно вы можете require("express")из любого места в вашем проекте, и он отлично работает.

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

Другие обходные пути

Я лично не использую эти методы, но они отвечают на ваш вопрос, и, конечно, вы знаете свою ситуацию лучше, чем я.

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

Далее вы можете пойти на компромисс и потребовать общий локальный файл из всех ваших примеров. Этот общий файл просто реэкспортирует настоящий файл в каталог дедушки.

examples / downloads / app.js (и многим другим нравится)

var express = require('./express')

примеры / загрузки / express.js

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

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

JasonSmith
источник
14
Я согласен с тем, что ребята из Node.js, по какой-то причине, выбрали относительное требование Я просто не вижу его преимуществ, ни из вашего ответа. Мне все еще кажется "плохим";)
Адам Шмидег
21
«Вы - второстепенные лидеры сообщества Node.js». Те же лидеры решили использовать обратные вызовы вместо фьючерсов / обещаний. Большинство моих консультаций по nodejs включает в себя проклятие упомянутых «лидеров» и убеждение людей перейти в JVM. Что намного легче после нескольких месяцев использования nodejs :)
David Sergey
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 ...
Алекс Мантаут
13

Если вы используете пряжу вместо npm, вы можете использовать рабочие пространства .

Допустим, у меня есть папка, которую servicesя хочу более легко:

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

Чтобы создать рабочую область Yarn, создайте 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')
cyberwombat
источник
6
Возможно, стоит уточнить, что это работает только для пряжи , а не для npm? Я рассчитывал, что это, вероятно, сработает и для npm, поэтому потратил немного времени на размышления о том, что я сделал неправильно, пока не попробовал использовать пряжу. Возможно, это было глупое предположение, но, возможно, я не единственный.
ArneHugo
2
Я немного отредактировал, чтобы уточнить. Извините за путаницу.
Cyberwombat
12

ИМХО, самый простой способ - определить собственную функцию как часть 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 = require ('r'). R; в моем файле index.js. Но у меня есть проблема в моих тестах обетов: они не запускают index.js, поэтому мои тесты не проходят, потому что requireS не определено. В любом случае, сейчас я могу добавить GLOBAL.requires = require ('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". Я должен требовать ('./ some') вместо require ("prj / some"). И таким образом все мое приложение будет в директории 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
  • node_modules
    • ...
  • ЦСИ
    • 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');

Таким образом, весь код приложения иерархически организован в модули и доступен для всего другого кода относительно корня приложения.

Конечно, основным недостатком является то, что в файловом браузере вы не можете развернуть / свернуть дерево, как будто оно фактически организовано в каталоги. Но мне нравится, что в нем очень четко указано, откуда исходит весь код, и он не использует никакой «магии».

indirectlylit
источник
Судя по сути, решение № 7 «Упаковщик» довольно простое и удобное.
Пьер-Люк Жендро
Я вижу еще одно маленькое удобство - «перемещение» файла в другую «папку» становится переименованием, что проще, чем перемещение файла. Кроме того, я склонен замечать, что после получаса работы над проектом, в любом случае, почти все дерево моего приложения расширяется. Добавление одного уровня пространства папок может сделать большую кодовую базу управляемой и не вносить слишком много информации, ../x/xкоторая уже читаема.
Лыжи
Вы заново изобретаете папки, используя точки вместо слешей, чтобы преодолеть явное отсутствие в nodejs.
Симона Джанни
9

Предполагая, что корнем вашего проекта является текущий рабочий каталог, это должно работать:

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

// require file relative to current working directory
config = require( path.resolve('.','config.js') );
protometa
источник
config = require('./config.js');действует тоже.
cespon
7
@cespon нет, это только относительно файла, требующего.
протомета
8

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

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

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

senornestor
источник
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);

и затем в любое время, когда вы хотите что-то требовать от корня, независимо от того, где вы находитесь, вы просто используете requireFromRoot вместо ванильного требования. До сих пор у меня неплохо работает.

user1417684
источник
Спасибо! Я думаю, что это довольно умно и просто.
Райан
Прости меня отец, ибо я согрешил. Я портировал это ES6 и получил следующее: requireFromRoot = ((root) => (resource) => require(`${root}/${resource}`))(__dirname);. Любите решение, но вам действительно нужно связывать __dirname так?
Nuck
1
Моя память немного туманна, но я считаю, что __dirname меняет значение в зависимости от того, в каком файле он используется. Теперь может случиться так, что, поскольку функция определена в одном месте, но используется в нескольких местах, значение останется постоянным даже без этой привязки, но я просто сделал это, чтобы убедиться, что это действительно так.
user1417684
сделал это давным-давно, вызывает боли при тестировании envs и тому подобное. не стоит накладных расходов. случайный новый глобал делает новых людей неопределенными, бла-бла
The
А как у тебя requireэта функция?
Дарко Максимович
5

Вот реальный способ, которым я занимаюсь больше 6 месяцев. Я использую папку с именем node_modules в качестве своей корневой папки в проекте, таким образом, она всегда будет искать эту папку везде, где я называю абсолютную потребность:

  • node_modules
    • мой проект
      • index.js Я могу потребовать ("myProject / someFolder / hey.js") вместо require ("./ someFolder / hey.js")
      • someFolder, который содержит hey.js

Это более полезно, когда вы вложены в папки, и гораздо меньше работы, чтобы изменить местоположение файла, если оно установлено абсолютно. Я использую только 2 относительных требования во всем приложении .

Totty.js
источник
4
Я использую аналогичный подход, за исключением того, что я добавляю локальный (проект) node_modulesв систему /srcи оставляю /node_modulesпродавцам отделять вещи. Так что я /src/node_modulesдля местного кода и /node_modulesдля поставщиков.
Мариус Балчитис
33
ИМХО папка 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, поэтому пользователю не требуются глубокие знания.
Йоханнес Эвальд
Конечно, но Node.js в Windows не поддерживает символические ссылки по умолчанию.
Стивен Вачон
4

В вашем собственном проекте вы можете изменить любой файл .js, который используется в корневом каталоге, и добавить его путь к свойству process.envпеременной. Например:

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

После этого вы можете получить доступ к собственности везде:

// in app.js
express = require(process.env.root);
AtraCaelus
источник
4

Еще один ответ:

Представьте себе эту структуру папок:

  • node_modules
    • lodash
  • ЦСИ
    • подкаталог
      • 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-plugin-module-resolver с этим. Файл 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"
Troopers
источник
4

Только что натолкнулся на эту статью, в которой упоминается app-module-path . Это позволяет вам настроить базу следующим образом:

require('app-module-path').addPath(baseDir);
Ole
источник
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.jsесть require('project').

Дэн Д.
источник
Можете ли вы показать исходный код вашего теста, пожалуйста? хорошо, и сработало бы, если бы мне пришлось требовать ('project.a') таким образом?
Totty.js
Что вы имеете в виду require('project.a')? Я думаю, что это может означать require('project/a'), хотя require('project').aэто также возможно?
Дэн Д.
но с вашим примером мне нужно будет создать эти папки в каждой папке, где есть модуль, которому нужен метод require. В любом случае вам нужно позаботиться о времени "../" в зависимости от папки.
Totty.js
На самом деле ссылка должна быть только в node_modulesкаталоге в ближайшем родительском элементе файла, и тогда ссылка будет одинаковой для обоих. См. Nodejs.org/api/…
Дэн Д.
И будет относительным из этого места. Например: project/node_modules/project -> ../.
Дэн Д.
2

Если кто-то ищет еще один способ обойти эту проблему, вот мой собственный вклад в эту работу:

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

Основная идея: вы создаете файл JSON в корне проекта, который отображает ваши пути к файлам с сокращенными именами (или заставляет use-automapper сделать это за вас). Затем вы можете запросить ваши файлы / модули, используя эти имена. Вот так:

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_modules изменится, возникнут более серьезные проблемы. Такое поведение должно оставаться последовательным.

Чтобы прояснить ситуацию, я делаю это, потому что имя модуля не имеет значения.

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

Я использовал это недавно для angular2. Я хочу загрузить сервис из корня.

import {MyService} from 'root/../../app/services/http/my.service';
justonpoints
источник
Что касается вашей угловой ссылки, вы можете просто импортировать стандартное приложение CLI, а src/app/my.serviceтакже настроить VSC на использование относительного импорта для файлов машинописи.
Плоппи
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()
GAFI
источник
Иногда у меня есть личные пакеты в основном проекте, и этот скрипт порвет с этим. Кроме того, я не уверен, что он будет работать нормально с webpack (если вы используете webpack с node.js, как я)
Totty.js
Если у вас есть вложенные каталоги с пакетными файлами, каждый каталог сможет запрашивать только файлы в своем пакете. Разве это не то поведение, которое вы хотите? Я не проверял с веб-пакетом.
GAFI
Это отлично сработало для простого проекта и намного проще, чем любой другой ответ.
byxor
2

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

node_modules

Со следующей структурой каталогов:

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

Таким образом, код в under srcбудет по-прежнему appразрешен src, в то время как babel больше не будет видеть символические ссылки.

user716468
источник
Спасибо, но я не рекомендовал бы делать это волшебство. Сначала вы потеряете все операции импорта, они не будут рассчитываться вашей IDE. Если вы используете другие инструменты, такие как тип потока, он также не будет работать должным образом.
Totty.js
На самом деле, поток работает в моем случае, что неудивительно, поскольку решения зависят от стандартной модели разрешения узлового узла и символических ссылок. Так что это не совсем волшебно для таких инструментов, как поток, чтобы понять. Но IDE разные.
user716468
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

я создал модуль узла под названием "rekiure"

это позволяет требовать без использования относительных путей

https://npmjs.org/package/rekuire

это супер легко использовать

Надав Лешем
источник
1

Мы собираемся попробовать новый способ решения этой проблемы.

Взяв примеры из других известных проектов, таких как spring и guice, мы определим объект «context», который будет содержать все операторы «require».

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

Например

var context = {}

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

Это требует от нас написания каждого модуля как функции, которая получает опции, что в любом случае представляется нам наилучшей практикой.

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

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

var module1Ref = context.moduel1;

Если вы хотите, вы можете легко написать цикл для выполнения операторов require

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

Это должно облегчить жизнь, когда вы хотите использовать макеты (тесты), а также решить вашу проблему в процессе, делая ваш код многократно используемым как пакет.

Вы также можете повторно использовать код инициализации контекста, отделив от него объявление bean-компонентов. например, ваш main.jsфайл может выглядеть так

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

Этот метод также применим к внешним библиотекам, не нужно жестко кодировать их имена каждый раз, когда они нам нужны - однако он потребует особого подхода, поскольку их экспорт не является функциями, ожидающими контекст.

Позже мы также можем определить bean-компоненты как функции, которые позволят нам использовать requireразличные модули в соответствии с окружением, но это выходит за рамки этого потока.

парень Мограби
источник
1

У меня были проблемы с этой же проблемой, поэтому я написал пакет под названием include .

Включите дескрипторы, определяющие корневую папку вашего проекта путем поиска файла package.json, а затем передаете аргумент пути, который вы даете ему, в native require () без всякой путаницы относительного пути. Я представляю это не как замену require (), а как инструмент, требующий обработки неупакованных / сторонних файлов или библиотек. Что-то вроде

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

Я надеюсь, что это может быть полезно.

Энтони Николс
источник
1

Если js-файл точки входа вашего приложения (т. Е. Тот, в котором вы на самом деле запускаете «узел») находится в корневом каталоге вашего проекта, вы можете действительно легко это сделать с помощью модуля rootpath npm . Просто установите его через

npm install --save rootpath

... затем в самом верху js-файла точки входа добавьте:

require('rootpath')();

С этого момента все требуемые вызовы теперь относятся к корню проекта - например, require('../../../config/debugging/log'); становится require('config/debugging/log');(где папка config находится в корне проекта).

Эндрю Фолкнер
источник
1

В простых строках вы можете вызвать свою собственную папку как модуль:

Для этого нам понадобятся: глобальный и модуль app-module-path

здесь "App-module-path" - это модуль, он позволяет вам добавлять дополнительные каталоги к пути поиска модуля Node.js. И "global" - все, что вы прикрепляете к этому объекту, будет доступно везде в вашем приложении.

Теперь взгляните на этот фрагмент:

global.appBasePath = __dirname;

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

__dirname - текущий текущий каталог узла. Здесь вы можете указать свой собственный путь для поиска пути к модулю.

троянский
источник