Перенос загрузки скриптов JS в футер 2.X

440
День добрый,

Почему нужно грузить js после контента можно почитать, например тут. Если кратко - это нужно для того, чтобы ускорить загрузку страниц. В блогах и на форуме готового решения не нашел, если пропустил - кидайте в комментах.

На гите инициатива делить теги на те, что нужно грузить в head и те, что в перед </body> потерпела неудачу (возможно, моей аргументации не хватило), поэтому напишу что можно сделать на текущий момент для реализации этой идеи.

На InstantCMS2 есть для этого механизм - почти без танцев, почти без бубна. Но некоторые нюансы есть, поэтому появилось желание оформить это постом.

В чем сложность:
Нам надо оставить часть скриптов сверху, а часть снизу - а функция для вывода js только одна $this->printJavascriptTags. Сверху должна быть статистика и те скрипты, без которых код на странице выдаст ошибки при загрузке.

Решение этой задачи сводится к внесению изменений в один файл шаблона main.tpl.php. Минус в том, что мы больше не сможем использовать методы addMainJS, addControllerJS, addJSFromContext для скриптов, которые нужно загрузить в секцию head, но если на кону скорость загрузки страницы... Еще минус в том, что мы грузим jquery напрямую и возможны ситуации, когда этот скрипт повторно загрузится снизу.. Обычно такого не должно быть, но ситуация возможна.

Решение

1. Подключаем jquery в блоке head напрямую.
В шаблоне вместо
Код PHP:
  1. <?php $this->addMainJS("templates/{$this->name}/js/jquery.js"); ?>
вставляем строку
Код PHP:
  1. <script type="text/javascript" src="/templates/default/js/jquery.js"></script>
2. Грузим сверху все css и другие теги (сюда могут попасть и js, которые добавлены через функцию addHead)
Заменяем строку
Код PHP:
  1. <?php $this->head(); ?>
на
Код PHP:
  1. <?php $this->head(true, false, true); ?>
3. Добавляем перед </body> строку
Код PHP:
  1. <?php $this->printJavascriptTags(); ?>
После этих замен сверху будут грузиться все стили, jquery и другие теги, которые добавлены через метод addHead.

Остается вопрос - что делать со скриптами, которые обязательно должны грузиться сверху? - их нужно подключать не через addMainJS или addControllerJS. Подключать их теперь нужно только через addHead и тогда они попадут в блок <head></head>.
Релиз компонента Smart Slider, бесплатная версия | Обновление компонентов для корректной работы в InstantCMS 2.8.1
Комментарии (21)
Олег Васильевич я 8 сентября 2017 в 14:35 0
small user social cms
Супер!
Будем разбираться.
Спасибо!
Олег Васильевич я 8 сентября 2017 в 15:17 0
small user social cms
Остается вопрос - что делать со скриптами, которые обязательно должны грузиться сверху? - их нужно подключать не через addMainJS или addControllerJS. Подключать их теперь нужно только через addHead и тогда они попадут в блок <head></head>.
Возможно, тупой, вопрос: наследуемость шаблона при таком подключении не пострадает?
Спасибо!
@SmartControl 8 сентября 2017 в 15:38 0
small user social cms
Прочитал в документации про наследование - не пострадает. Все изменения вносятся в main.tpl.php основного шаблона, а наследование то касается подключаемых файлов - шаблонов страниц и CSS/JS файлы.
Evanescence 8 сентября 2017 в 15:52 +2
small user social cms
Когда то тоже занялся этим вопросом, в итоге решил что подключаемые js скрипты должны оставаться на верху.
Уже не помню какие проблемы возникли, но core.js, rating.js и еще несколько, должны быть на верху, так как перед footer-ом есть такой код https://prnt.sc/ginla2

