LINUX.ORG.RU

Javascript cachebuster

 ,


0

1

Возможно ли на клиентской стороне и силами только самого javascript модифицировать тег <script src=«tests.js»> чтобы исключить кеширование?
Иначе приходится извращаться когда меняется скрипт с тестами.
Как я понял, феншуйный способ предотвратить кеширование это добавлять рандомное число типа <script src=«tests.js?314159»>, но каждый раз руками это делать - неспортивно.
Интернеты обнаружили древний сниппет, который у меня нормально не работает по какой-то причине (меняется только первый тег, который вовсе без src)

★★★★★

код по ссылке

Меня как будто в мозг изнасиловали.

GoodPerson
()

но каждый раз руками это делать - неспортивно.

А если попробовать это дело автоматизировать? Например, добавлять не какое-нибудь рандомное число, а хеш файла (sha1sum или git hash-object в помощь). В итоге: изменился файл скрипта → изменился хеш → браузер качает новую версию. Можно вместо хеша использовать дату модификации файла.

theNamelessOne ★★★★★
()

Как я понял, феншуйный способ предотвратить кеширование это добавлять рандомное число типа <script src=«tests.js?314159»>, но каждый раз руками это делать - неспортивно.

Нет, феншуй — это <script src=«bundle.SHA1.js»>, а sha1 вставляется автоматически.

x3al ★★★★★
()
Ответ на: комментарий от theNamelessOne

Сразу уточню, что это разовая задача и я не веб-разработчик и вообще не разработчик.
Билд процесса нет, файлы просто копируются на устройство (внутри крутится огрызок Ubuntu, без возможности установки чего-либо)
Полноценного браузера нет, под капотом устройства почти голый webkit
Веб сервера нет, это чисто клиентская часть.


Производительность и красота кода непринципиальны, меня устроит любой костыль. Сейчас я меняю параметры скрипта в текстовом редакторе перед копированием.

zolden ★★★★★
() автор топика
Ответ на: комментарий от zolden

Ну вообще-то даже такие фреймворки, как .NET MVC Core решают проблемы кеша при деплое костылями в коде вьюх. Дай больше подробностей, решить-то проблему можно хоть переименовав жс файлы и отредактировать их подключение, но сказав структуру проекта, я думаю, есть более простое решение.

nikolnik ★★★
()

https://github.com/addyosmani/basket.js
https://github.com/nodeca/bag.js

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

Смысл в том, что грузишь не напрямую, а через загрузчик.

По феньшую - сделать сборщик ассетов, который будет уникальные имена файлов делать (md5 и т.п.).

Vit ★★★★★
()
Ответ на: комментарий от zolden

Попробуй.

var rep = /.*\?.*/;

document.addEventListener('DOMContentLoaded', function() {
  [].slice.call(document.getElementsByTagName('script'))
    .filter(function(element) {
      return element.hasAttribute('src');
    })
    .forEach(function(element) {
      particle = rep.test(element.src) ? '&' : '?';
      element.src = element.src + particle + Date.now();
    });
});
GoodPerson
()
Ответ на: комментарий от zolden

меня устроит любой костыль

Ну, в таком случае, вот тебе костыль (build.sh).

#!/bin/sh

JS_SRC=test.js
HTML_SRC=index.html
HASH=$(sha1sum ${JS_SRC} | cut -f1 -d' ')
JS_OUT=$(echo ${JS_SRC} | sed "s/\\.js$/.${HASH:0:16}.js/")

rm -rf build && mkdir build
cp ${JS_SRC} build/${JS_OUT}
sed "s/TEST_JS_PLACEHOLDER/${JS_OUT}/" ${HTML_SRC} > build/${HTML_SRC}

Замени в HTML-файле <script src="tests.js" /> на <script src="TEST_JS_PLACEHOLDER" />, и после каждого изменения test.js выполняй скрипт build.sh. Пример

λ nameless@desktop zolden → tree # "структура" проекта
.
├── build.sh
├── index.html
└── test.js

