Ранним жарким утром спросонья пришла в голову идея. Подозреваю, что у этой идеи есть минусы либо ее уже реализовали куда более годным способом — но, авось да пригодится кому-нибудь.
Очень часто веб-разработчики сталкиваются с проблемой большого количества мелких файлов. Картинки, скрипты, css — неудобно, все дела. Нужно как-то бороться с этим. import, спрайты, блаблабла — это хорошо, но можно попробовать и иначе. Мой вариант — упаковка всех необходимых ресурсов в архив на стороне сервера(реализация — на php), получение данных на клиенте, установка ресурсов в нужных местах.
Проблемы на данный момент: не придумал толком, как кешировать полученный архив, таким способом не стоит паковать динамический контент или большие файлы.
Для распаковки архива на клиенте использована библиотека JSZip, для удобства — jQuery.
Итак, посмотрим на код.
ziplogic.php:
class ZipLogic extends ZipArchive{
public $filename;
public function __construct() {
$filename = "current/latest.zip";
$this->filename = $filename;
if(file_exists($filename))
unlink($filename);
if ($this->open($filename, ZIPARCHIVE::CREATE)!==TRUE) {
$error = error_get_last();
echo $error["message"];
return null;
}
}
public function pack($url){
$this->addFile($url);
}
}
Этот класс наследуется от ZipArchive и нужен только для чуть более удобной работы с архивом.
Теперь — код для упаковки нужных ресурсов:
index.php:
include "ziplogic.php";
$zpack = new ZipLogic();
if($zpack==null)
{
echo 'wrong data';
return;
}
$zpack->pack('img/screen.png');
$zpack->pack('img/screen_1.png');
$zpack->pack('img/screen_2.png');
$zpack->pack('css/alotofstyles.css');
$zpack->pack('js/cooljs.js');
$zpack->close();
include 'content.html';
Тут, собственно, тоже нет ничего особо интересного: создаем объект ZipLogic, перечисляем все ссылки на ресурсы, которые нужно упаковать, закрываем объект, подключаем конечную html'ку. В результате в папке current создается архив latest.zip, который содержит в себе все нужные ресурсы(см. ziplogic.php).
По хорошему, использовать его нужно перед публикацией страницы, каждый раз генерировать нет смысла.
Ну и на закуску — сама html'ка. Верстку не критиковать, пожалуйста — ее здесь нет.
content.html:
<script src="js/jquery-1.9.1.js"></script>
<script src="js/jszip.min.js"></script>
<link type="text/css" zpack="css/alotofstyles.css" rel="stylesheet">
<script zpack="js/cooljs.js"></script>
<style>
body{margin: 0;}
</style>
<div id="loader" style="position: absolute; width: 100%; height: 100%;background: rgba(148, 148, 148, 1);">
<img src="" style="
position: relative;
top: 50%;
left: 50%;
height: 25px;
width: 250px;
margin-left: -125px;
margin-top: -12.5px;
">
</div>
<img zpack="img/screen.png"/>
<img zpack="img/screen_1.png"/>
<img zpack="img/screen_2.png"/>
<script>
function getBinary(url, callback){
var oReq = new XMLHttpRequest();
oReq.open("GET", url, true);
oReq.responseType = "arraybuffer";
oReq.onload = function (oEvent) {
var arrayBuffer = oReq.response;
if (arrayBuffer) {
var byteArray = new Uint8Array(arrayBuffer);
callback(byteArray);
}
};
oReq.send(null);
}
function unpackResources(data){
var pack = new JSZip();
pack.load(data);
$.each(pack.files, function(k, v){
var blob = new Blob([pack.file(k).asArrayBuffer()], {type: 'application/octet-binary'});
var url = URL.createObjectURL(blob);
$('[zpack="'+k+'"').each(function(){
switch($(this).prop("tagName").toLowerCase())
{
case 'img' :
$(this).attr('src', url);
break;
case 'script' :
$(this).attr('src', url);
break;
case 'link' :
$(this).attr('href', url);
break;
case 'a' :
$(this).attr('href', url);
break;
}
});
});
}
$(document).ready(function(){
getBinary('current/latest.zip', function(data){
unpackResources(data);
$('#loader').hide();
});
});
</script>
Тут стоит описать чуть подробнее.
Функция getBinary, если не ошибаюсь, честно сперта со stackoverflow. Скачивает архив и передает полученный массив байт в callback.
Функция unpackResources, собственно, и делает основную часть работы: обрабатывает содержимое архива, вытаскивает пути, находит все элементы, ресурсы в которых помечены через zpack, создает соотв. blob и подгружает его в нужный элемент.
Пока все это добро не подгрузится, висит загрузчик.
В итоге получаем довольно простой код, позволяющий упаковать большое количество ресурсов в 1 архив и распаковать его на стороне клиента.
Спасибо за внимание, комментарии и идеи крайне приветствуются, критика без использования слов «идиот» и «криворукий ламер» — тоже.
Автор: Demogor