Ок. Компилятор выбран. Однако, это только половина задачи. Вторая половина задачи выходит из того факта, что, если я хочу подключать .py файлы из шаблона — мне нужно кеширование и компиляция кода в зону static. Я совсем не хочу, чтобы при каждом рендере шаблона вызывался довольно тяжелый компилятор. Кроме того, для установки сервера в productive режим, у меня на руках должен оказаться работающий набор скомпилированных скриптов. А еще, я хочу не думать о том, что библиотеки могут загружаться на страницу позже кода. Сопроводительные задачи должен решать робот. Для этой цели собственно и был написан django-compressor.
Вообще, django-compressor довольно спорный tool. Спорный с точки зрения необходимости — гораздо правильнее строить приложение так, чтобы задачи которые решает компрессор, вообще не вставали. Гораздо правильнее использовать CSS для стилей, и скрипт для клиентской части. Но питон силен именно тем, что позволяет быстро делать прототипы. А в прототипе главное не оптимальность. В прототипе главное — быстро и эффективно перейти от этапа создания среды для эксперимента, к собственно эксперименту. Компрессор был написан какраз исходя из того, что сначала должен быть создан прототип, и создан он должен быть быстро.
Про компрессор
Если коротко, то компрессор действует следующим образом — он берет все, что находится между тегами {% compress "group_name" %}{% endcompress %}, и переставляет “это все” в то место, где находится тег {%compressed "group_name" "compiler_name"%}. Перед подстановкой проверяется наличие контрольной суммы в кеше компрессора, и на этом основании принимается решение — нужна ли компиляция с использованием компилятора compiler_name или можно просто вернуть содержимое файла (или путь к файлу) соответствующее контрольной сумме. Компрессор умеет разбирать наследование шаблонов, инклуды, блоки и переменные. Поэтому можно спокойно выстраивать удобную для себя структуру шаблонов, не оглядываясь. Содержимое нескольких тегов {% compress %} будет встречаться в на странице в том же порядке, в котором происходил рендер.
Компилятор задается в settings.py как элемент словаря COMPRESSOR_COMPILERS следующего вида:
"pycow_file":{"result_wrapper":"""<script type="application/javascript" src="%(rendered)s"></script>""",
"returns_url":True,
"extension":"js",
"compiler":"pycow_compressor.pycow"},
Здесь result_wrapper определяет, какой текст будет окружать результат компиляции. returns_url определяет что надо возвращать — путь в кеше к скомпилированному файлу или содержимое скомпилированного файла. extension определяет какое расширение указывать для скомпилированных в кеш файлов. compiler определяет где взять функцию для компиляции.
Вторым аргументом для функции компилятора будет передан контекст. Так что, если внешний компилятор умеет работать с контекстом — можно приютить и его. Обращаю внимание — контекст будет закеширован после первой компиляции. Отслеживать и кешировать изменения переменных контекста я считаю избыточным. Поэтому, изменения в контексте не будут отражаться в скомпилированном файле, но для верстки стилей с использованием clevercss - сойдет.
Это какбы все. Следует еще добавить, что в реальном мире, никто не захочет держать клиентский (или еще какой) код внутри шаблонов, поэтому есть тег {% compress_file "group_name" "file/path" %}, который позволяет вынести код в отдельный файл. Путь считается относительным к корню проекта.
Производительность компрессора
Особо не вникал, т.к. это утилита времени разработки. Сравнение времени рендера шаблона в 10 строк без компрессора и с ним дало отличие в 4 раза — с 0.018 до 0.056 секунд. Очевиден выиграш в количестве запросов к серверу, но за все надо платить.
Comments