Эта статья рассчитана на Spring Boot разработчиков, желающих пощупать мир современного фронтенда. Я потратил некоторое количество времени на поиск наиболее приличного фреймворка и мой выбор пал на Svelte. Почему именно он, а не React или Vue? Лучше всего на этот вопрос ответит главная страница фреймворка, а я выделю главные его особенности:
Компиляция в чистый JS на этапе сборки приложения — клиенту не нужно тянуть кучу неиспользуемых сущностей, негативно сказывающихся на размере и производительности;
Лаконичность — всё выглядит как фрагменты HTML, обсыпанные синтаксическим сахаром, вследствии чего проект на Svelte легко читать, редактировать и писать;
Простота освоения — хватит некоторых знаний JS, CSS и HTML.
В то же время у фреймворка есть и недостаток, выходящий из первого пункта: не получится просто так взять и передать "сырые" компоненты .svelte в слой представления REST MVC приложения, так как предварительно их нужно компилировать в среде Node.js, тем самым выходя за рамки JVM и идя на небольшие ухищрения.
Spring Boot
Для начала создам предельно простой Spring Boot проект с единственным контроллером:
Зависимости в pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
</dependency>
Структура проекта
SpringSvelteApplication.kt
@SpringBootApplication
class SpringSvelteApplication
fun main() {
runApplication<SpringSvelteApplication>()
}
MainController
@Controller
class MainController {
// Returns the index.html view layer template from the static
@GetMapping
fun getIndex() = "index.html"
}
Теперь нужно поместить шаблон представления index.html в папку static, чтобы контроллеру было что возвращать. А этот шаблон, в свою очередь, будет предоставлять клиенту код, созданный компилятором Svelte. Но для начала потребуется подключить сам Svelte.
Svelte
Внедрение этого фреймворка можно разбить на 3 шага:
Загрузка шаблона репозитория в директорию проекта
Для начала нужно установить Node.js (если он ещё не установлен).
После этого всё, что нужно сделать — это ввести в терминал следующие команды:
cd project_path
npx degit sveltejs/template svelte
cd svelte
npm install
, где project_path — корень проекта; в моём случае это
C:\Users\illyc\Desktop\Programming\Projects\KOTLIN\spring_svelte
После упешного выполнения этих команд в корне проекта будет создана директория svelte, загрузятся файлы шаблона из репозитория sveltejs/template и установятся некоторые пакеты из npm:
Конфигурирование Svelte
Итак, у нас есть шаблонный проект Svelte, состоящий из 4 директорий:
node_modules — библиотеки NodeJS, на которых построен фреймворк;
scripts — содержит некие дополнительные установки, в нашем случае это TypeScript: если вы не собираетесь писать на TS, то можно эту папку удалить;
src — "исходный код" субприложения: сюда в дальнейшем необходимо помещать svelte-компоненты;
public — директория, в которую по умолчанию падают скомпилированные Svelte ресурсы. Здесь же находится файл index.html. Всё содержимое public помещаем в директорию resources/static Spring Boot приложения. После этого директория public больше не понадобится.
Можно удалить файлы README и .gitignore (в этом случае будет использоваться .gitignore из корня проекта Spring Boot)
Теперь проект имеет следующий вид:
Далее необходимо указать путь компиляции Svelte. Открываем файл rollup.config.js, находим там единственный export default и меняем стандартный путь в output на путь к директории static в Spring Boot приложении:
// ...
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: '../src/main/resources/static/build/bundle.js' // was 'public/build/bundle.js'
},
// ...
Теперь, если выполнить команду npm run build
, то скомпилированные ресурсы поместятся в resources/static, тем самым слой представления Spring Boot всегда будет иметь к ним доступ.
Конфигурирование IDE
И последний штрих — настроить компиляцию Svelte непосредственно перед компиляцией Spring Boot. И поможет нам в этом IDE. В моём случае это intellij.
Всё, что нужно, это добавить npm run build, запускающего выполнение svelte/package.json, и добавить его непосредственно перед сборкой Spring Boot в Run Configurations:
Полученным способом приложение будет собираться бесшовно: вначале компилируются ресурсы представления, затем Spring Boot проект с этими ресурсами.
После всех шагов проект полностью готов к работе. Запустим и посмотрим, что там происходит на localhost:8080:
Давайте отредактируем компонент App.svelte так, чтобы отображённое слово World реактивно изменилось на имя, полученное с сервера:
App.svelte
<script>
import app from "./main";
export let name;
fetch("/name")
.then(response => response.text())
.then(text => name = text)
</script>
<main>
<h1>Hello {name}!</h1>
<p>Visit the <a href="https://svelte.dev/tutorial">Svelte tutorial</a> to learn how to build Svelte apps.</p>
</main>
<style>
// Origin styles
</style>
И добавим контроллер, возвращающий это имя:
MainController
@Controller
class MainController {
@GetMapping()
fun getIndex() = "index.html"
@GetMapping("/name")
@ResponseBody
fun getName() = "spring boot"
}
Работает!
Комментарии (8)
panzerfaust
20.09.2022 07:02+3Давайте отредактируем компонент App.svelte так, чтобы слово World реактивно менялось на имя, получаемое с сервера
Вы императивно запрашиваете имя, императивно обновляете переменную в шаблоне. AJAX вижу, реактивность - нет.
fuck_blyat Автор
20.09.2022 10:16+1Не совсем. Перед тем, как из fetch вернётся промис, переменная name имеет значение 'world' из импорта, и до получения промиса оно таким и отображается на доли секунды; после же отображение меняется на полученное из промиса. Это и есть реактивность, хоть и код выглядит императивным. Такая особенность Svelte
panzerfaust
20.09.2022 10:50+1Вам стоит почитать о разнице между асинхронностью и реактивностью.
fuck_blyat Автор
20.09.2022 11:20Ну примерно такая же разница, как между сантехникой и раковиной.
Да, переменная name не является реактивной, если Вы про это, но я такого и не писал. Реактивно её отображение.
Вот это<h1>Hello {name}!</h1>
aleksandy
Т.е. после каждой малюсенькой правки, нужно не только пересобирать фронтовую часть (что как бы логично), но и потом всё собранное копировать в ресурсы?
Можно же было хоть как-то это всё автоматизировать, хотя бы запуск сборки через
exec-maven-plugin
с указанием сразу правильного пути, куда следует складывать собранный дистрибутив. Причём этот путь 146% должен быть где-то вtarget
.Короче, статья ни о чём.
fuck_blyat Автор
Перечитайте внимательней пункт "Конфигурирование Svelte". Там есть кусок rollup.config.js, в котором прописан путь компиляции ресурсов и как этим пользоваться.