Pull to refresh

Comments 28

include("models/Abstract.js");
include("views/Abstract.js");

Что же делать, как же быть…
models.Abstract и views.Abstract например?
Нет, это я у вас спрашиваю, как ваша библиотека разруливает такие случаи?
Библиотека с разруливанием таких случаев никак не взаимосвязана. Здесь-то как раз случай простой- когда такие объекты создаются в пределах одного проекта, достаточно просто договориться об именовании, например как я привёл выше.

Более «сложный» случай — это когда что-то инклюдится, и коллизии возникают где-то глубоко в зависимостях, а мы даже не знаем, где конкретно.

А вообще у меня основной тезис как раз состоит в том, что если вынести этот вопрос за пределы компетенции библиотеки, то это позволит сильно упростить управление зависимостями. Политику именования объектов при этом можно выбирать как угодно, не привязываясь к ограничениям библиотеки.
То есть, если у меня будет примерно такая вложенность:
js/Collection/Filtered/Paginated.js
то, чтобы избежать конфликтов, в начале init мне нужно будет написать примерно так?
collection = collection || {}
collection.filtered = collection.filtered || {}
collection.filtered.paginated = SomeFabricCall({});
Вы можете также описать какую-нибудь функцию для автоматического построения пустого объекта. Тогда достаточно будет написать что-то вроде

// "Экспортируемый" объект
createNamespace("collection.filtered");

// Разные штуки, предоставляемые вашей билиотекой - модулем
collection.filtered.paginated = SomeFabricCall({});

collection.filtered.whatever = ...


Иными словами — да, предлагается (но не обязательно) определять в каждом модуле один глобальный объект в котором будет всё остальное.
Ясно, спасибо.

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

А что для вас сложностью является? Определение библиотечного объекта или соглашение об именовании?
Ни разу не встречал сложностей с AMD, если честно. Зависимости прописываются точно так же, как у вас — в строковом литерале, содержащем путь, что достаточно очевидно, имхо. Описываются модули точно так же, как у вас — через коллбэк. Понятно, что определение AMD-модуля занимает несколько больше строк кода, нежели у вас, но, если подумать, там все на своем месте и ничего лишнего нет. Никаких сложностей, повторюсь, я не встречал.

Это не сложности, это проблемы.
Почему я не перейду с AMD на Helios Kernel: AMD, во-первых, вообще не нуждается ни в каких конвенциях по наименованию (именованные модули вообще объявлены устаревшими, ЕМНИП). Во-вторых, она не требует ручного (пусть даже и библиотечного) объявления неймспейсов. Из этих двух пунктов вытекает, например, что при желании можно подключить одновременно zepto и jQuery (или абстрактную вьюху и абстрактную модель, как в моем первом комментарии). В-третьих, архитектурная сила модулей не только в том, что их можно прицепить один к другому, а и в том, что они не мешают друг другу (читай, не засоряют глобальное пространство).
Вроде бы в AMD «module ID» мэпится в путь по конфигам и обстоятельствам? Это как раз хороший пример лишней функциональности, без которой я хотел обойтись. Это может быть удобно использовано, если нужны разные версии одной библиотеки. Но из-за этой возможности нельзянаверняка сказать, где именно расположен исходник модуля.

Мне кажется, вы ожидаете от Helios Kernel, что он должен обладать возможностями AMD, но на мой взгляд Helios Kernel даже и не совсем конкурент, он претендует быть решением скорее не для модулей, которые генерят объекты на экспорт, а для файлов с исходным кодом. Внутри функции init() может быть что угодно, любой код, который будет выполнен как только модуль загрузится. То есть, хотелось сделать что-то вроде аналога макроса инклюд.

Продолжая думать в эту сторону — код внутри функции init(), в том числе и определять объекты модулей в формате наподобие AMD, с экспортом зависимостей и без коллизий. Это можно было бы реализовать поверх в виде отдельной библиотеки с умным разруливанием зависимостей и генерацией имени файла по id модуля, такая библиотека могла бы использовать kernel.require() для загрузки нужных модулей (интересная кстати мысль)

Но моя идея состоит в том, что без этих фич часто можно обойтись. Особенно если формат модуля при этом проще становится. Поэтому про Helios Kernel можно сказать, что это решение
для управления зависимостей между js-скриптами без лишних наворотов.
Но из-за этой возможности нельзянаверняка сказать, где именно расположен исходник модуля.
Можно. require.js же знает, откуда что грузить. Да, можно написать кривой и извращенный конфиг, где '$' будет алиасом Backbone, 'Backbone' — алиасом для underscore и т.д., но кто в здравом уме будет это делать? #define true false // happy debugging, bitches?

не для модулей, которые генерят объекты на экспорт, а для файлов с исходным кодом
Не вижу особых отличий между
require(['lib/vendor/jquery'], function ($) { $.fn.myPlugin })
и
include("lib/vendor/jquery");
init = function () {
    $.fn.myPlugin
}


