В продолжение темы серверного 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 стилями - нет давно умерших, всегда можно найти точки использования, стили лежат рядом с виджетами и т.п.
Смотрите исходники тут. Фидбэк приветствуется, всем хорошего дня.