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-модуля занимает несколько больше строк кода, нежели у вас, но, если подумать, там все на своем месте и ничего лишнего нет. Никаких сложностей, повторюсь, я не встречал.
Это не сложности, это проблемы.
Почему я не перейду с AMD на Helios Kernel: AMD, во-первых, вообще не нуждается ни в каких конвенциях по наименованию (именованные модули вообще объявлены устаревшими, ЕМНИП). Во-вторых, она не требует ручного (пусть даже и библиотечного) объявления неймспейсов. Из этих двух пунктов вытекает, например, что при желании можно подключить одновременно zepto и jQuery (или абстрактную вьюху и абстрактную модель, как в моем первом комментарии). В-третьих, архитектурная сила модулей не только в том, что их можно прицепить один к другому, а и в том, что они не мешают друг другу (читай, не засоряют глобальное пространство).
Это не сложности, это проблемы.
Почему я не перейду с AMD на Helios Kernel: AMD, во-первых, вообще не нуждается ни в каких конвенциях по наименованию (именованные модули вообще объявлены устаревшими, ЕМНИП). Во-вторых, она не требует ручного (пусть даже и библиотечного) объявления неймспейсов. Из этих двух пунктов вытекает, например, что при желании можно подключить одновременно zepto и jQuery (или абстрактную вьюху и абстрактную модель, как в моем первом комментарии). В-третьих, архитектурная сила модулей не только в том, что их можно прицепить один к другому, а и в том, что они не мешают друг другу (читай, не засоряют глобальное пространство).
Вроде бы в AMD «module ID» мэпится в путь по конфигам и обстоятельствам? Это как раз хороший пример лишней функциональности, без которой я хотел обойтись. Это может быть удобно использовано, если нужны разные версии одной библиотеки. Но из-за этой возможности нельзянаверняка сказать, где именно расположен исходник модуля.
Мне кажется, вы ожидаете от Helios Kernel, что он должен обладать возможностями AMD, но на мой взгляд Helios Kernel даже и не совсем конкурент, он претендует быть решением скорее не для модулей, которые генерят объекты на экспорт, а для файлов с исходным кодом. Внутри функции init() может быть что угодно, любой код, который будет выполнен как только модуль загрузится. То есть, хотелось сделать что-то вроде аналога макроса инклюд.
Продолжая думать в эту сторону — код внутри функции init(), в том числе и определять объекты модулей в формате наподобие AMD, с экспортом зависимостей и без коллизий. Это можно было бы реализовать поверх в виде отдельной библиотеки с умным разруливанием зависимостей и генерацией имени файла по id модуля, такая библиотека могла бы использовать kernel.require() для загрузки нужных модулей (интересная кстати мысль)
Но моя идея состоит в том, что без этих фич часто можно обойтись. Особенно если формат модуля при этом проще становится. Поэтому про Helios Kernel можно сказать, что это решение
для управления зависимостей между js-скриптами без лишних наворотов.
Мне кажется, вы ожидаете от 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 или автоматически сгенеренное на основе пути к файлу имя?
В связи с началом поддержки Node.js возникают два вопроса:
- В чём достоинства этой системы по сравнению
с API модулей Node?
- В чём недостатки этой системы по сравнению
с API модулей Node?
Описаны сомнительные достоинства. Как минимум записывать в плюсы то, что при обнаружении циклических зависимостей просто выкидывать ошибку, мол, так делать не надо, уже как-то странно. Другие пункты по поводу того, что мол с зависимостями как-то проще… а оно и в commonJS довольно легко и просто, если вы конечно не вызываете какую-то библиотеку глубоко в исходниках.
Да нету modeule.exports, зато есть init. По сути структура модуля получается конечно логичнее, но как-то ограничивает.
И еще вопрос, зачем могла понадобится функциональность выгрузки модулей? Это поидее противоречит здравому смыслу. Загрузилось в память — ну и пусть себе сидит. В следующий раз быстрее отработает. Ну и может еще v8 оптимизаций успел докрутить.
Да нету modeule.exports, зато есть init. По сути структура модуля получается конечно логичнее, но как-то ограничивает.
И еще вопрос, зачем могла понадобится функциональность выгрузки модулей? Это поидее противоречит здравому смыслу. Загрузилось в память — ну и пусть себе сидит. В следующий раз быстрее отработает. Ну и может еще v8 оптимизаций успел докрутить.
Код не может выполняться по кругу, разрешать циклические зависимости может иметь смысл только для случая, когда два модуля используют объекты друг друга «крест-накрест». Это пример плохого дизайна, поэтому запрет циклических зависимостей помогает этого избежать. Есть циклическая зависимость — нужно выделить общий код в отдельный модуль, потом проще же поддерживать будет. Так что это является даже преимуществом, а не недостатком.
Других ограничений Helios Kernel не накладывает (в сравнении с require из nodejs) — код модуля расположен в функции init(), там можно делать что угодно. Это менее ограничивающий подход в сравнении с exports, где всегда нужно создавать и экспортировать объект.
Функциональность выгрузки задумывалась для веба. Загрузились какие-то данные, мы с ними поработали, они больше не нужны — мы их выгрузили.
У Helios Kernel нет двух версий для веба и для nodejs, это один и тот же код, который работает одинаково под обоими средами.
А вообще, идея с работой в nodejs появилась ради возможности создавать совместимые модули, которые без конвертации будут работать и в node и в вебе.
Других ограничений Helios Kernel не накладывает (в сравнении с require из nodejs) — код модуля расположен в функции init(), там можно делать что угодно. Это менее ограничивающий подход в сравнении с exports, где всегда нужно создавать и экспортировать объект.
Функциональность выгрузки задумывалась для веба. Загрузились какие-то данные, мы с ними поработали, они больше не нужны — мы их выгрузили.
У Helios Kernel нет двух версий для веба и для nodejs, это один и тот же код, который работает одинаково под обоими средами.
А вообще, идея с работой в nodejs появилась ради возможности создавать совместимые модули, которые без конвертации будут работать и в node и в вебе.
Полные пути к модулям требуют сразу продуманной иерархии директорий, которой зачастую сходу в проекте нет. То есть, привязываясь к пути вы теряете в гибкости в последующих потенциальных изменениях в структуре папок.
Для успешного использования модулей зачастую достаточно неймспейса + названия модуля.
Конечно хотелось бы услышать более конкретные плюсы и минусы вашего подхода на конкретном примере. Пока я не вижу плюсов.
Для успешного использования модулей зачастую достаточно неймспейса + названия модуля.
Конечно хотелось бы услышать более конкретные плюсы и минусы вашего подхода на конкретном примере. Пока я не вижу плюсов.
Пути же относительные. В крайнем случае, аргумент для include() можно генерить (если вы хотите в вашем проекте часто менять расположение модулей, но мне кажется не стоит это часто делать). Или какая гибкость имеется в виду?
К примеру, расположение библиотек. Изначально все хранилось в общей директории. Приложение должно поступить в опенсорс, код нужно изменить с учетом того, что библиотеки под свободными лицензиями должны быть в vendors + каждая в своей директории + содержать текст лицензии.
Этот пример конечно гипотетический, но вероятный. Чаще всего случается рефакторинг кода от других разработчиков, которые валили библиотеки в неправильные места.
Как мне кажется, хорошая практика — держать конфиг, который бы отвечал за пути к библиотекам / модулям, а на уровне модуля был бы утвержден определенный стандарт
Этот пример конечно гипотетический, но вероятный. Чаще всего случается рефакторинг кода от других разработчиков, которые валили библиотеки в неправильные места.
Как мне кажется, хорошая практика — держать конфиг, который бы отвечал за пути к библиотекам / модулям, а на уровне модуля был бы утвержден определенный стандарт
namespace/ModuleName
, namespace/LibraryName
.В следующих сериях: include_once, requre_once и другие вещи, подсмотренные в php.
У меня один вопрос — зачем?
Есть же спецификации AMD, CommonJS (асинхронная и синхронная загрузка модулей соответственно).
Тот же нодовский commonjs можно спокойно использовать в браузере (browserify, component).
Есть же спецификации AMD, CommonJS (асинхронная и синхронная загрузка модулей соответственно).
Тот же нодовский commonjs можно спокойно использовать в браузере (browserify, component).
Зачем? Зачем? Зачем мне Ваш пехапе в node.js, чем Вам Modules/1.1 не понравился? TJH сейчас бы повесился, смотря на это чудо!
Ладно, будем считать, что Вам захотелось написать велосипед. Но из этого велосипеда видно, что Вы в node.js/JavaScript вошли недавно и так же недавно вышли из PHP. И не совсем поняли Modules/1.1.
Ладно, будем считать, что Вам захотелось написать велосипед. Но из этого велосипеда видно, что Вы в node.js/JavaScript вошли недавно и так же недавно вышли из PHP. И не совсем поняли Modules/1.1.
библиотека позволяющая описывать зависимости между javascript-модулями «в стиле include»Но зачем?!
require
это элегантное своей простотой, и одновременно мощное решение:1. мы задаём импортируемому объекту имя на месте, что делает поиск имён более прозрачным
2. можно импортировать суб-объект из exports, ставя точку после
require(...)
3. можно импортировать под любым именем
4. можно импортировать локально
Я недавно накатал текст по этому вопросу: gist.github.com/asvd/7619633
Всё никак руки не доходят перевести.
Если совсем грубо говоря, то примерно вот почему: в подходах, где есть экспортирование объекта из модуля, мы искуственно связываем внутреннюю структуру библиотеки (то, как она разбита на модули) и её АПИ (экспортируемый объект). Поэтому если например позже захочется переделать структуру проекта, нужно будет приложить немало усилий, чтоб сохранить интерфейс.
Всё никак руки не доходят перевести.
Если совсем грубо говоря, то примерно вот почему: в подходах, где есть экспортирование объекта из модуля, мы искуственно связываем внутреннюю структуру библиотеки (то, как она разбита на модули) и её АПИ (экспортируемый объект). Поэтому если например позже захочется переделать структуру проекта, нужно будет приложить немало усилий, чтоб сохранить интерфейс.
Sign up to leave a comment.
Helios Kernel — include в джаваскрипте, теперь и для nodejs