Использование TailwindCSS в веб-приложениях Common Lisp без использования инструментов Node.js

В этой статье мы рассмотрим, как использовать TailwindCSS как библиотеку CSS класса utility в веб-приложении Common Lisp без использования инструментария Node.js или JavaScript.

Я уже писал статью об использовании TailwindCSS в Common Lisp, но настройка инструментария была несколько запутанной. На вашей машине должен быть установлен Node.js. Вам нужно установить дополнительные библиотеки npm и настроить некоторые конфигурации вокруг них, чтобы заставить Tailwind CSS работать в ваших веб-приложениях Common Lisp.

Но в этом посте мы рассмотрим более чистый и простой способ использования утилитарных классов CSS в веб-приложениях Common Lisp, используя возможности родной платформы Common Lisp и ее инструментальной экосистемы.

cl-djula-tailwind

cl-djula-tailwind — это пакет Common Lisp, который поможет вам использовать классы TailwindCSS в ваших шаблонах Djula без каких-либо инструментов JavaScript или Node.js.

Создайте новый проект Caveman

Мы собираемся создать новый проект Caveman на Common Lisp. Поэтому запустите ваш любимый интерпретатор Lisp и введите следующие команды для создания нового проекта веб-приложения на Common Lisp с использованием Caveman.

(ql:quickload :caveman2)
(caveman2:make-project #P"~/quicklisp/local-projects/cl-tw-demo")
Войти в полноэкранный режим Выйти из полноэкранного режима

Если вы хотите узнать больше о создании веб-приложений на Common Lisp, вы можете обратиться к моей предыдущей статье.

Лисп для веб — 5

Rajasegar Chandran ・ Jul 3 ’21 ・ 11 min read

#commonlisp #webdev #lisp #caveman2

Теперь нам нужно добавить cl-djula-tailwind в качестве системной зависимости для нашего вновь созданного проекта. Откройте файл определения системы для проекта под названием cl-tw-demo.asd и добавьте cl-djula-tailwind в раздел :depends-on.

(defsystem "cl-tw-demo"
  :version "0.1.0"
  :author "Rajasegar Chandran"
  :license ""
  :depends-on ("clack"
               "lack"
               "caveman2"
               "envy"
               "cl-ppcre"
               "uiop"

               ;; for @route annotation
               "cl-syntax-annot"

               ;; HTML Template
               "djula"

               ;; for DB
               "datafly"
               "sxql"

        ;; Djula Tailwind
        "cl-djula-tailwind")
  :components ((:module "src"
                :components
                ((:file "main" :depends-on ("config" "view" "db"))
                 (:file "web" :depends-on ("view"))
                 (:file "view" :depends-on ("config"))
                 (:file "db" :depends-on ("config"))
                 (:file "config"))))
  :description ""
  :in-order-to ((test-op (test-op "cl-tw-demo-test"))))

Вход в полноэкранный режим Выход из полноэкранного режима

Внедрение CSS в шаблоны

Добавьте место для таблицы стилей, созданной cl-djula-tailwind в шаблоне по умолчанию templates/layouts/default.html. Также необходимо добавить фильтр safe к переменной tailwind, чтобы пометить строку как не требующую дальнейшей экранировки HTML перед выводом. В противном случае Djula будет пытаться экранировать или кодировать кавычки и другие символы в генерируемом css. Более подробную информацию о фильтре safe можно найти в документации Djula.

<!DOCTYPE html>
  <html class="h-full bg-gray-100">
<head>
  <meta charset="utf-8">
  <title>{% block title %}{% endblock %}</title>
  <link rel="stylesheet" type="text/css" media="screen" href="/css/main.css">
    <style>{{ tailwind | safe }}</style>
</head>
Вход в полноэкранный режим Выйти из полноэкранного режима

Генерация таблицы стилей

Чтобы сгенерировать таблицу стилей для наших шаблонов маршрутов, мы собираемся вызвать экспортируемую по умолчанию функцию get-stylesheet из cl-djula-tailwind и передать ей имя шаблона и каталог шаблона в качестве аргументов.

И нам нужно установить значение для переменной шаблона tailwind, которую мы уже использовали ранее в шаблоне макета по умолчанию. Эта переменная будет изменяться для каждого маршрута, так как CSS для каждого маршрута будет генерироваться на лету и отправляться в шаблон. Поэтому нам нужно использовать *default-template-arugments*.

В Djula вы можете использовать переменную *DEFAULT-TEMPLATE-ARGUMENTS* для хранения аргументов, которые будут доступны для всех шаблонов. Она представляет собой plist, поэтому используйте getf для добавления аргументов, например, так:

(setf (getf djula:*default-template-arguments* :tailwind) 'some-value)
Войти в полноэкранный режим Выйти из полноэкранного режима

И теперь вы можете получить доступ к {{ tailwind }} в вашем шаблоне.

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

Более подробную информацию об аргументах шаблона по умолчанию вы можете найти в документации Djula

Теперь определите новую функцию render-stylesheet в src/web.lisp, как показано ниже.

(defun render-stylesheet (template)
    (setf (getf djula:*default-template-arguments* :tailwind) (cl-djula-tailwind:get-stylesheet template *template-directory*)))
Вход в полноэкранный режим Выйти из полноэкранного режима

Маршруты

Следующим шагом будет указать нашему веб-приложению, что сгенерированная таблица стилей должна отображаться в наших шаблонах. Вызовите функцию render-stylesheet в ваших маршрутах с именем шаблона в качестве аргумента перед стандартной функцией render Djula.

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

(defroute "/" ()
  (render-stylesheet #P"index.html")
  (render #P"index.html"))
Вход в полноэкранный режим Выход из полноэкранного режима

Посмотрите на демонстрационное приложение в действии

Теперь загрузите наше демо-приложение и запустите сервер, чтобы увидеть веб-приложение в действии и посмотреть, как работает наш Tailwind CSS, генерируемый на лету.

(ql:quickload :cl-tw-demo)
(cl-tw-demo:start :port 3000)
Вход в полноэкранный режим Выйти из полноэкранного режима

Ниже приведены некоторые примеры скриншотов демонстрационного приложения.

Как это работает

Давайте посмотрим, как это работает. Всякий раз, когда вы запрашиваете страницу в вашем веб-приложении, Djula будет пытаться прочитать ваш шаблон маршрута, скомпилировать его и затем отправить HTML-ответ браузеру. Именно так обычно все работает в приложении Caveman. Кроме того, пакет cl-djula-tailwind также анализирует имена классов Tailwind, используемые в ваших шаблонах, шаблонах макетов и партициях, используемых в вашей разметке, а затем строит минифицированный список определений классов CSS и помещает их в место в шаблоне макета по умолчанию через тег <style>, так что он будет автоматически подхвачен браузером, и ваш HTML-контент будет правильно отформатирован в соответствии с классами CSS, которые вы использовали.

CSS генерируется с помощью другого пакета Common Lisp под названием cl-css и минифицируется с помощью cl-minify-css. Имена классов из файлов шаблонов анализируются с помощью cl-ppcre, используя различные шаблоны регулярных выражений для различных имен классов, начиная от простых, отзывчивых, псевдоклассов, темного режима и так далее.

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

Используя расширение CSS Overview в браузере Chrome, я собрал некоторую статистику неиспользуемых CSS. Ниже приведены данные с сайта TailwindCSS.

Вы все еще можете увидеть некоторые неиспользуемые CSS при обычном подходе. А используя cl-djula-tailwind в нашем демонстрационном приложении, вот результат

При нашем новом подходе, когда мы отправляем только необходимые CSS, неиспользуемых CSS нет вообще.

Исходный код

Исходный код пакета cl-djula-tailwind размещен на Github здесь.

Демо-версия

Существует также демо-приложение, использующее пакет cl-djula-tailwind для тестирования и улучшения пакета. Оно размещено на Github здесь

Что дальше?

Пакет cl-djula-tailwind все еще находится на стадии бета-версии и еще не готов к производству. Но вы можете поиграть с ним. Большинство классов util, используемых в Tailwind, охвачены, но все еще есть над чем работать, чтобы подготовить его к производству.

Ниже перечислены некоторые вещи, о которых необходимо позаботиться:

  • Предоставить возможность для Tailwind CSS типа config.
  • Покрыть все утилиты в Tailwind
  • Обработка глубоко вложенных партиций в шаблонах Djula (в настоящее время она может обрабатывать только партиции верхнего уровня в шаблонах маршрутов).

Если вы найдете что-то, чего не хватает в Tailwind, и что можно сделать частью cl-djula-tailwind, пожалуйста, поднимите вопрос в репозитории.

Надеюсь, вам понравился этот инструмент Common Lisp и возможность генерировать CSS util-классы «на лету» для ваших веб-страниц. Пожалуйста, сообщите мне о любых вопросах или отзывах в разделе комментариев.

Оцените статью
devanswers.ru
Добавить комментарий