Comments 38
Спасибо.
Если честно, на счет «трудного» не знаю. Как только реализовано – уже и не трудное, вроде.
Ну вот был момент, с которого «нахлебался». Разного рода артефакты встречались. «Достаешь» из 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.
Или у вас есть old-school модуль, который требуется включить в проект.
Решается примерно так: eval.apply(window, ...)
либо with(window){ code }
.
Я просто отвечал на вопрос о встреченных трудностях, ну и перечислял те что встретил. eval я не использую, создав функцию через module = new Function(js_txt), я просто делаю module.call(window), что тоже самое с точки зрения результата.
А интеграция модулей вообще идет и без function и без call, чтобы сохранить привычку браузера «править» наши рутинные ошибки. Вот здесь flex.core.js, строки 4400 — 4410 – то как интегрируются модули в систему.
eval я не использую, создав функцию через module = new Function(js_txt)
Ну это как сказать, не используете. new Function
это тот же самый eval
, со всеми вытекающими. Всех нюансов не знаю, но не стоит обманываться ;)
Подмечу дизайн промо-сайта. Просто, но круто. Мне прям очень нравится :)
А вообще, хорошая работа!
Честно говоря, читая ваши терзания про localStorage, ручное управление кешем и пр., меня не покидает ощущение, что если организовать всё иначе, то будет проще и надёжнее. Скажем я делаю так:
- Собираю JS-файлы в группы по смыслу и группирую по бандлам (для production-а).
- Все ресурсы, которые могут быть обновлены со временем гружу по
/etag/public...
ссылке. Т.е. как только ресурс будет обновлён, он будет грузиться по новому URI, и, таким образом проблема с инвалидацией кеша решена. - Все подобные ресурсы кешируются браузером, скажем, на месяц-два.
Итого, без localStorage
, bse64
, eval
-а, используя только нативные базовые возможности и никаких хаков, пользователь при повторной загрузке получает ответ 200
от собственного кеша, не обращаясь к серверу (т.е. без 304
). При первой же загрузке, вместо нескольких десятков файлов грузит 1-2 бандла. Это даёт некий оверхед по трафику (копеечный), зато большой буст к скорости загрузки, что, имхо, куда важнее.
Плюс, ещё не понравилось, то, что вы назвали едиными файлами конфигурации… Столько возни на ровном месте, и всё ради чего? Вместо тех же групп можно использовать директории и относительные пути. Значительно меньше телодвижений же. А от дубляжа зависимость-использование вы вроде бы не избавились.
Может быть я что-нибудь недопонял, sorry.
По поводу раздела JQ
: возьмите knockoutJS
или какую-нибудь альтернативу ему. И забудете про DOM и ручную работу с ним. Экономит время с чудовищной силой. Т.е. никаких _node
и .events().add
не потребуется :) 90% такого грязного кода будет решать либа, а вы будете писать только… гхм, viewModel-и, которые куда ближе к устной логике, которой вы бы могли описать задачу, чем возня с DOM-ом.
Спустя годик-два использования angularJS
, knockoutJS
или какой-нибудь другой реактивной либы вы сможете делать интерфейсы поразительной мощи и сложности за весьма краткое время. То что вы бы ранее отбросили просто потому, что "да на это год уйдёт", будете приниматься клепать с энтузиазмом, потому что теперь хватит и месяца :D
Знаете, меня столько раз это стопорило «Все уже придумано, написано – бери и используй!». Вот упрусь в какую-нибудь дилемму и сразу подобные мысли в голову лезут.
А потом вспоминаю, что ключевая мотивация у меня – это вопрос «а как это работает вообще?» и возвращаюсь к разработке ). Собственно, большую часть того, что можно делать в JS я узнал не из рабочих проектов (основная работа), а в процессе изобретения этого велика. Поэтому личный profit в виде опыта уже есть )
Что же касается AngularJS или же knockoutJS, или чего-то еще, то тут дело в том, что нет «конфликта интересов» — у меня просто нет такого выбора: использовать мои решения или AngularJS или же knockoutJS. Если заказчик говорит – делай что хочешь, я вежливо его спрашиваю – не против ли он стать «полигоном» для моих собственных наработок (если я понимаю, что оно не навредит). Не против? Чудно, беру ответственность на себя. Если решение должно быть на чем-то другом – не вопрос.
Нет, я не против велосипедов. Сам навелосипедил уже довольно много. Ну так навелосипедьте себе свой KnockoutJS, в рамках программы "хочу разобраться". Предварительно изучив и попробовав сущ-ие решения, ибо так будет быстрее и конечный продукт будет лучше. Суть в том, что руками ковыряться в DOM-е это муторно, долго и очень дорого.
Тут большую роль играет личная мотивация. Посмотрите мой ответ вам чуть
Таких больших проектов просто не встречал в практике и, честно сказать, не думал о них вовсе, работая над своим великом. Наиболее крупный, что был у меня – это где-то около 200 модулей (только JS файлы), где хоть и не использовались мои решения, но все же был единый регистр всех модулей, вынесенный в один файл. Было порядка 500 срок с описанием всяких особенностей и это было довольно удобно.
Может быть существует некий предел, после которого архитектура и применяемые решения должны как-то учитывать масштаб системы. Конечно, для проекта, где описание модулей занимает 4 – 5 тыс. строк что-то должно быть сделано иначе.
И еще, просто чтобы убедиться, что мы говорим об одном и том же. Под модулем я понимаю модуль без учета ресурсов. То есть модуль может запрашивать еще и какие-то ресурсы (CSS к примеру), которые не в какие регистры не вносятся, а определяются в рамках объявления модуля.
Я видел регистр всех ресурсов для большого проекта. Да, там было, если не ошибаюсь, порядка 6 тыс. строк. Но убери оттуда все CSS и вспомогательные ресурсы (вроде сторонних библиотек JS) и количество строк сократится кратно (именно кратно, потому что многие вспомогательные ресурсы объявляются многократно для указания зависимостей одного от другого).
flex.register.modules.js задумывался не как перечень всего и вся, а как место, где определяются «ключевые» (не знаю какое слово подобрать) модули. И никаких зависимостей, никаких ресурсов, ничего кроме просто путей к модулям в этом регистре не объявляется. Все ресурсы объявляются только на уровне объявления модуля (то есть в файле самого модуля). И с этой точки зрения для проекта с количеством модулей, скажем меньше 100, наличие единого регистра мне видится больше в позитивном свете, нежели, чем в негативном.
Но опять же, у меня нет богатого опыта работы с огромными проектами, где только модулей тысячи. Поэтому мое мнение очень субъективно, и я это понимаю.
Я (честно) все время с момента моей публикации думаю о том, почему регистр модулей — это «зло». В том смысле, что в регистре объявляются только имена модулей и настройки кэширования – ничего больше – никаких зависимостей.
И я не могу понять, в чем потенциальная проблема такого регистра. Вы не первый, кто обращает внимание на некую проблему, пока характеризующуюся как «хлебнете», «не используйте» и так далее.
Я хочу, очень хочу понять в чем эта самая потенциальная проблема. И я понимаю, что регистр, где объявляются зависимости – это геморрой. Но если зависимостей в нем не объявляется?
Не эффективно с точки зрения дополнительной сущности? Да, с этой точки зрения – однозначное да – дополнительное телодвижение только для того, чтобы «убрать» пути из объявления модулей. Но разве с этого можно «хлебнуть»?
Изначально (пару лет назад) этот злополучный регистр как раз и содержал зависимости. То есть зависимости объявлялись не при объявлении модулей, а в регистре. И очень быстро я пришел к тому, что это крайне, крайне неудобно и неэффективно. Поэтому я оставил в регистре только и исключительно пути (ссылки на JS-файлы модулей), а также настройки кэширования. Ну и вроде как неудобств особых не испытывал в проектах до 50 модулей где-то.
Да, регистр засорялся ненужным ссылками (в результате copy / paste с других проектов), но и чистился за пару минут.
С другой стороны, я имел контроль над кэшированием в одном месте, да и несколько раз мне приходилось менять структуру папок на уже сданном проекте и тогда мне этот регистр был очень кстати, потому как все изменения вносились лишь в один файл и не приходилось «бегать» по проекту поиском, чтобы править каждый отдельный модуль (конечно, в requireJS все тоже самое через настройки, но я с ним и не конкурирую).
Я совершенно не исключаю, что я не прав, я даже знаю, что я ничего не знаю ))) Но очень прошу вас, развернуть ваш тезис о нависшем надо мною «хлебну» ))
Еще раз спасибо.
P.S.
Я либо не выспался, либо что-то не понимаю:
«…но не выносите зависимости из кода…»
«Выносить зависимости из кода необходимо.»
JS Загрузчик + шаблонизатор или история очередного велика