0 directories, 3 files
λ nameless@desktop zolden → cat index.html # обрати внимание на маркер TEST_JS_PLACEHOLDER
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Uh oh</title>
    <script src="TEST_JS_PLACEHOLDER" />
  </head>
  <body>
    <p>Hello, World!</p>
  </body>
</html>
λ nameless@desktop zolden → ./build.sh # запускаем "сборку"
λ nameless@desktop zolden → tree # в директории build появился файл с хешем в имени файла                              
.
├── build
│   ├── index.html
│   └── test.1881d659f83950b8.js
├── build.sh
├── index.html
└── test.js

1 directory, 5 files
λ nameless@desktop zolden → cat build/index.html | grep script # build/index.html содержит ссылку на этот файл с хешем
    <script src="test.1881d659f83950b8.js" />
λ nameless@desktop zolden → echo "console.log('goodbye, cruel world')" > test.js # изменили содержимое файла... 
λ nameless@desktop zolden → ./build.sh # пересобрали проект
λ nameless@desktop zolden → tree # ...изменился хеш в build/test.$HASH.js
.
├── build
│   ├── index.html
│   └── test.756047c69801669a.js
├── build.sh
├── index.html
└── test.js

1 directory, 5 files
λ nameless@desktop zolden → cat build/index.html | grep script # ссылка в build/index.html также изменилась
    <script src="test.756047c69801669a.js" />

Это самый примитивный вариант. Про assets compilers уже сказали.

theNamelessOne ★★★★★
()
Ответ на: комментарий от nikolnik

Cтруктура проекта:1 HTML файл, внутри подключается 1 js файл с тестами QUnit.
Они загружаются на устройство флешкой и там автоматом запускаются.

Никаких фреймворков не используется, чистый HTML+ чистый JS
Код можно произвольно модифицировать под свои нужды + при необходимости я могу поднять веб-сервер в локалке и что-нибудь дёргать с него.

zolden ★★★★★
() автор топика
Ответ на: комментарий от GoodPerson

Спасибо, на вид то, что доктор прописал!
А есть уверенность, что к моменту DOMContentLoaded браузер уже не принял решение о том взять ли скрипт из кеша?

zolden ★★★★★
() автор топика
Ответ на: комментарий от GoodPerson

