Автоматическая смена версии стилей при очистке кэша в MODX
Решил поделиться своим решением версионирования файлов стилей. Зачем нужно версионирование, я, наверное не буду объяснять. Вообще смена версий не такой частый процесс и зачастую он нужен не только для того, чтобы браузеры подхватывали измерения в стилях, но и для отслеживания версий сайта. Вариантов как это реализовать масса. Я состряпал наиболее подходящее для меня и решил поделиться им.
К слову, пока писал этот пост, в телеграм канале как раз подняли эту тему. :-)
Для начала создадим контекстную настройку, запускаем скрипт в консоли:
Далее создаем плагин и вешаем его на событие OnBeforeCacheUpdate. Я использую версионирование с текущей датой, мне так проще.
После фидбэка от Василия Наумкина, сделал вариант плагина который проверяет изменения в указанных файлах и при наличии таковых, заменяет версию. В плагине укажите пути к своим файлам стилей, которые необходимо проверять на наличие изменений.
У меня так же есть версия плагина с рандомной строкой, если нужно могу скинуть.
Ну и к стилям дописываем вывод значения настройки:
Конечно кто-то скажет что вариант слишком громоздкий. Но меня он вполне устраивает. Если кто-то поделится своим решением, более цивилизованным — то будет круто. Каждый подберет для себя более оптимальное решение.
К слову, пока писал этот пост, в телеграм канале как раз подняли эту тему. :-)
Шаг 1
Для начала создадим контекстную настройку, запускаем скрипт в консоли:
$contextKey = 'style_version';
if (!$contextSetting = $modx->getObject('modContextSetting', array('key' => $contextKey))) {
$contextSetting = $modx->newObject('modContextSetting');
}
$contextSetting->set('context_key', 'web');
$contextSetting->set('key', 'style_version');
$contextSetting->set('value', '');
$contextSetting->set('xtype', 'textfield');
$contextSetting->set('namespace', 'core');
$contextSetting->set('area', 'Site');
$contextSetting->save();
// Clear the cache:
$modx->cacheManager->refresh(array(
'context_settings' => array('contexts' => array('web'))
));
Шаг 2
Далее создаем плагин и вешаем его на событие OnBeforeCacheUpdate. Я использую версионирование с текущей датой, мне так проще.
if ($modx->event->name == 'OnBeforeCacheUpdate') {
// Version as current date
$today = date("dmY");
// Check if we have context with key style_version
if (!$contextSetting = $modx->getObject('modContextSetting', array('key' => 'style_version', 'context_key' => 'web'))) {
return;
}
$contextSetting->set('value', $today);
$contextSetting->save();
// clear context cache
// $modx->cacheManager->refresh(array(
// 'context_settings' => array('contexts' => array('web'))
// ));
}
После фидбэка от Василия Наумкина, сделал вариант плагина который проверяет изменения в указанных файлах и при наличии таковых, заменяет версию. В плагине укажите пути к своим файлам стилей, которые необходимо проверять на наличие изменений.
<?php
if ($modx->event->name == 'OnBeforeCacheUpdate') {
// which files we must check
$files = [
'public/template/css/styles.css',
'public/template/js/scripts.min.js'
];
$lastChangeTime = 0;
// check every file
foreach($files as $file){
$filepath = MODX_BASE_PATH.$file;
if (file_exists($filepath) && filemtime($filepath) > $lastChangeTime) {
$lastChangeTime = filemtime($filepath);
}
}
// Show result as date/month/year/hour/minutes/seconds
$lastChangeTime = date('dmYHis', $lastChangeTime);
// Check if we have context with key style_version
if (!$contextSetting = $modx->getObject('modContextSetting', array('key' => 'style_version', 'context_key' => 'web'))) {
return;
}
$contextSetting->set('value', $lastChangeTime);
$contextSetting->save();
// clear context cache
// $modx->cacheManager->refresh(array(
// 'context_settings' => array('contexts' => array('web'))
// ));
}
У меня так же есть версия плагина с рандомной строкой, если нужно могу скинуть.
Шаг 3
Ну и к стилям дописываем вывод значения настройки:
<link rel="stylesheet" href="public/template/css/styles.css?v={$_modx->config.style_version}" type="text/css"/>
<script src="public/template/js/scripts.min.js?v={$_modx->config.style_version}" type="text/javascript"></script>
Конечно кто-то скажет что вариант слишком громоздкий. Но меня он вполне устраивает. Если кто-то поделится своим решением, более цивилизованным — то будет круто. Каждый подберет для себя более оптимальное решение.
Поблагодарить автора
Отправить деньги
Комментарии: 17
То есть, даже если ничего не поменялось, а просто сбросили кэш — то юзер перекачивает файлы заново? Как-то это не очень логично.
Лучше уж тогда своим PHP скриптом вставлять в настройку не текущую дату, а дату изменения файлов, или считать их хэш. Чтобы все файлы качались только когда хоть один из них изменился.
Ну а совсем уж идеальный вариант — собирать скрипты и стили через npm и уже там добавлять хэш каждому файлу, автоматически. Чтобы юзер качал только изменённые, а не все.
Лучше уж тогда своим PHP скриптом вставлять в настройку не текущую дату, а дату изменения файлов, или считать их хэш. Чтобы все файлы качались только когда хоть один из них изменился.
Ну а совсем уж идеальный вариант — собирать скрипты и стили через npm и уже там добавлять хэш каждому файлу, автоматически. Чтобы юзер качал только изменённые, а не все.
Клиенты кэш редко сбрасывают, если вообще сбрасывают. Такое происходит только когда я вношу правки и соответственно я знаю что при очистке кэша, плагин подхватит текущую дату. Плюс, в моем варианте дата указывается в формате день/месяц/год. Так что, в день пользователь максимум 1 раз скачивает файлы стилей. На некоторых сайтах я вообще использую формат месяц/год.
Ну а вообще да, надо бы сделать версию с функцией
Ну а вообще да, надо бы сделать версию с функцией
filemtime
Клиенты кэш редко сбрасывают, если вообще сбрасывают.Ты же вроде для всех пишешь, а не только для себя.
Решение должно быть универсальным.
Плюс, в моем варианте дата указывается в формате день/месяц/год.Это, как раз-таки, минус. Потому что посетитель сможет увидеть только одну правку файлов в день.
Тоже верно, значит есть смысл написать вариант плагина с filemtime. Займусь этим и чуть позже дополню статью еще одним вариантом.
Спасибо за фидбэк!
Спасибо за фидбэк!
Только сейчас увидел
Замени на
Это ж как нужно не читать документацию, чтобы такие велосипеды городить?!
$today = date("d-m-Y");
$today = trim(preg_replace('/[^0-9]+/', ' ', $today));
$today = str_replace(' ', '', $today);
Замени на
$today = date("dmY");
Это ж как нужно не читать документацию, чтобы такие велосипеды городить?!
Да уж, спасибо, вот так и рождается говнокод… :-))
Обновил пост, добавил версию плагина который проверяет когда последний раз изменялся файл.
Обновил пост, добавил версию плагина который проверяет когда последний раз изменялся файл.
Ну теперь можно вообще сделать один маленький сниппет
И использовать его как-то так:
<?php
$filepath = MODX_BASE_PATH . $input;
if (file_exists($filepath)) {
return $input . '?v=' . date('dmYHis', filemtime($filepath));
}
И использовать его как-то так:
<link rel="stylesheet" href="{'public/template/css/styles.css' | version}" type="text/css"/>
<script src="{'public/template/js/scripts.min.js' | version}" type="text/javascript"></script>
Так можно, конечно, но сниппет будет дёргаться и проверять файл на каждой странице — нафига это надо? Вариант с системной настройкой как-бы кэширует эту работу.
В принципе, можно вызывать и сниппет кэшированным
Всё работает, все довольны.
В принципе, можно вызывать и сниппет кэшированным
<link rel="stylesheet" href="[[version?input=`public/template/css/styles.css`]]" type="text/css"/>
<script src="[[version?input=`public/template/js/scripts.min.js`]]" type="text/javascript"></script>
Систаксис MODX пропишет результат работы прямо в кэш страницы, и удалит при общем сбросе кэша. Всё работает, все довольны.
мне кажется, лучше всего возвращать не дату, а md5 хеш файла, по типу как работает gulp-version-number, таким образом хеш изменится только тогда, когда в файле будут внесены изменения, но тут уж кому что нравится))
А вот тут интересно — если файл большой, то какая операция быстрее — вычисление хеша файла или чтение даты его изменения? Надо бы потестировать…
Насколько я понимаю, посмотреть время изменения всегда будет быстрее, так как оно пишется в inode файловой системы, для этого даже не нужно читать сам файл.
Но и у файла можно читать не всё содержимое, а первые 100 байт, например. В любом случае, речь идёт о микросекундах.
Но и у файла можно читать не всё содержимое, а первые 100 байт, например. В любом случае, речь идёт о микросекундах.
Оставлю данный метод- протестированы на 5 сайтах, полет отличный!
Мне, как немолодому человеку и ввиду возраста начинающему брюзжать по каждому поводу, кажется что современные подходы в программировании направлены на избыточное усложнение.
В 95 процентов случаев веб разработчики делают довольно простые проекты, но стремятся наворотить туда как можно больше технологий — композеры, пайпы, варганты, докеры, препроцессоры, галпы, боуэры, энпээмы, рэст фулы, вотчеры, системы контроля версий…
На мой взгляд и вопрос с кешированием файлов стилей и скриптов также чрезмерно раздут. Прочел и ужаснулся, люди целые программы разрабатывают для этого. Разве не правильнее просто завести в каком-то своем пространстве имен свою системную настройку в которой будет лежать число. Это число и добавляеть как версию файла к стилям и скриптам. Во время разработки сайта это кеширование вообще не имеет смысла, достаточно нажать в браузере ctrl+f5 и весь кеш браузера слетел. На продакшине даже если и пришлось вносить какие то доработку в верстку или стили, зашел и в админке сменил цифру 3 на 4 в системных настройках. И все, все пользователи скачают новые файлы.
В 95 процентов случаев веб разработчики делают довольно простые проекты, но стремятся наворотить туда как можно больше технологий — композеры, пайпы, варганты, докеры, препроцессоры, галпы, боуэры, энпээмы, рэст фулы, вотчеры, системы контроля версий…
На мой взгляд и вопрос с кешированием файлов стилей и скриптов также чрезмерно раздут. Прочел и ужаснулся, люди целые программы разрабатывают для этого. Разве не правильнее просто завести в каком-то своем пространстве имен свою системную настройку в которой будет лежать число. Это число и добавляеть как версию файла к стилям и скриптам. Во время разработки сайта это кеширование вообще не имеет смысла, достаточно нажать в браузере ctrl+f5 и весь кеш браузера слетел. На продакшине даже если и пришлось вносить какие то доработку в верстку или стили, зашел и в админке сменил цифру 3 на 4 в системных настройках. И все, все пользователи скачают новые файлы.
Конечно, старичкам трудно осваивать что-то новое, им бы внуков понянчить.
Еще недавно я так же вручную менял версию, но всё время выходило вот так:
И теперь это уже автоматизировано.
На мой взгляд и вопрос с кешированием файлов стилей и скриптов также чрезмерно раздут. Прочел и ужаснулся, люди целые программы разрабатывают для этого.Внезапно, программисты любят писать программы и автоматизировать свой труд!
Во время разработки сайта это кеширование вообще не имеет смысла, достаточно нажать в браузере ctrl+f5 и весь кеш браузера слетел.А еще лучше использовать webpack-dev-server, которому ничего и нажимать не надо, он в реальном времени отображает все изменения из IDE.
На продакшине даже если и пришлось вносить какие то доработку в верстку или стилиТо просто выгрузил все изменения из IDE и запустил npm run build. Чтобы не ошибиться и не забыть что-то нажать в админке.
Еще недавно я так же вручную менял версию, но всё время выходило вот так:
И теперь это уже автоматизировано.
В 95 процентов случаев веб разработчики делают довольно простые проектыНо бывает и наоборот, когда разработчик продолжает развиваться и делает всё более сложные проекты.
Ну на самом деле этот скрипт нужен например когда клиент вносит правки и ты с ним налету делаешь изменения чтобы он посмотрел. Большая часть клиентов не знает что можно скинуть кеш страницы, или он может быть с телефона, или планшета, телевизора, холодильника… После того как закончили с правками, то можно и выключить этот плагин.
Там в обсуждении в телеге предложили такой вариант:
@Евгений Generalov
@Евгений Generalov
<?php
switch($scriptProperties['options']['type']) {
case 'script':
echo '<script src="'.$input.'?v='.filemtime($_SERVER['DOCUMENT_ROOT'] .'/'. $input).'"></script>';
break;
case 'stylesheet':
echo '<link rel="stylesheet" type="text/css" href="'.$input.'?v='.filemtime($_SERVER['DOCUMENT_ROOT'] .'/'. $input).'">';
break;
}
Использование: {'assets/css/main.min.css'| includeFile : ['type' => 'stylesheet']}
Я таким способом пользуюсь, просто дата файла
if ($modx->event->name == 'pdoToolsOnFenomInit') {
// return file version
$fenom->addModifier('version', function ($input) use ($modx) {
$output = $input;
$file = MODX_BASE_PATH.$input;
if (file_exists($file)) {
$output = $input.'?v='.filemtime($file);
}
return $output;
});
}
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.