Setup Java Spring Boot Hilla

This documentation was generated with the assistance of AI. Please report any inaccuracies.

Scaffolds a Hilla (Vaadin) React frontend into the module of a Spring Boot hexagonal reactor that runs the web server: the Vaadin BOM and starter dependencies, the vaadin-maven-plugin build-frontend execution, a file-based router with a sample view and test, a vitest/@vitest/coverage-v8 toolchain, ESLint flat config plus Prettier, a Playwright component-testing setup and a root .ui-quality.yml (the catalog’s UI contract), the .gitignore additions the frontend needs, and — only when Sonar analysis is enabled — the sonar.sources/ sonar.tests/lcov properties on the root pom (Gradle: the boot project’s sonar {} block). It reads the manifest’s project.language (java/kotlin) and project.buildTool (maven/gradle) and adapts the build wiring accordingly; the frontend files are identical in every combination.

Purpose

iru-setup-java-springboot-hilla fills in the one part of a Spring Boot reactor that iru-setup-java-springboot-pom and iru-setup-java-springboot-modules don’t cover on their own: an actual Hilla React frontend, wired end to end and verified against a real build rather than assumed to work. Two findings behind it were confirmed empirically by building and running a real Spring Boot 4 + Hilla project: hilla-spring-boot-starter alone does not build, because the auto-generated Flow compatibility shim under src/main/frontend/generated/flow/ always references a Flow client resource that only vaadin-spring-boot-starter provides — both starters are always added, regardless of whether hand-written Flow @Route views are wanted; and routes.tsx/generated/file-routes.ts are derived by Hilla’s file-based router on every prepare-frontend/build-frontend run, so this skill writes views/@index.tsx and views/@layout.tsx only and never touches anything under src/main/frontend/generated/.

Kotlin and Gradle. project.language (absent means java) and project.buildTool (absent means maven; gradle only with kotlin) change only the build wiring and the server-side service code, never the frontend files. On Maven the pom fragment is unchanged for Kotlin (vaadin-maven-plugin runs after kotlin-maven-plugin). On Gradle the com.vaadin plugin is applied to the :boot project, with the Vaadin BOM (also added to developmentOnly), starters and plugin alias resolved from gradle/libs.versions.toml, and vaadinPrepareFrontend run explicitly because it is not part of the build graph. Kotlin @BrowserCallable services rely on Kotlin’s own nullability (String required, String? optional) — no @Nonnull/JSpecify annotations are added. A manifest pairing gradle with java is a stop.

The skill announces whether it is scaffolding the frontend from scratch or updating an existing one. When frontend files or pom wiring it owns already exist, it warns and asks Update (fill gaps only, recommended) / Keep as is / Replace (regenerate everything) / Stop, unless on-existing pre-answers; regenerating the sample view and test is asked as a follow-up rather than assumed.

Plugin

Shipped by the iru-springboot plugin of the ai-catalog marketplace (install with /plugin install iru-springboot@ai-catalog; see Plugins).

Invocation

/iru-setup-java-springboot-hilla

Inputs

Argument Required Description Default

stack-file

No

args key: value line naming the manifest path. Read for the module layout (which module is boot, the web module) and sonar.mode. If it doesn’t exist, the skill stops and tells the user to run /iru-setup-java-springboot (or -modules) first.

springboot-stack.yml at the repository root

project.language / project.buildTool

No (manifest fields)

java/kotlin and maven/gradle; select the Maven pom wiring or the Gradle com.vaadin plugin wiring (Step 2) and whether Kotlin @BrowserCallable conventions apply (Step 2a). gradle with java is rejected.

java / maven

mode

No

args key: value line, new or existing. Informational only: it never means "update silently".

None

on-existing

No

args key: value line, ask, keep, update or replace, pre-answering the existing-frontend question for every file.

ask

frontend

Yes (manifest field)

Must be hilla in the manifest for this skill to proceed without asking. If it’s none, the user is asked via AskUserQuestion whether to add a frontend anyway; proceeding updates the manifest’s frontend: field to hilla.

None — read from the manifest

accessibility

No

args key: value line, enforce, report, off or none: the UI tests' automated accessibility level written to .ui-quality.yml (Step 4b). Resolved from args, else the manifest’s top-level accessibility key (written by Setup Java Spring Boot, meaningful only with frontend: hilla), else enforce; never asked. none opts out entirely: no accessibility tooling is installed and the generated templates omit accessibility attributes (asked as "None — opt out entirely"). In mode: existing a prior level is never silently flipped.

enforce

sonar.mode

Yes (manifest field)

When not none, triggers Step 7’s sonar.sources/sonar.tests/sonar.javascript.lcov.reportPaths merge into the root pom’s existing Sonar properties. Skipped entirely when none.

None — read from the manifest