Чорт побьери, в Developer tools видно, что при таком раскладе скрипт берётся из кеша :(

zolden ★★★★★
() автор топика
Ответ на: комментарий от theNamelessOne

Спасибо, вариант я понял, и он мне всё-таки кажется более трудоёмким

А можно ли как-то перезагружать/перечитывать скрипт по какому-либо событию?
В идеале я бы вообще хотел избавиться от переноса файлов на флешке.
Примерная схема мне видится такой: скрипт лежит на локальном веб-сервере на моём компе + в HTML файле добавляем некую волшебную кнопку.
Файл меняем, нажимаю волшебную кнопку - происходит волшебство.

Один ньюанс: на устройстве нет браузера, поэтому сходу я не знаю как эмулировать Ctrl+F5

zolden ★★★★★
() автор топика
Последнее исправление: zolden (всего исправлений: 1)
Ответ на: комментарий от zolden

Уверенности нет, в MDN пишут так:

The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading.

Попробуй просто после нужных скриптов воткнуть без 3 и 12 строчек.

GoodPerson
()
Ответ на: комментарий от zolden

Примерная схема мне видится такой: скрипт лежит на локальном веб-сервере на моём компе + в HTML файле добавляем некую волшебную кнопку. Файл меняем, нажимаю волшебную кнопку - происходит волшебство.

Джаваскрипт не имеет доступа к файлам на устройстве, так что не получится. А http/tcp-сервер на устройстве поднять нельзя?

theNamelessOne ★★★★★
()
Последнее исправление: theNamelessOne (всего исправлений: 1)
Ответ на: комментарий от GoodPerson

Попробовал - результат тот же, скрипт берётся из кеша

zolden ★★★★★
() автор топика
Ответ на: комментарий от theNamelessOne

Устройство обрезано по самые помидоры, веб-сервер поднять к сожалению нельзя, там даже FTP/SSH нет, из-за чего приходится сношаться с флешкой.
Но я, кажется, нашёл вариант с эмуляцией Ctrl+F5 - http://stackoverflow.com/questions/7563010/how-do-i-simulate-ctrl-f5-with-jquery
По предварительным тестам (без устройства) location.reload(true) действительно перезапрашивает скрипты по честному.

Не уверен пока что это сработает на железке, ибо хз что там за webkit, но пока это кажется нормальным вариантом.

Спасибо за участие.

zolden ★★★★★
() автор топика
Ответ на: комментарий от zolden

Устройство обрезано по самые помидоры, веб-сервер поднять к сожалению нельзя, там даже FTP/SSH нет, из-за чего приходится сношаться с флешкой.

Я слишком туманно выразился. Может ли пользовательская программа создавать tcp-сокет и bind'ить его на порт?

Но в любом случае, этот вариант будет гораздо сложнее реализовать (и смысла в этом не будет, если вариант с эмуляцией Ctrl-F5 работает и устраивает тебя).

theNamelessOne ★★★★★
()
Последнее исправление: theNamelessOne (всего исправлений: 2)
Ответ на: комментарий от zolden

при необходимости я могу поднять веб-сервер в локалке и что-нибудь дёргать с него

Тогда на сервере врубаешь etag или last-modified для всей статики, ну или вообще вырубаешь кэширование, и браузер каждый раз по-честному будет их перезапрашивать

annulen ★★★★★
()

Эти ваши жабы и так нормально кэши и другие блоки современных процев нивелируют до уровня первопня.

anonymous
()
Ответ на: комментарий от annulen

а, я видимо не так понял действия

браузер каждый раз по-честному будет их перезапрашивать

я подумал про аналог нажатия F5, но теперь я всё осознал

zolden ★★★★★
() автор топика

Как я понял, феншуйный способ предотвратить кеширование это добавлять рандомное число типа <script src=«tests.js?314159»>

Ты неправильно понял. Самый правильный путь называется «expires 0» в терминах nginx

kawaii_neko ★★★★
()
Ответ на: комментарий от theNamelessOne

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

Vit ★★★★★
()
Ответ на: комментарий от kawaii_neko

Закончи, пожалуйста фразу:
expires 0 в терминах ngnix реализуется в схеме без веб-сервера следующим образом:
1) ...
2) ...
3) ...

zolden ★★★★★
() автор топика
Ответ на: комментарий от Vit

В случае ТСа такое вряд ли возможно, но вообще я согласен.

theNamelessOne ★★★★★
()
Ответ на: комментарий от zolden

expires 0 в терминах ngnix реализуется в схеме без веб-сервера

/0. У локальных файлов нет http-заголовков, так как запрашиваются они не через http, поэтому expires: 0 вписать некуда.

Вообще я крайне удивлен, что file:// кэшируется. Там точно протокол file://, или все-таки какой-то костыльный веб-сервер, раздающий файлы с флэшки?

annulen ★★★★★
()
Ответ на: комментарий от annulen

Хз, но все, кто-хоть что-то знает об этом поделии клянутся, что веб-сервера нет.
На самом деле, я даже не до конца уверен как именно обстоит дело с кешированием, зачастую я просто ребутаю железку, когда на вид трюк с script.js?randomnumber не срабатывает.
Так что если трюк с reload сработает, мне это здорово сэкономит время

zolden ★★★★★
() автор топика
Ответ на: комментарий от zolden

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

Ты знаешь, по какому урлу загружается исходная страница? Ресурсы загружаются по относительным урлам? Если да, то они используют тот же протокол, что и страница, то есть если страница грузится как http://foo.bar/baz, то и ресурсы грузятся по http.

В любом случае имеет смысл поднять у себя на компе например nginx и грузить весь контент с него, так и заголовки можно настроить, и (пере)заливать на устройство ничего не надо

annulen ★★★★★
()
Ответ на: комментарий от annulen

Ты знаешь, по какому урлу загружается исходная страница?

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

zolden ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.