Поясните, пожалуйста, зачем выкладывать «расковырянную» версию и почему то, что лежит сейчас на github нереальные исходники? )
Просто я искренне полагал (и полагаю), что рабочий «мусор» на паблике ни к чему. Есть файл, есть история с которой видны изменения ну и так далее.
Если вам интересен какой-то отдельный модуль, то просто сверните код до второго уровня вложенности и вы увидите все девять модулей по отдельности. Да и станет очевидным то, как все это собирается.
Если посмотреть на код и свернуть блоки до 2-ой вложенности, то вы увидите 9-ть независимых друг от друга модулей (в том смысле, независимых, что они могут существовать отдельно). То что вы видите на github, да и на промо сайте — это уже результирующий файл.
Спасибо за комментарий. Я думаю, что сравнивать этот шаблонизатор с React нельзя — разные масштабы, да и React — это не шаблонизатор. Ну а то что сделал я — это для очень узкого круга задач — фактически это просто инструмент для создания не слишком сложных UI компонентов (по крайне мере я его так применяю). У React спект применения значительно, значительно шире.
Для меня (я могу судить только по себе :)) главное приимущество: это возможность открывать шаблоны в отрыве от проекта, отлаживать их, править стили. Мне это удобно. Даже если компонент стал сложный, с логикой какой-то, то на создание тестовой страницы (что бы открыть его отдельно) уходит 3-и минуты и все, я снова могу отлаживать копмонент в отрыве от всего приложения.
Добавлен новый параметр [serialize] в колекцию параметров метода _patterns.get(). Пока заменяет экранирует только теги. Но расширить функционал — не проблема. По умолчанию в true. Еще раз спасибо за предложение.
ЗЫ
Документацию обновлю позже )
Экранизацию я как-то из виду упустил. Но это не вопрос архитектуры. Кроме того, вы легко можете это и предотвратить средствами шаблонизатора, добавив обработчик к соответствующей модели.
Но все равно, спасибо за хорошее критическое замечание, правда какое-то категоричное )
Я (честно) все время с момента моей публикации думаю о том, почему регистр модулей — это «зло». В том смысле, что в регистре объявляются только имена модулей и настройки кэширования – ничего больше – никаких зависимостей.
И я не могу понять, в чем потенциальная проблема такого регистра. Вы не первый, кто обращает внимание на некую проблему, пока характеризующуюся как «хлебнете», «не используйте» и так далее.
Я хочу, очень хочу понять в чем эта самая потенциальная проблема. И я понимаю, что регистр, где объявляются зависимости – это геморрой. Но если зависимостей в нем не объявляется?
Не эффективно с точки зрения дополнительной сущности? Да, с этой точки зрения – однозначное да – дополнительное телодвижение только для того, чтобы «убрать» пути из объявления модулей. Но разве с этого можно «хлебнуть»?
Изначально (пару лет назад) этот злополучный регистр как раз и содержал зависимости. То есть зависимости объявлялись не при объявлении модулей, а в регистре. И очень быстро я пришел к тому, что это крайне, крайне неудобно и неэффективно. Поэтому я оставил в регистре только и исключительно пути (ссылки на JS-файлы модулей), а также настройки кэширования. Ну и вроде как неудобств особых не испытывал в проектах до 50 модулей где-то.
Да, регистр засорялся ненужным ссылками (в результате copy / paste с других проектов), но и чистился за пару минут.
С другой стороны, я имел контроль над кэшированием в одном месте, да и несколько раз мне приходилось менять структуру папок на уже сданном проекте и тогда мне этот регистр был очень кстати, потому как все изменения вносились лишь в один файл и не приходилось «бегать» по проекту поиском, чтобы править каждый отдельный модуль (конечно, в requireJS все тоже самое через настройки, но я с ним и не конкурирую).
Я совершенно не исключаю, что я не прав, я даже знаю, что я ничего не знаю ))) Но очень прошу вас, развернуть ваш тезис о нависшем надо мною «хлебну» ))
Таких больших проектов просто не встречал в практике и, честно сказать, не думал о них вовсе, работая над своим великом. Наиболее крупный, что был у меня – это где-то около 200 модулей (только JS файлы), где хоть и не использовались мои решения, но все же был единый регистр всех модулей, вынесенный в один файл. Было порядка 500 срок с описанием всяких особенностей и это было довольно удобно.
Может быть существует некий предел, после которого архитектура и применяемые решения должны как-то учитывать масштаб системы. Конечно, для проекта, где описание модулей занимает 4 – 5 тыс. строк что-то должно быть сделано иначе.
И еще, просто чтобы убедиться, что мы говорим об одном и том же. Под модулем я понимаю модуль без учета ресурсов. То есть модуль может запрашивать еще и какие-то ресурсы (CSS к примеру), которые не в какие регистры не вносятся, а определяются в рамках объявления модуля.
Я видел регистр всех ресурсов для большого проекта. Да, там было, если не ошибаюсь, порядка 6 тыс. строк. Но убери оттуда все CSS и вспомогательные ресурсы (вроде сторонних библиотек JS) и количество строк сократится кратно (именно кратно, потому что многие вспомогательные ресурсы объявляются многократно для указания зависимостей одного от другого).
flex.register.modules.js задумывался не как перечень всего и вся, а как место, где определяются «ключевые» (не знаю какое слово подобрать) модули. И никаких зависимостей, никаких ресурсов, ничего кроме просто путей к модулям в этом регистре не объявляется. Все ресурсы объявляются только на уровне объявления модуля (то есть в файле самого модуля). И с этой точки зрения для проекта с количеством модулей, скажем меньше 100, наличие единого регистра мне видится больше в позитивном свете, нежели, чем в негативном.
Но опять же, у меня нет богатого опыта работы с огромными проектами, где только модулей тысячи. Поэтому мое мнение очень субъективно, и я это понимаю.
Я просто отвечал на вопрос о встреченных трудностях, ну и перечислял те что встретил. eval я не использую, создав функцию через module = new Function(js_txt), я просто делаю module.call(window), что тоже самое с точки зрения результата.
А интеграция модулей вообще идет и без function и без call, чтобы сохранить привычку браузера «править» наши рутинные ошибки. Вот здесь flex.core.js, строки 4400 — 4410 – то как интегрируются модули в систему.
Вы все верно поняли ) И предложенные вами решения верны со всех точек зрения и мало того применяются в том числе мною. Не в этом ли вся прелесть нашей профессии – во множестве решений одних и тех же задач? )
Тут большую роль играет личная мотивация. Посмотрите мой ответ вам чуть ниже выше ).
Знаете, меня столько раз это стопорило «Все уже придумано, написано – бери и используй!». Вот упрусь в какую-нибудь дилемму и сразу подобные мысли в голову лезут.
А потом вспоминаю, что ключевая мотивация у меня – это вопрос «а как это работает вообще?» и возвращаюсь к разработке ). Собственно, большую часть того, что можно делать в JS я узнал не из рабочих проектов (основная работа), а в процессе изобретения этого велика. Поэтому личный profit в виде опыта уже есть )
Что же касается AngularJS или же knockoutJS, или чего-то еще, то тут дело в том, что нет «конфликта интересов» — у меня просто нет такого выбора: использовать мои решения или AngularJS или же knockoutJS. Если заказчик говорит – делай что хочешь, я вежливо его спрашиваю – не против ли он стать «полигоном» для моих собственных наработок (если я понимаю, что оно не навредит). Не против? Чудно, беру ответственность на себя. Если решение должно быть на чем-то другом – не вопрос.
Если честно, на счет «трудного» не знаю. Как только реализовано – уже и не трудное, вроде.
Ну вот был момент, с которого «нахлебался». Разного рода артефакты встречались. «Достаешь» из localStorage что-то, а там что-то, чего быть не должно (какой-нибудь левый символ). Я не изучал что это было и не смог бы изучить, так как было это 2-3 года назад, когда опыта у меня было меньше. Но вот еще тогда принял решение ничего в первозданном виде в localStorage не хранить – все преобразуется в base64String.
Что еще? Вот есть до сих пор не разрешенная проблема – сброс. До сих пор ломаю голову как его реализовать корректно. Суть проста. В проекте используется модули A, B, С и D. Спустя какое-то время их взяли и переименовали на _A, _B, _С и _D. С точки зрения контроллера кэша – это новые ресурсы, так что в localStorage мы получим не 4-е модуля, а 8-ь, что не хорошо. Пока проблема решена через параметр при подключении flex.core.js?v=xxx, где xxx – произвольное число (версия). Если оно не совпадет с тем, что был ранее зафиксирован на клиенте (или не был зафиксирован вовсе), то будет выполнено localStorage.clear(). Кстати по этой же причине я отказался от кэширования картинок, что ранее задумывалось в рамках хотя бы иконок. Лучше браузера это пока никто не сделает :)
Вот другая сложность. Например, не все JS получится получить через xmlhttprequest – origin policy может быть настроена, что никак.
Есть еще проблема куда хуже, чем те что я перечислил уже. И тоже связана с JS. Это плохой код. Например, вот забыли вы поставить где-то банально «;». В 99 случаях из 100 вы этого даже и не узнаете, потому как браузер такие вещи «подправляет» за нас (что мне лично очень не нравится). Но браузер это подправляет только если скрипт подключен обычным способом, а вот если вы из localStorage его достали и интегрировали через new Function(content), просто как пример, то вас может ожидать сюрприз – throw какого-нибудь исключения, потому как в данном случае браузер уже ничего не «подправляет» за нас.
Или у вас есть old-school модуль, который требуется включить в проект. И этот вот модуль использует глобальные переменные. И объявляет их не как window[‘my_global_var’], а вот так var my_global_var. В результате такой модуль не будет работать корректно, потому как его интеграция будет проводится через new Function(content), то есть переменная my_global_var станет не глобальной к window, а глобальной в контексте функции.
Еще сложно «ловить» окончание загрузки CSS файлов. Это вам лучше посмотреть в коде flex.core.js, начиная со строки 4140. Сама проблема на 4178.
Если же говорить непосредственно о шаблонах, а не о ресурсах вроде JS и CSS, то здесь проблем не было. Были и есть проблемы со сборкой, как уже упомянутый тег table. Дело в том, что браузер не дает вам поместить, например, div в table (оно и верно), но это вас ограничивает, так как вы не можете создать временные «обертки» при сборке. В результате приходится проверять «совместимость» тегов, что несколько усложняет логику.
Надеюсь я в верном русле понял вопрос и с пользой ответил )
П.С.
В целом, задача сохранения ресурсов (JS и CSS) в localStorage может быть решена безусловно, но выставляет требования к качеству самих ресурсов, особенно JS.
Просто я искренне полагал (и полагаю), что рабочий «мусор» на паблике ни к чему. Есть файл, есть история с которой видны изменения ну и так далее.
Если вам интересен какой-то отдельный модуль, то просто сверните код до второго уровня вложенности и вы увидите все девять модулей по отдельности. Да и станет очевидным то, как все это собирается.
Для меня (я могу судить только по себе :)) главное приимущество: это возможность открывать шаблоны в отрыве от проекта, отлаживать их, править стили. Мне это удобно. Даже если компонент стал сложный, с логикой какой-то, то на создание тестовой страницы (что бы открыть его отдельно) уходит 3-и минуты и все, я снова могу отлаживать копмонент в отрыве от всего приложения.
ЗЫ
Документацию обновлю позже )
Но все равно, спасибо за хорошее критическое замечание, правда какое-то категоричное )
Я (честно) все время с момента моей публикации думаю о том, почему регистр модулей — это «зло». В том смысле, что в регистре объявляются только имена модулей и настройки кэширования – ничего больше – никаких зависимостей.
И я не могу понять, в чем потенциальная проблема такого регистра. Вы не первый, кто обращает внимание на некую проблему, пока характеризующуюся как «хлебнете», «не используйте» и так далее.
Я хочу, очень хочу понять в чем эта самая потенциальная проблема. И я понимаю, что регистр, где объявляются зависимости – это геморрой. Но если зависимостей в нем не объявляется?
Не эффективно с точки зрения дополнительной сущности? Да, с этой точки зрения – однозначное да – дополнительное телодвижение только для того, чтобы «убрать» пути из объявления модулей. Но разве с этого можно «хлебнуть»?
Изначально (пару лет назад) этот злополучный регистр как раз и содержал зависимости. То есть зависимости объявлялись не при объявлении модулей, а в регистре. И очень быстро я пришел к тому, что это крайне, крайне неудобно и неэффективно. Поэтому я оставил в регистре только и исключительно пути (ссылки на JS-файлы модулей), а также настройки кэширования. Ну и вроде как неудобств особых не испытывал в проектах до 50 модулей где-то.
Да, регистр засорялся ненужным ссылками (в результате copy / paste с других проектов), но и чистился за пару минут.
С другой стороны, я имел контроль над кэшированием в одном месте, да и несколько раз мне приходилось менять структуру папок на уже сданном проекте и тогда мне этот регистр был очень кстати, потому как все изменения вносились лишь в один файл и не приходилось «бегать» по проекту поиском, чтобы править каждый отдельный модуль (конечно, в requireJS все тоже самое через настройки, но я с ним и не конкурирую).
Я совершенно не исключаю, что я не прав, я даже знаю, что я ничего не знаю ))) Но очень прошу вас, развернуть ваш тезис о нависшем надо мною «хлебну» ))
Еще раз спасибо.
P.S.
Я либо не выспался, либо что-то не понимаю:
Таких больших проектов просто не встречал в практике и, честно сказать, не думал о них вовсе, работая над своим великом. Наиболее крупный, что был у меня – это где-то около 200 модулей (только JS файлы), где хоть и не использовались мои решения, но все же был единый регистр всех модулей, вынесенный в один файл. Было порядка 500 срок с описанием всяких особенностей и это было довольно удобно.
Может быть существует некий предел, после которого архитектура и применяемые решения должны как-то учитывать масштаб системы. Конечно, для проекта, где описание модулей занимает 4 – 5 тыс. строк что-то должно быть сделано иначе.
И еще, просто чтобы убедиться, что мы говорим об одном и том же. Под модулем я понимаю модуль без учета ресурсов. То есть модуль может запрашивать еще и какие-то ресурсы (CSS к примеру), которые не в какие регистры не вносятся, а определяются в рамках объявления модуля.
Я видел регистр всех ресурсов для большого проекта. Да, там было, если не ошибаюсь, порядка 6 тыс. строк. Но убери оттуда все CSS и вспомогательные ресурсы (вроде сторонних библиотек JS) и количество строк сократится кратно (именно кратно, потому что многие вспомогательные ресурсы объявляются многократно для указания зависимостей одного от другого).
flex.register.modules.js задумывался не как перечень всего и вся, а как место, где определяются «ключевые» (не знаю какое слово подобрать) модули. И никаких зависимостей, никаких ресурсов, ничего кроме просто путей к модулям в этом регистре не объявляется. Все ресурсы объявляются только на уровне объявления модуля (то есть в файле самого модуля). И с этой точки зрения для проекта с количеством модулей, скажем меньше 100, наличие единого регистра мне видится больше в позитивном свете, нежели, чем в негативном.
Но опять же, у меня нет богатого опыта работы с огромными проектами, где только модулей тысячи. Поэтому мое мнение очень субъективно, и я это понимаю.
Я просто отвечал на вопрос о встреченных трудностях, ну и перечислял те что встретил. eval я не использую, создав функцию через module = new Function(js_txt), я просто делаю module.call(window), что тоже самое с точки зрения результата.
А интеграция модулей вообще идет и без function и без call, чтобы сохранить привычку браузера «править» наши рутинные ошибки. Вот здесь flex.core.js, строки 4400 — 4410 – то как интегрируются модули в систему.
Тут большую роль играет личная мотивация. Посмотрите мой ответ вам чуть
нижевыше ).Знаете, меня столько раз это стопорило «Все уже придумано, написано – бери и используй!». Вот упрусь в какую-нибудь дилемму и сразу подобные мысли в голову лезут.
А потом вспоминаю, что ключевая мотивация у меня – это вопрос «а как это работает вообще?» и возвращаюсь к разработке ). Собственно, большую часть того, что можно делать в JS я узнал не из рабочих проектов (основная работа), а в процессе изобретения этого велика. Поэтому личный profit в виде опыта уже есть )
Что же касается AngularJS или же knockoutJS, или чего-то еще, то тут дело в том, что нет «конфликта интересов» — у меня просто нет такого выбора: использовать мои решения или AngularJS или же knockoutJS. Если заказчик говорит – делай что хочешь, я вежливо его спрашиваю – не против ли он стать «полигоном» для моих собственных наработок (если я понимаю, что оно не навредит). Не против? Чудно, беру ответственность на себя. Если решение должно быть на чем-то другом – не вопрос.
Если честно, на счет «трудного» не знаю. Как только реализовано – уже и не трудное, вроде.
Ну вот был момент, с которого «нахлебался». Разного рода артефакты встречались. «Достаешь» из localStorage что-то, а там что-то, чего быть не должно (какой-нибудь левый символ). Я не изучал что это было и не смог бы изучить, так как было это 2-3 года назад, когда опыта у меня было меньше. Но вот еще тогда принял решение ничего в первозданном виде в localStorage не хранить – все преобразуется в base64String.
Что еще? Вот есть до сих пор не разрешенная проблема – сброс. До сих пор ломаю голову как его реализовать корректно. Суть проста. В проекте используется модули A, B, С и D. Спустя какое-то время их взяли и переименовали на _A, _B, _С и _D. С точки зрения контроллера кэша – это новые ресурсы, так что в localStorage мы получим не 4-е модуля, а 8-ь, что не хорошо. Пока проблема решена через параметр при подключении flex.core.js?v=xxx, где xxx – произвольное число (версия). Если оно не совпадет с тем, что был ранее зафиксирован на клиенте (или не был зафиксирован вовсе), то будет выполнено localStorage.clear(). Кстати по этой же причине я отказался от кэширования картинок, что ранее задумывалось в рамках хотя бы иконок. Лучше браузера это пока никто не сделает :)
Вот другая сложность. Например, не все JS получится получить через xmlhttprequest – origin policy может быть настроена, что никак.
Есть еще проблема куда хуже, чем те что я перечислил уже. И тоже связана с JS. Это плохой код. Например, вот забыли вы поставить где-то банально «;». В 99 случаях из 100 вы этого даже и не узнаете, потому как браузер такие вещи «подправляет» за нас (что мне лично очень не нравится). Но браузер это подправляет только если скрипт подключен обычным способом, а вот если вы из localStorage его достали и интегрировали через new Function(content), просто как пример, то вас может ожидать сюрприз – throw какого-нибудь исключения, потому как в данном случае браузер уже ничего не «подправляет» за нас.
Или у вас есть old-school модуль, который требуется включить в проект. И этот вот модуль использует глобальные переменные. И объявляет их не как window[‘my_global_var’], а вот так var my_global_var. В результате такой модуль не будет работать корректно, потому как его интеграция будет проводится через new Function(content), то есть переменная my_global_var станет не глобальной к window, а глобальной в контексте функции.
Еще сложно «ловить» окончание загрузки CSS файлов. Это вам лучше посмотреть в коде flex.core.js, начиная со строки 4140. Сама проблема на 4178.
Если же говорить непосредственно о шаблонах, а не о ресурсах вроде JS и CSS, то здесь проблем не было. Были и есть проблемы со сборкой, как уже упомянутый тег table. Дело в том, что браузер не дает вам поместить, например, div в table (оно и верно), но это вас ограничивает, так как вы не можете создать временные «обертки» при сборке. В результате приходится проверять «совместимость» тегов, что несколько усложняет логику.
Надеюсь я в верном русле понял вопрос и с пользой ответил )
П.С.
В целом, задача сохранения ресурсов (JS и CSS) в localStorage может быть решена безусловно, но выставляет требования к качеству самих ресурсов, особенно JS.