По этому, без таких методов как $this->addFooterJS() и для вывода $this->footer() на мой взгляд не получиться грамотно реализовать
@SmartControl 8 сентября 2017 в 16:01 0
small user social cms
Согласен, нужны обновления соответствующие. На гите у меня с первого раза не вышло это доходчиво донести и предложение было отклонено - вот может этот пост даст более качественную аргументацию почему это нужно сделать на уровне движка.
@spartak 8 сентября 2017 в 16:21 0
small user social cms
Заодно может рассмотрят код core.js..ну или хотя бы сделают отдельные core.js для шаблона сайта и шаблона админки..В админке половина кода из этого файла вообще не нужно.. в шаблоне сайта приходиться редактировать этот файл постоянно..на пример при подключении bootstap очень мешает использование тегов nav в этом файле...Извиняюсь. Отошел от темы.
vikont 8 сентября 2017 в 18:19 0
small user social cms
Хочу вас огорчить, уже поднимался этот вопрос, на что "отцы создатели" Инстанта предложили не заморачиваться и отправить Гугломерку скорости загрузки страниц куда подальше....
Предполагаю, что данный вопрос пока труднореализуемый или действительно не стоит всех усилий.
@SmartControl 8 сентября 2017 в 19:05 0
small user social cms
Да причём тут гугломерка.. тут вопрос как быстро пользователь страницу увидит. Реализовать просто, но если желания делать это красиво нет, то каждый будет под себя настраивать.
letsgo 8 сентября 2017 в 20:30 0
small user social cms
Себе делал, но также пришёл к выводу что лучше сверху. Скорость показатели можно и другим догнать, но подмигивание при загрузке некрасиво.
@SmartControl 8 сентября 2017 в 21:02 0
small user social cms
Да, возможно. Вообще - это неправильное решение. Делать надо по-другому.. Но это придется хакать файлы движка, чего не хочется (по-крайней мере в паблик я это писать не буду - сделаю для себя только).
Нельзя массово переносить скрипты вниз. этим нужно управлять. Не все скрипты приводят к "подмигиванию", какие-то можно безболезненно убрать вниз.
Fuze 8 сентября 2017 в 21:15 +1
small user social cms
Нет смысла убирать скрипты выборочно, если стремиться к показателям. Второе, просто так скрипты вниз перенести нельзя, есть еще инлайновые скрипты, использующие jquery и которые перестанут работать. Все

Код JAVASCRIPT:
  1. $(function(){
  2. // что-то там
  3. });
нужно менять на что то вроде

Код JAVASCRIPT:
  1. document.addEventListener('DOMContentLoaded', function (){
  2. // что-то там
  3. });
@SmartControl 8 сентября 2017 в 21:37 0
small user social cms
Нет смысла убирать скрипты выборочно, если стремиться к показателям

Простой пример. У меня есть компонент, который грузит 200кб скриптов - я их подключаю у себя снизу (добавил хук "print_footer"), потому что незачем тратить время на загрузку пользователем 200кб скрипта. Но я не могу дать пользователям такую возможность без правок шаблона, а добавлять такое требование к компоненту не хочу - это усложняет использование компонента.. В итоге получается все пользователи вынуждены замедлять загрузку страницы из-за одного компонента, который этого даже не требует - ему все-равно где и что подгружать.

Решение для себя вижу в добавлении доп настроек - если пользователь руками хочет добавить хук, то скрипт будет подключаться внизу. Если не хочет, то сверху со всеми вместе.

Второе, просто так скрипты вниз перенести нельзя, есть еще инлайновые скрипты, использующие jquery и которые перестанут работать.
Согласен, в моем решении (которое в посте и описано) jquery принудительно грузится сверху. В все остальное внизу.
Val 8 сентября 2017 в 21:53 0
small user social cms
Физически время полной загрузки страницы не меняется от положения скриптов на ней)) Меняется ощущение пользователя, т.е. уменьшается время пока пользователь увидит первый текст на странице.
Т.к. это CMS т.е. система для сайтостроителей без глубоких знаний программирования, то при переносе скриптов к футеру резко повышается вероятность всевозможных ошибок инлайн скриптов которые сделаны так чтобы сразу выполняться (и это не оф. разработчики так делают, а сторонние горе программисты или сами админы сайтов находят на просторах интернета). И посыпятся куча претензий от таких сайтостроителей что ничего не работает и во всем этом виноват движок, а не их кривые руки.
И последнее, если не ошибаюсь в современных стандартах и современных браузерах (IE 10+) подгружать скрипты можно в неблокирующем асинхронном режиме ( ссылка). По сути тот же эффект что и перемещение к закрывающему тегу body. Можно в функции типа addJS(), addMainJS() и др. добавить флаг is_async или is_defer кому надо чтобы пользовался)) без костылестроения.
@SmartControl 8 сентября 2017 в 22:09 0
small user social cms
Физически время полной загрузки страницы не меняется от положения скриптов на ней))
Все верно. От перемены мест слагаемых сумма не меняется. Забота именно о картинке, которую увидит пользователь - ускорить ее появление.

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

И последнее, если не ошибаюсь в современных стандартах и современных браузерах (IE 10+) подгружать скрипты можно в неблокирующем асинхронном режиме
Да, это вариант. Если нам не важен порядок загрузки скриптов, потому что при такой загрузке скрипты загрузятся не по порядку следования в документе, а как попало - асинхронность она ж такая...

