Pull to refresh

JQuery-UI внутри бинарника

Reading time3 min
Views1.1K
У программ на хаскеле есть одно свойство. После компиляции мы получаем самодостаточный бинарник, один файл с исполняемым машинным кодом. Языков с компиляторами, удобных для веб разработки, не так уж и много. Это свойство не имеет особого значения. Однако, оно позволяет добиться непревзойдённого удобства установки программ. И не только установки, но и всего того, что скрывается за английским словом deployment.

Веб-приложения используют дополнительные данные — изображения, стили css, скрипты javascript. Как правило они хранятся отдельно от исполняемого кода приложения в файловой системе веб-сервера. Но если этих дополнительных ресурсов меньше мегабайта — почему бы не встроить их прямо в бинарник? Сделаем deployment веб-приложений проще!

Эта статья продолжает тему маленького, но интересного проекта iptadmin.

Встраивание


Встраивание текста в исполняемый файл — задача простая. Достаточно создать строковую константу. Встраивание двоичных файлов в исполняемый файл немного сложнее.

На просторах hackage была найдена библиотека file-embed от автора web-фреймворка yesod.
Эта библиотека используя расширение ghc template haskell на этапе компиляции читает произвольные файлы, конвертирует их в строки, сохраняет в строковые константы и предоставляет к ним интерфейс как к байтовым строкам. Строковые символы с кодами вне печатаемого диапазона сохраняются без проблем. Так как при таком подходе они не участвуют в вводе/выводе и не отображаются в редакторе кода.

Автор библиотеки предлагает использовать функцию embedDir. Она получает список файлов из указанного каталога, и создаёт список пар (Имя файла, Байтовая строка) для удобной обработки большого набора файлов.

Но всё-таки была использована функция embedFile, она вызывается для каждого файла по-отдельности(функция PageHandlers). Это увеличило количество кода, однако дало уверенность, что если программа скомпилировалась, то все файлы уж точно есть в наличии. Количество необходимых тестов уменьшилось.

Доступ к ресурсам


Url для доступа к «статическим» данным оставлен прежним. Поэтому в клиентской части приложения ничего править не пришлось. Корневой каталог http сервера /static обрабатывается отдельным обработчиком. Обработчик вызывается в начале функции авторизации (authorize). До процедуры авторизации, чтобы страница входа в систему работала правильно.

Отдать клиенту файл по ByteString в Happstack достаточно просто. Можно лапидарно собрать значение типа Response с помощью конструктора данных Response. В поле rsHeaders добавить заголовок с Content-Type, в поле rsBody указать наш сохранённый ByteString.

Однако в Happstack 6 появился модуль Happstack.Server.FileServe.BuildingBlocks, который делает именно то, что нужно. Функция strictByteSTringResponse принимает на вход ByteString, описание Content-Type и возвращает клиенту файл. Эта функция и была использована. Для передачи клиенту разных типов файлов написаны функции returnJs, returnCss и returnPng.

304


«Большие» веб-сервера поддерживают conditional GET запросы с заголовками If-Modified-Since, и если запрашиваемый файл не изменился с момента последнего обращения, возвращают код 304 с пустым message-body. Такой метод ускоряет работу веб-приложений и сокращает сетевой трафик.

Отвечать клиенту кодом 304 для уже загруженных ресурсов необходимо. В случае сборки ответа клиенту вручную, с использованием конструктора Response, нужно было бы также вручную анализировать запрос и проверять, что данные не изменились с момента последнего запроса. Функции модуля Happstack.Server.FileServe.BuildingBlocks реализуют этот функционал «под капотом». Нужно только передавать дату и время изменения данных.

Откуда взять эту дату? Очевидно, в нашем случае временем последнего изменения «файла» будет время компиляции приложения. Поэтому получим его в процессе компиляции с помощью template haskell(updateTime).

Проблемы и решения


У этого подхода есть несколько очевидных проблем.

При изменении только статических файлов, система сборки не пересобирает модуль Static. Поэтому для принудительной пересборки нужно выполнить команду touch Static.hs, а только затем выполнять сборку. Для автоматизации в Makefile была добавлена команда htmlrebuild.

Кроме этого, цикл разработки значительно увеличивается. После правки javascript программы, необходимо полностью пересобрать модуль Static приложения. Затем запустить его, и только после этого можно начать отладку. Этот вопрос решается просто, на время разработки нужно включить доступ через каталог /static к файлам в файловой системе. Как это делается во всех веб-приложениях. Средствами happstack это делается тривиально. И только во время сборки готового выпуска встраивать ресурсы в исполняемый файл.

p.s.
Как обычно буду рад критике и любой другой обратной связи.
Если котому-то вдруг случайно пост на эту тему показался интересным, предлагайте интересующие темы для будущих постов. Если нет аккаунта на этом замечательном сайте, есть другие способы связи.
Tags:
Hubs:
Total votes 21: ↑21 and ↓0+21
Comments7

Articles