Локальные модули NodeJS для сложных структур приложений

В настоящее время я участвую в разработке приложения для Windows 8 с использованием JavaScript. Мы используем npm и browserify для управления зависимостями и преобразования наших модулей в удобный для браузера формат AMD.

Одна проблема, с которой мы сталкиваемся, — это сумасшедшие требования к путям. Это потому, что у нас есть папка верхнего уровня внутри нашего приложения «компоненты». Эта папка содержит кучу вложенных компонентов/модулей пользовательского интерфейса. Для этих модулей иногда требуются утилиты и помощники lib, которые находятся в каталоге lib.

Так, например, для модуля, находящегося в «my/app/components/product/grid/item», может потребоваться вспомогательный модуль, который находится в «my/app/lib/helpers/view».

Требуемый путь немного сумасшедший и очень уродливый: require("../../../../lib/helpers/view");

Мы делаем все возможное, чтобы построить приложение по модульному принципу. Теперь я думаю, что правильный подход к этому состоит в том, чтобы модули наших компонентов зависели от этих вспомогательных модулей util. Я мог бы поместить помощников lib в их собственное внешнее частное репозиторий git, но это было проблемой с точки зрения предоставления доступа другим командам (плюс частные репозитории git работают медленно). Кроме того, поскольку эти модули используются только в приложении, вносить изменения, отправлять изменения, а затем возвращаться к приложению и обновлять npm — пустая трата времени. Для некоторых это нормально, но если мы действительно сломаем это, это может очень быстро устареть.

Я мог бы сделать npm install "my/app/lib/helpers/view" внутри компонентов package.json? Но npm install не сделает это за нас автоматически.

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


person pbo    schedule 09.03.2013    source источник
comment
Мой текущий подход состоит в том, чтобы запускать пакетный скрипт всякий раз, когда мы собираем, который устанавливает переменную среды для NODE_PATH.   -  person pbo    schedule 09.03.2013
comment
Хорошо, поиграйте еще немного со ссылкой на npm. Я заставляю свои модули приложений иметь файлы package.json, npm-ссылку внутри этих модулей, чтобы сделать их доступными, а затем с верхнего уровня npm связываю их. поскольку npm install не свяжет эти модули для меня.   -  person pbo    schedule 09.03.2013
comment
Я думаю, что отдельные репозитории - это путь.   -  person Domenic    schedule 13.03.2013
comment
Особенно для чего-то вроде помощников.   -  person Domenic    schedule 13.03.2013
comment
По сути, всякий раз, когда вы в конечном итоге поднимаетесь на один уровень, вы, вероятно, в порядке, но если вы поднимаетесь на много уровней, а затем возвращаетесь в другое дерево каталогов, вы смотрите на что-то, что должно быть отдельным пакетом. Делаете ли вы его собственным репозиторием или используете технику регистрации в node_modules, как рекомендует @substack, решать вам.   -  person Domenic    schedule 13.03.2013


Ответы (3)


Вы можете поместить свои "my/app/components/product/grid/item" файлы в node_modules/grid/item.js, а затем, когда вы require('grid/item') в своем коде приложения, вы получите нужный файл с гораздо более кратким синтаксисом пути. Просто проверьте node_modules/grid/item.js и любые другие файлы в git. Каталог node_modules/ даже не обязательно должен находиться на верхнем уровне, поскольку алгоритм require, используемый узлом и браузером, будет искать каталоги node_modules/ от текущего пути до /, пока не найдет соответствующий модуль.

Просто не забудьте добавить "grid" в массив "bundledDependencies" в package.json, чтобы не t случайно установить что-то поверх него.

Вы можете узнать больше о проверке модулей узлов в git.

Прочтите раздел руководства browserify о том, как избежать ../../../../. ./../ для получения дополнительной информации.

NODE_PATH — это всегда плохая идея, и браузер не поддерживает его. Никогда не используйте его никогда.

person substack    schedule 09.03.2013
comment
Интересный. Я знал, что NODE_PATH — не лучший подход, но недавно я посмотрел видео TJ о модульных веб-приложениях (tjholowaychuk.com/post/38571504626/) с экспрессом, и он упоминает об использовании NODE_PATH. - person pbo; 10.03.2013
comment
Да, мы git ignore node_modules/*, но я думал, что термоусадочная пленка блокирует ВСЕ зависимости, даже зависимости ваших зависимостей. Этот пост, кажется, не упоминает этот факт. - person pbo; 10.03.2013
comment
Я бы предпочел не размещать их на верхнем уровне, поэтому, как вы упомянули, я бы, возможно, создал структуру каталогов, в которой node_modules верхнего уровня предназначены для сторонних разработчиков, а затем внутри моей папки lib могут быть node_modules для локальных модулей приложения. Я предполагаю, что моя проблема с этим подходом заключается в том, что вам нужно будет иметь плоский список локальных модулей. - person pbo; 10.03.2013
comment
Да, хорошо, но в этом случае кажется, что Browserify не будет преобразовывать необработанные исходные файлы, такие как JSX или CoffeeScript. Как потребовать файл jsx таким образом? - person Sebastien Lorber; 19.05.2014
comment
Вы говорите, что NODE_PATH — плохая идея. Не могли бы вы уточнить? - person basickarl; 30.01.2017

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

require.config({
    paths: {
        "helpers": "my/app/lib/helpers"    
    }
});

Это сократит некоторые из ваших длинных путей.

person jcreamer898    schedule 09.03.2013
comment
Да, я думаю, что это только для requirejs, которые мы не используем. См. выше, мы используем браузер, чтобы обернуть наши модули. Кроме того, я бы хотел, чтобы это решение работало и на сервере. - person pbo; 09.03.2013

Проблема функции require() заключается в том, что пути относительно текущего файла. Вы можете поместить свои модули в каталог node_modules, но это худшее, что вы можете сделать. node_modules — это каталог, в котором находятся все сторонние модули. Если вы будете следовать этому простому правилу, очень легко и удобно всегда оставаться в курсе событий, вы можете удалить все зависимости (удалив node_modules) и просто сделать npm install.

Лучшее решение — определить собственную функцию require и сделать ее глобальной. Например:

Структура вашего проекта:

my-project
| tools
|- docs
|- logs
|- conf
`- src
   |- node_modules
   |- package.json
   |- mod.js
   |- a
   |  `- b
   |     `- c.js
   `- d
      `- app.js

мод.js

global.mod = function (file){
  return require ("./" + file);
};

app.js

//This should be the first line in your main script
require ("../mod");

//Now all the modules are relative from the `src` directory
//You want to use the a/b/c.js module
var c = mod ("a/b/c");

Вот и все, легко. Если вы хотите получить сторонний модуль, расположенный в node_modules, используйте require(). Если вы хотите получить свои собственные модули, используйте mod().

И помните, node_modules предназначен только для сторонних модулей, правило №1.

person Gabriel Llamas    schedule 09.03.2013
comment
Пользовательская функция require, как у вас здесь с require("./" + file), не поддается статическому анализу и не будет работать с браузером. Размещение собственных модулей в node_modules/ вполне приемлемо, и именно поэтому существует такая вещь, как "bundledDependencies". - person substack; 10.03.2013
comment
Если он не совместим с браузером, сделайте его совместимым с браузером. Мое решение более чистое, чем размещение ваших вещей внутри node_modules - person Gabriel Llamas; 10.03.2013