Я нашел решение, как буду делать для своих компонентов.. Это будет просьба для пользователей добавить хук в перед </body>, в противном случае загрузка в head c атрибутом async - это не самый плохой вариант.
Val 8 сентября 2017 в 22:45 0
small user social cms
@SmartControl:
Если нам не важен порядок загрузки скриптов, потому что при такой загрузке скрипты загрузятся не по порядку следования в документе, а как попало
Не совсем, почитайте подробнее про defer ;)
С другой стороны, блокировки контента не будет, эффект пользователя достигнет, а то что какой либо скрипт подгрузится позже (не в порядке следования) на работоспособность страницы не повлияет (если конечно с умом подходить к вопросу).
Олег Васильевич я 9 сентября 2017 в 10:51 0
small user social cms
Можно в функции типа addJS(), addMainJS() и др. добавить флаг is_async или is_defer кому надо чтобы пользовался)) без костылестроения.
Val, за многое, что сделали вам признателен (уверен, не я один).
Предложите решение в виде от которого разработчики не смогут отказаться и я ваш стописяттысячный должник!
Val 9 сентября 2017 в 12:55 0
small user social cms
Как я ниже описал двумя строками кода решить вопрос не получится. Поэтому прежде чем с головой окунаться в проблему, хотелось бы от разработчиков знать - а надо ли? В противном случае можно потратить время, сделать решение которое все равно не будет востребовано.
@SmartControl 9 сентября 2017 в 11:14 0
small user social cms
Стоп, вы предлагаете добавить костыль в addJS(), addMainJS(), чтобы работать без костылестроения?)) - так в том то и вопрос, что нужно обновить движок, чтобы все было красиво. Я же с этого и начинал. Сейчас возможностей не хватает, чтобы делать со скриптами то, что хочется.

Костылями я и сам могу что угодно провернуть, но дело в том, что пользователи моего компонента "костылять" не будут, я их и просить об этом не стану..

Я вас прекрасно понимаю, про is_async и is_defer, но сейчас это костыли.
Val 9 сентября 2017 в 12:37 0
small user social cms
У нас разное видение костылестроительной отрасли smile
Я предложил вариант по примеру функций html компонентов (html_input, html_textarea и др.). В них есть возможность добавлять свои атрибуты для тега ( $attributes=array() ). Но просто так добавить атрибуты в JS (и CSS) нельзя. Конечно нужно допиливать весь механизм сбора js-тегов их мерж и вывод. В текущей версии движка из коробки этого нет. Если сделать получим возможность сбора всех JS в одном месте и не блокированную загрузку тех из них которые разработчик дополнения посчитал возможным и необходимым это сделать. Т.е. более логично все скрипты видеть в одном месте чем разбросанными по странице.

Откровенно говоря лишь единицы захотят разбираться с асинхронностью и допиливать свои дополнения чтобы страница прогрузилась на 70 мсек быстрее)). Поэтому "овчинка не стоит выделки".
Я лишь указал что такое возможно. Но я не говорил что это делается в 2 клика.

Если делать, то делать все в одном месте или внизу или вверху. Внизу для универсальной CMS опасно. Поэтому логично сделано вверху. Если хочется получить возможность оптимизации загрузки - то логичнее дорабатывать атрибуты, а не разбрасывать скрипты по странице.
@SmartControl 9 сентября 2017 в 12:54 0
small user social cms
Откровенно говоря лишь единицы захотят разбираться с асинхронностью и допиливать свои дополнения чтобы страница прогрузилась на 70 мсек быстрее)). Поэтому "овчинка не стоит выделки".

Я бы добавил - лишь единицы могут разрабатывать компоненты, поэтому можно не париться)) Позиция не супер для универсальной CMS.. Нужно добавлять и атрибуты (атрибуты может быть важнее и приоритетнее - да и проще) и вывод внизу - я все-таки думаю, что должна быть универсальность.

Какой -то забавный спор выходит. Первая позиция - "надо сделать универсальней". Вторая - "да ладно, и так пойдет". Если пойдет, то конечно можно не продолжать) Как-нибудь и так будет работать, работало же раньше, можно и не пытаться сделать лучше и быстрее - не пойдем на поводу у гугломерок.

Для нормальных посещаемых сайтов и 70 мсек имеют значение если это задержка только от одного компонента. которых могут быть десятки.
@SmartControl 9 сентября 2017 в 13:04 0
small user social cms
SmartControl:
Я вас прекрасно понимаю, про is_async и is_defer, но сейчас это костыли.

Точнее их можно использовать только в функции addHead - там все что хочешь.. И атрибуты, и теги и тд.. И все выведется сверху.