В продолжение темы серверного HTML рендеринга на Kotlin.
Если вы не читали статью, кратко напомню о чём речь: я написал небольшой можно сказать фреймворк для генерации HTML на стороне сервера на Kotlin. И поддержку строготипизированных routes для удобного создания ендпоинтов, ссылок на них и форм. Теперь Spring Views можно создавать на Kotlin и по крайней мере в моих проектах (а один из них очень большой - сотни отдельных страниц и десятки виджетов) это дало мне огромное удобство, уверенность, безопасность, рефакторо-пригодность, простое версионирование и переиспользование кода, например, теперь я точно не сделаю опечатку в URI или имени параметра и не смогу передать неверный тип данных на endpoint.
Одна из проблем которые до недавнего времени была в связи с использованием данного фреймворка - это CSS-стили. Приходилось либо инлайнить стили непосредственно для HTML элемента, либо мейнтейнить огромный (или несколько поменьше) CSS файл без возможности внятно следить за старыми более неиспользуемыми классами и селекторами. Кто создавал большие CSS файлы знает о чём я говорю - со временем количество классов накапливается и вычистить их не задев чего-то всё ещё нужного очень сложно. Вот так приходилось работать с CSS стилями раньше:
DIV("css-class-name") {...} // или DIV { style("color: red;") +"Hello World" }
В принципе жить можно, но хотелось чего-нибудь:
что-то на подобии Styled-Components из ReactJS, но так же на Kotlin
по возможности поддержку JVM hot-reload в режиме отладки
как следствие кода на Kotlin - иметь возможность всегда отслеживать зависимости и удалять более неиспользующиеся CSS-правила.
Долго думал как это получше сделать, и пока что первая версия получила вот такой синтаксис:
@Component // Spring @Component object MyCssClass : CssClass({ style = "color: black;" hover = """ color: red; text-decoration: underline; """ }) ... A(MyCssClass) { href(SomeUsefulRoute(param = 1)) +"Click me" }
То есть объявляем object который будет нести информацию о CSS свойствах элемента. И далее просто используем его в тех же местах где раньше можно было указать css-class-name. CssClass поддерживает массу "псевдоклассов" типа hover, active, firstOfType, before, after и так далее, так же можно добавлять media брейкпоинты и всякие другие штуки. Вот более насыщенный пример:
@Component object Container : CssClass({ style = "padding: 25px;" hover = "background: #eee;" add(">a", "color: green;") add(">a:hover", "text-decoration: underline;") media("max-width: 991px") { style = "padding: 10px;" } })
Вы наверняка заметили двойные скобочки ({...}) - в конструктор я передаю функцию-инициализатор стилей. Это нужно для того, чтобы в дебаг режиме JVM можно было на лету менять свойства CSS класса без перезапуска приложения: код который генерирует сам css-файл может быть запущен в режиме dev-mode, когда на каждый запрос файла будут выполнены все функции-инициализаторы ещё раз и файл будет собран заново.
Если по какой-то причине вам не нравится object - можно просто объявить class и использовать его:
@Component class Container : CssClass({...}) ... DIV(Container::class) { ... }
Теперь в проекте порядок с CSS стилями - нет давно умерших, всегда можно найти точки использования, стили лежат рядом с виджетами и т.п.
Смотрите исходники тут. Фидбэк приветствуется, всем хорошего дня.