Да, нередко можно обойтись без алиасов, путей, конфигов и прочего, но в этих же случаях можно обойтись и вообще без модулей.
или, другими словами — откуда берется имя переменной library1? Это глобальная переменная в файле path/to/library1.js или автоматически сгенеренное на основе пути к файлу имя?
Да, переменную определяет автор модуля в его функции init(). На сайте описано, как это делается
В связи с началом поддержки Node.js возникают два вопроса:

Описаны сомнительные достоинства. Как минимум записывать в плюсы то, что при обнаружении циклических зависимостей просто выкидывать ошибку, мол, так делать не надо, уже как-то странно. Другие пункты по поводу того, что мол с зависимостями как-то проще… а оно и в commonJS довольно легко и просто, если вы конечно не вызываете какую-то библиотеку глубоко в исходниках.
Да нету modeule.exports, зато есть init. По сути структура модуля получается конечно логичнее, но как-то ограничивает.

И еще вопрос, зачем могла понадобится функциональность выгрузки модулей? Это поидее противоречит здравому смыслу. Загрузилось в память — ну и пусть себе сидит. В следующий раз быстрее отработает. Ну и может еще v8 оптимизаций успел докрутить.

Код не может выполняться по кругу, разрешать циклические зависимости может иметь смысл только для случая, когда два модуля используют объекты друг друга «крест-накрест». Это пример плохого дизайна, поэтому запрет циклических зависимостей помогает этого избежать. Есть циклическая зависимость — нужно выделить общий код в отдельный модуль, потом проще же поддерживать будет. Так что это является даже преимуществом, а не недостатком.

Других ограничений Helios Kernel не накладывает (в сравнении с require из nodejs) — код модуля расположен в функции init(), там можно делать что угодно. Это менее ограничивающий подход в сравнении с exports, где всегда нужно создавать и экспортировать объект.

Функциональность выгрузки задумывалась для веба. Загрузились какие-то данные, мы с ними поработали, они больше не нужны — мы их выгрузили.

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

А вообще, идея с работой в nodejs появилась ради возможности создавать совместимые модули, которые без конвертации будут работать и в node и в вебе.
Полные пути к модулям требуют сразу продуманной иерархии директорий, которой зачастую сходу в проекте нет. То есть, привязываясь к пути вы теряете в гибкости в последующих потенциальных изменениях в структуре папок.

Для успешного использования модулей зачастую достаточно неймспейса + названия модуля.

Конечно хотелось бы услышать более конкретные плюсы и минусы вашего подхода на конкретном примере. Пока я не вижу плюсов.
Пути же относительные. В крайнем случае, аргумент для include() можно генерить (если вы хотите в вашем проекте часто менять расположение модулей, но мне кажется не стоит это часто делать). Или какая гибкость имеется в виду?
К примеру, расположение библиотек. Изначально все хранилось в общей директории. Приложение должно поступить в опенсорс, код нужно изменить с учетом того, что библиотеки под свободными лицензиями должны быть в vendors + каждая в своей директории + содержать текст лицензии.

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

Как мне кажется, хорошая практика — держать конфиг, который бы отвечал за пути к библиотекам / модулям, а на уровне модуля был бы утвержден определенный стандарт namespace/ModuleName, namespace/LibraryName.
include() уже так и работает
ну тут все же система модулей… просто вместо require идет include. Но лично мое мнение — система сомнительная.
У меня один вопрос — зачем?

Есть же спецификации AMD, CommonJS (асинхронная и синхронная загрузка модулей соответственно).

Тот же нодовский commonjs можно спокойно использовать в браузере (browserify, component).
Зачем? Зачем? Зачем мне Ваш пехапе в node.js, чем Вам Modules/1.1 не понравился? TJH сейчас бы повесился, смотря на это чудо!
Ладно, будем считать, что Вам захотелось написать велосипед. Но из этого велосипеда видно, что Вы в node.js/JavaScript вошли недавно и так же недавно вышли из PHP. И не совсем поняли Modules/1.1.
Почему PHP? Тогда уж Си например :-)
библиотека позволяющая описывать зависимости между javascript-модулями «в стиле include»
Но зачем?!

require это элегантное своей простотой, и одновременно мощное решение:
1. мы задаём импортируемому объекту имя на месте, что делает поиск имён более прозрачным
2. можно импортировать суб-объект из exports, ставя точку после require(...)
3. можно импортировать под любым именем
4. можно импортировать локально
Я недавно накатал текст по этому вопросу: gist.github.com/asvd/7619633

Всё никак руки не доходят перевести.

Если совсем грубо говоря, то примерно вот почему: в подходах, где есть экспортирование объекта из модуля, мы искуственно связываем внутреннюю структуру библиотеки (то, как она разбита на модули) и её АПИ (экспортируемый объект). Поэтому если например позже захочется переделать структуру проекта, нужно будет приложить немало усилий, чтоб сохранить интерфейс.
Sign up to leave a comment.

Articles