Outputs

  • <web-module>/pom.xml (Maven) — vaadin-spring-boot-starter, hilla-spring-boot-starter, and optional vaadin-dev dependencies, plus the vaadin-maven-plugin execution (prepare-frontend, build-frontend).

  • boot/build.gradle.kts (Gradle, Kotlin) — the com.vaadin plugin alias, javaParameters, the BOM platform, both starters and developmentOnly vaadin-dev.

  • Root pom.xml — the <vaadin.version> property, vaadin-bom dependencyManagement import, vaadin-maven-plugin pluginManagement entry, and production profile, only when they aren’t already there (normally owned by Setup Java Spring Boot Poms). On Gradle the equivalent is the version catalog’s vaadin version, vaadin-bom library and com.vaadin plugin alias.

  • <web-module>/src/main/frontend/views/@index.tsx, views/@layout.tsx, and index.html — never anything under src/main/frontend/generated/.

  • <web-module>/vitest.config.ts (extending Vaadin’s generated Vite config), src/main/frontend/test/setup.ts, and a colocated sample test views/@index.test.tsx.

  • <web-module>/package.json test/test:watch/coverage/lint/format scripts and devDependencies (vitest, @vitest/coverage-v8, Testing Library, ESLint, Prettier and their plugins).

  • <web-module>/eslint.config.js (flat config), .prettierrc.json, .prettierignore.

  • UI contract files (Step 4b; see Building user interfaces): .ui-quality.yml at the repository root (accessibility, directions, themes); in the web module a standalone Vite component gallery (playwright/vite.config.ts, playwright/gallery/index.html and main.tsx, since Vaadin’s own Vite config needs prepare-frontend), playwright.config.ts, e2e/support/ui-screenshots.ts (copied from the skill’s reference/ui-screenshots.ts), a stories/HomeView.story.tsx story and e2e/components/HomeView.spec.ts, which captures .ui-screenshots/screen/HomeView/ across left-to-right/right-to-left × light/dark with an @axe-core/playwright check; a test:ui script and the @playwright/test/@axe-core/playwright devDependencies.

  • .gitignore additions for <web-module>/node_modules/, src/main/frontend/generated/, vite.generated.ts, the Playwright test-results/ and playwright-report/ directories and .ui-screenshots/ — shown as a diff and confirmed before writing.

  • Kotlin @BrowserCallable conventions (Step 2a) — no sample service is scaffolded.

  • Root pom sonar.sources/sonar.tests/sonar.test.inclusions/sonar.javascript.lcov.reportPaths merged in, and sonar.exclusions extended with /frontend/generated/, only when sonar.mode isn’t none. Kotlin + Maven uses src/main/kotlin roots; Gradle adds a sonar {} block to boot/build.gradle.kts instead.

  • Optional example Flow @Route Java class and component starter, only if Step 1’s Flow-views question was answered Yes.

Execution flow

flowchart TD A["Start /iru-setup-java-springboot-hilla"] --> B["Step 0: Read the manifest and args\n(language, buildTool, frontend)"] B -- manifest missing --> STOP1["Stop: run iru-setup-java-springboot\n(or -modules) first"] B -- frontend is not hilla --> ASK1{"AskUserQuestion:\nproceed anyway?"} ASK1 -- stop --> STOP2["Stop"] ASK1 -- proceed --> B2["Update manifest frontend: hilla"] B2 --> C B -- frontend is hilla --> C["Step 1: Survey web module,\nroot pom Vaadin wiring,\nexisting frontend files,\nresolve npm/Vaadin versions,\nFlow-views question"] C -- existing frontend found --> ASK2{"Announce from scratch vs update;\nAskUserQuestion (or on-existing):\nUpdate fill gaps / Keep as is /\nReplace / Stop"} ASK2 -- stop --> STOP3["Stop"] ASK2 -- update or replace --> D ASK2 -- keep as is --> M C -- no existing frontend --> D["Step 2: Module build wiring\n(both Vaadin/Hilla starters;\nMaven plugin or Gradle com.vaadin)"] D --> D2["Step 2a: Kotlin BrowserCallable\nconventions (Kotlin only)"] D2 --> E["Step 3: src/main/frontend/\n@index.tsx, @layout.tsx, index.html"] E --> F["Step 4: vitest.config.ts,\ntest/setup.ts, sample @index.test.tsx"] F --> F2["Step 4b: UI contract: .ui-quality.yml,\nPlaywright gallery + config,\ncapture helper, HomeView story and spec"] F2 --> G["Step 5: package.json scripts/deps,\neslint.config.js, Prettier config"] G --> H["Step 6: .gitignore additions\n(shown as diff, confirmed)"] H --> I{"Step 7: sonar.mode\nis none?"} I -- yes --> K I -- no --> J["Merge sonar.sources/tests/\nlcov.reportPaths, extend\nsonar.exclusions"] J --> K["Step 8: Verify via iru-gate-runner —\nmvn or gradle prepare-frontend,\nthen npm ci + vitest --coverage,\nthen Playwright UI tests"] K -- optional --> L["Optional: mvn package -Pproduction\n-DskipTests via iru-gate-runner"] K --> M["Step 9: Report versions, files created/\nupdated/replaced/kept, Sonar/Node\noutcome, warnings"] L --> M

Dependencies

Invokes

None — it reads springboot-stack.yml and writes pom, frontend, and configuration files directly.

Invoked by

Also runs standalone (/iru-setup-java-springboot-hilla) against any reactor already built by Setup Java Spring Boot Modules.

  • iru-gate-runner — Step 8’s mvn vaadin:prepare-frontend gate (Gradle: ./gradlew :boot:vaadinPrepareFrontend), then npm ci + npx vitest run --coverage in the web module, then CI=1 npx playwright test with UI_SCREENSHOTS_DIR set (a missing Chromium is reported as unverified, never downloaded), and an optional -Pproduction package build.

Source

SKILL.md on GitHub — the file this page was generated from.