Pull to refresh

Comments 38

я конечно не фронтэндщик, но чем не мил Вам Angular?
Я не пытался повторить Angular и против него ничего не имею. Мне хотелось создать некую платформу (извините, если термин не подходит). То есть мне не нужен весь багаж Angular, не нужны все возможности RequireJS. Мне нужна была некая база, которую я могу использовать как в минимальной комплектации, так и существенно расширенной (включая шаблонизатор, биндинги и прочее прочее).
На чем бы автор не писал, он был занят этим последние года 3-4 минимум.
Ну в самом начале я об этом и сказал — 3-4 года — это правда. Но не так что б каждый день. Если как-то усреднить, то, наверное, 2-4 часа в неделю — не больше. Да и переписывалось все 3 раза, вроде бы.
Нет, я ее босюсь. И в сфере web-разработки всего лишь с 2011 года. История моих постов как раз с того момента )
Крутяк) Тоже когда-то задумывался о кешировании шаблонов handlebars, но так руки и не дошли до создания своего велика. Спасибо, статья была интересной)
Не могли бы вы подсказать подводные камни кеширования шаблонов (у меня lodash из backbone) в localStorage? Пока пришло в голову подсчет md5 на сервере и подсчет его на клиенте. О прочтении header'ов что-то не додумался. Может быть что подскажете? что было трудным?
Спасибо.
Спасибо за комментарий. И вопрос.

Если честно, на счет «трудного» не знаю. Как только реализовано – уже и не трудное, вроде.

Ну вот был момент, с которого «нахлебался». Разного рода артефакты встречались. «Достаешь» из 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.apply(window, ...) и module.call(window) далеко не тот же самый результат. faiwer, спасибо за наводку на мысль )

Про eval.apply(window, ...) я узнал случайно, когда изучал исходники jQuery. В последствии они отказались от такого подхода в пользу чего-то вроде document.head.appendChild(script).

eval я не использую, создав функцию через module = new Function(js_txt)

Ну это как сказать, не используете. new Function это тот же самый eval, со всеми вытекающими. Всех нюансов не знаю, но не стоит обманываться ;)

Как-то все замудрено у вас. Мне лично нравится использовать Webpack для этих целей. Там и компоновка и ленивая загрузка и пр.
Подмечу дизайн промо-сайта. Просто, но круто. Мне прям очень нравится :)
Говорят, через localStorage шрифты можно кешировать, а не только js и css.
А вообще, хорошая работа!
Спасибо ) На счет шрифтов, мне даже такая мысль в голову не приходила ) Но это интересно, спасибо за наводку.
UFO just landed and posted this here
Пока не пробовал реализовать, но мысли такие есть )

Честно говоря, читая ваши терзания про 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-е это муторно, долго и очень дорого.

Ну так у меня все еще впереди )
Вы все верно поняли ) И предложенные вами решения верны со всех точек зрения и мало того применяются в том числе мною. Не в этом ли вся прелесть нашей профессии – во множестве решений одних и тех же задач? )

Тут большую роль играет личная мотивация. Посмотрите мой ответ вам чуть ниже выше ).

В таком случае рекомендую следующий велосипед организовать уже через браузерное кеширование, е-tag-и, при необходимости 304, сборку в бандлы. Правда, если честно, современный frontend даже без велосипедов уже слишком сложный. Ынтерпрайз пришёл и к нам. Даже DI используют.

В поносящему больших проектах ручное управление зависимостями приведет к аду, это очень плохое решение.
Поясните, пожалуйста, что вы имеете ввиду под «ручным» управлением зависимостей? Спасибо.
То что вы делаете в конфиге описывая руками какие файлы откуда тянуть это и есть ручное управление зависимостями. В больших проектах таки конфиги вырастают до неприличных 3к-5к тысяч строк и управлять всем этим становится не просто тяжело, а практически невозможно. Самый правильный и верный способ это описывать зависимости в коде и точка, не нравится amd паттерн который в requirejs, пишите commonjs модули, которые являются стандартом в мире nodejs. Не устраивает commonjs? Используйте новый стандарт Systemjs, но не выносите зависимости из кода иначе потом так и хлебнете что отмываться устанете.
Спасибо.

