Как мне управлять относительным сглаживанием путей в нескольких пулах для руткинга?
Это немного, но мне нужен пример кода, чтобы проиллюстрировать мое замешательство. После этого меня интересует ответ на следующее:
- Как использовать
require('module')
вместо require('../../src/module')
или require('./module')
?
- Как повторно использовать
./index.js
в spec/specs.js
без дублирования работы? (И предотвращение запуска src/app.js
как модуля ввода).
Я уже начал несколько проектов на основе браузера и люблю browserify и хрюкать. Но каждый проект умирает в той же точке моей кривой развития/обучения. Как только я добавлю тестирование в микс и вы должны управлять двумя browserify пакетами (app.js
и spec/specs.js
), вся система разваливается. Я объясню:
Я использую grunt-browserify и задаю свой начальный каталог:
.
├── Gruntfile.js
├── index.js (generated via grunt-browserify) [1]
├── lib
│ ├── jquery
│ │ └── jquery.js [2]
│ └── jquery-ui
│ └── jquery-ui.js [3]
├── spec
│ ├── specs.js (generated via grunt-browserify) [4]
│ └── src
│ ├── spec_helper.js (entry)
│ └── module_spec.js (entry)
└── src
├── app.js (entry)
└── module.js
- Использует один файл записи (
src/app.js
) и выполняет код для объединения всех необходимых модулей.
- Использует прокси-браузер для псевдонима
jquery
.
- Просто накладывается на
jquery-ui
без прокладки (требуется после вас var $ = require('jquery')
).
- Использует все вспомогательные и специальные файлы в
spec/src
в качестве модулей ввода.
Я перейду через свою конфигурацию:
browserify: {
dist: {
files: {
'index.js': ['src/app.js']
}
}
}
// in app.js
var MyModule = require('./module'); // <-- relative path required?!
С
Теперь добавьте jquery:
browserify: {
options: {
shim: {
jquery: {
path: 'lib/jquery/jquery.js',
exports: '$'
}
},
noParse: ['lib/**/*.js'],
alias: [
'lib/jquery-ui/jquery-ui.js:jquery-ui'
]
},
dist: {
files: {
'index.js': ['src/app.js']
}
}
}
// in app.js
var $ = require('jquery');
require('jquery-ui');
var MyModule = require('./module');
С
Теперь добавьте спецификации:
options: {
shim: {
jquery: {
path: 'lib/jquery/jquery.js',
exports: '$'
}
},
noParse: ['lib/**/*.js'],
alias: [
'lib/jquery-ui/jquery-ui.js:jquery-ui'
]
},
dist: {
files: {
'app.js': 'src/app.js'
}
},
spec: {
files: {
'spec/specs.js': ['spec/src/**/*helper.js', 'spec/src/**/*spec.js']
}
}
// in app.js
var $ = require('jquery');
require('jquery-ui');
var MyModule = require('./module');
// in spec/src/module_spec.js
describe("MyModule", function() {
var MyModule = require('../../src/module'); // <-- This looks like butt!!!
});
Сад
Подводя итог: Как мне...
- Используйте
require('module')
вместо require('../../src/module')
или require('./module')
?
- повторно использовать
./index.js
в spec/specs.js
без дублирования работы? (И предотвращение запуска src/app.js
как модуля ввода).
Ответы
Ответ 1
Эти ответы зависят от того, как настраивается остальная часть вашего проекта, но, возможно, это хорошая отправная точка. Кроме того, вам нужно будет использовать текущую версию v2 beta grunt-browserify для этого, чтобы на самом деле работать (npm install [email protected]
).
1.
Вы можете использовать aliasMapping для создания динамических псевдонимов для своих модулей. Просто для ясности, переместите все ваши модули на src/modules/
. Тогда конфигурация aliasMapping может быть примерно такой:
options: {
aliasMappings: {
cwd: 'src',
src: ['modules/**/*.js']
}
}
Предположим, что у вас есть модуль в src/modules/magic/stuff.js
, тогда вы можете потребовать его так, независимо от того, где находится файл .js, который выполняет запрос:
var magicStuff = require('modules/magic/stuff.js');
2.
Не уверен в этом. Структура вашего проекта показывает spec/index.js
, но вы указываете spec/specs.js
. Должны ли они быть одним и тем же файлом?
В любом случае, о какой дублирующей работе вы говорите? Поскольку ./index.js
имеет другой файл записи, чем spec/index.js
. Если вы ищете способ включить ./index.js
в specs/
, то, возможно, вы можете скопировать его перед запуском тестов, а не создавать его с нуля.
Ответ 2
Простой ответ:
Простейшим является использование опции paths
для браузера. Я использую его в течение нескольких месяцев с большим успехом. Я даже сделал стартовый комплект, который использует эту функцию: https://github.com/stample/gulp-browserify-react-phonegap-starter
var b = browserify('./app', {paths: ['./node_modules','./src/js']});
paths - массив require.paths, если ничего не найдено в обычном node_modules рекурсивная прогулка
Если у вас есть файл в src/js/modulePath/myModule.js
, это не позволит вам писать require("myModule")
всюду, а скорее require("modulePath/myModule")
, из любого из ваших других исходных файлов.
Устаревшая опция?
Это не похоже!
Алгоритм разрешения модуля Browserify отражает алгоритм разрешения в NodeJS.
Таким образом, опция paths
Browserify является зеркалом поведения переменной NODE_PATH
env для NodeJS.
Заявитель Browserify (substack) утверждает в этой теме SO, что параметр NODE_PATH
устарел в NodeJS, и поэтому он также устарел в Browserify и может быть удален в следующих версиях.
Я не согласен с этим утверждением.
См. документацию NODE_PATH. Не упоминается, что опция устарела. Однако есть еще интересное упоминание о том, что делает в сторону требования к подставке:
Вам настоятельно рекомендуется размещать ваши зависимости локально в node_modules. Они будут загружаться быстрее и более надежно.
И этот вопрос был опубликован в 2012 году в списке рассылки.
Oliver Leics: is NODE_PATH deprecated?
Ben Noordhuis (ex core NodeJS contributor): No. Why do you ask?
И если что-то не устранено в алгоритме разрешения NodeJS, я не думаю, что он будет удален в ближайшее время из Browserify:)
Заключение
Вы можете использовать опцию paths
или поместить свой код в node_modules
, как официальная документация, и Рекомендовать обозреватель.
Лично мне не нравится идея поместить мой собственный код в node_modules
, поскольку я просто держу всю эту папку вне моего исходного элемента управления. Я использую параметр paths
в течение нескольких месяцев и не имею никаких проблем, и моя скорость сборки довольно хороша.
Решение по размещению символической ссылки внутри node_modules
может быть удобным, но, к сожалению, у нас есть разработчики, работающие с Windows здесь...
Я думаю, что там случай, когда вы не хотите использовать параметр paths
: при разработке библиотеки, опубликованной в репозитории NPM, который потребуется другим приложениям. Вы действительно не хотите, чтобы эти клиенты библиотеки настраивали специальную конфигурацию сборки только потому, что вы хотели избежать относительного пути ад в своей библиотеке.
Другой возможный вариант - использовать remapify
Ответ 3
Все ответы здесь, касающиеся псевдонимов и opts.paths
/$NODE_PATH
, невелики, потому что этот подход является устаревшей частью модульной системы в node и браузером, поэтому он может перестать работать в любое время.
Вы должны изучить как работает алгоритм node_modules, чтобы вы могли эффективно организовать свой код таким образом, чтобы он хорошо работал с вложенными node_modules
каталоги.
В справочнике обозревателя есть раздел, который охватывает избегать.. /../../../../../.. проблемы относительного пути. Его можно суммировать как:
- Поместите свой внутренний модульный код в
node_modules/
или node_modules/app
, чтобы вы могли require('yourmodule')
или require('app/yourmodule')
в зависимости от того, какой вы предпочитаете.
- Вы можете использовать символическую ссылку, если вы разрабатываете не-windows-платформы, и это то, что вы предпочитаете.
Не используйте opts.path
/$NODE_PATH
. Это делает ваш проект:
- неявно зависят от неочевидной настройки конфигурации или среды
- сложнее сделать работу как в node, так и в браузере
- уязвим для изменений в модульной системе, поскольку пути массивов устарели в node и браузерируют
Ответ 4
Я думаю, что самый лучший способ пойти - это, как отмечает Себастьян Лорбер, с установкой пути в вашем вызове браузера через трубу.
Но с последней версией браузера (с этого момента, то есть [email protected]
) переменная пути хранит пути только, которые Browserify будет использовать для своего процесса. Насколько я могу сказать, установка переменной paths исключает, скажем... ваши глобальные папки для node. В результате вам понадобится задача Gulp, которая выглядит примерно так:
gulp.task('reactBuild', function() {
return gulp.src(newThemeJSX)
.pipe(browserify({
debug: true,
extensions: ['.jsx', '.js', '.json'],
transform: [reactify],
paths: ['../base_folder/node_modules', '/usr/lib/node_modules']
}))
.pipe(gulp.dest(newThemeBuilt))
.on('error', function(error) {
console.log(error);
});
});