Таких больших проектов просто не встречал в практике и, честно сказать, не думал о них вовсе, работая над своим великом. Наиболее крупный, что был у меня – это где-то около 200 модулей (только JS файлы), где хоть и не использовались мои решения, но все же был единый регистр всех модулей, вынесенный в один файл. Было порядка 500 срок с описанием всяких особенностей и это было довольно удобно.

Может быть существует некий предел, после которого архитектура и применяемые решения должны как-то учитывать масштаб системы. Конечно, для проекта, где описание модулей занимает 4 – 5 тыс. строк что-то должно быть сделано иначе.

И еще, просто чтобы убедиться, что мы говорим об одном и том же. Под модулем я понимаю модуль без учета ресурсов. То есть модуль может запрашивать еще и какие-то ресурсы (CSS к примеру), которые не в какие регистры не вносятся, а определяются в рамках объявления модуля.

Я видел регистр всех ресурсов для большого проекта. Да, там было, если не ошибаюсь, порядка 6 тыс. строк. Но убери оттуда все CSS и вспомогательные ресурсы (вроде сторонних библиотек JS) и количество строк сократится кратно (именно кратно, потому что многие вспомогательные ресурсы объявляются многократно для указания зависимостей одного от другого).

flex.register.modules.js задумывался не как перечень всего и вся, а как место, где определяются «ключевые» (не знаю какое слово подобрать) модули. И никаких зависимостей, никаких ресурсов, ничего кроме просто путей к модулям в этом регистре не объявляется. Все ресурсы объявляются только на уровне объявления модуля (то есть в файле самого модуля). И с этой точки зрения для проекта с количеством модулей, скажем меньше 100, наличие единого регистра мне видится больше в позитивном свете, нежели, чем в негативном.

Но опять же, у меня нет богатого опыта работы с огромными проектами, где только модулей тысячи. Поэтому мое мнение очень субъективно, и я это понимаю.
UFO just landed and posted this here
Спасибо большое за комментарий.

Я (честно) все время с момента моей публикации думаю о том, почему регистр модулей — это «зло». В том смысле, что в регистре объявляются только имена модулей и настройки кэширования – ничего больше – никаких зависимостей.

И я не могу понять, в чем потенциальная проблема такого регистра. Вы не первый, кто обращает внимание на некую проблему, пока характеризующуюся как «хлебнете», «не используйте» и так далее.

Я хочу, очень хочу понять в чем эта самая потенциальная проблема. И я понимаю, что регистр, где объявляются зависимости – это геморрой. Но если зависимостей в нем не объявляется?

Не эффективно с точки зрения дополнительной сущности? Да, с этой точки зрения – однозначное да – дополнительное телодвижение только для того, чтобы «убрать» пути из объявления модулей. Но разве с этого можно «хлебнуть»?

Изначально (пару лет назад) этот злополучный регистр как раз и содержал зависимости. То есть зависимости объявлялись не при объявлении модулей, а в регистре. И очень быстро я пришел к тому, что это крайне, крайне неудобно и неэффективно. Поэтому я оставил в регистре только и исключительно пути (ссылки на JS-файлы модулей), а также настройки кэширования. Ну и вроде как неудобств особых не испытывал в проектах до 50 модулей где-то.

Да, регистр засорялся ненужным ссылками (в результате copy / paste с других проектов), но и чистился за пару минут.

С другой стороны, я имел контроль над кэшированием в одном месте, да и несколько раз мне приходилось менять структуру папок на уже сданном проекте и тогда мне этот регистр был очень кстати, потому как все изменения вносились лишь в один файл и не приходилось «бегать» по проекту поиском, чтобы править каждый отдельный модуль (конечно, в requireJS все тоже самое через настройки, но я с ним и не конкурирую).

Я совершенно не исключаю, что я не прав, я даже знаю, что я ничего не знаю ))) Но очень прошу вас, развернуть ваш тезис о нависшем надо мною «хлебну» ))

Еще раз спасибо.

P.S.
Я либо не выспался, либо что-то не понимаю:
«…но не выносите зависимости из кода…»

«Выносить зависимости из кода необходимо.»
Честно — не погружался глубоко.
Стоило бы
внешний вид — фактически решается плагинами для сборщика
система кеширования — решается этими самыми плагинами
Sign up to leave a comment.

Articles