SkillAgentSearch skills...

Undead

LiveView server implementation for the JVM

Install / Use

/learn @floodfx/Undead
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

🧟🧛‍♀️🐺 Undead - LiveViews for the JVM

javadoc

What is Undead?

Undead is dead-serious library for JVM devs who want to build scary fast, bewitching front-end experiences on the JVM without writing javascript 🙀.

Undead is a LiveView implementation for the JVM. (The name "Undead" is a play on the "Live" part of LiveViews 👻.) LiveViews let you build front-end experiences like those you can build with React or Vue.js but all without leaving the server. (See what is a liveview for more details on LiveViews but you don't need to know what a LiveView is to use Undead.)

NOTE: Undead relies on Java 21 Preview Features

Undead is built on top StringTemplates which is a "Preview Feature" of Java 21. In order to build and run Undead apps you have to run your IDE and/or the JVM with the --enable-preview flag and target Java 21. The pom.xml in this repo show you where you need to add flags. If you are running IntelliJ you have to futz with the settings...again this repo ships with the IntelliJ settings. I don't know about Eclipse and last time I checked VSCode plugins they didn't support Java 21 yet.

Sometimes you have to work a little to be on the bleeding edge...🔪

🍬 Benefits of building apps with Undead

  • No need to write javascript
  • Very fast, SEO-friendly, fully rendered HTML initial response
  • Extremely efficient, diff-based updates over Websockets
  • Small, easy-to-learn, yet powerful API
  • Modern, type-safe templating engine (String Templates)
  • Just another route on your existing web server

Further Undead does the following:

  • Makes normal things trivial
    • Dynamic, validated forms that map into model objects (and vice versa)
    • Dynamic page updates based on user actions (clicks, keys, focus, etc)
    • Debounce and throttle user events with ease
  • Makes hard things easy
    • File uploads with drag-n-drop, progress, and image previews
    • Multiplayer UIs, presence, and other real-time interactions using pub/sub
    • Only ship diffs reducing network overhead by huge amounts (transparent to dev btw)
  • Makes expensive/complicated things unecessary
    • No need for REST or GraphQL APIs (but easier to integrate with them if you do)
    • No need for front-end vs back-end code bases, FE vs BE state synchronization, etc
    • No need to build or maintain a large Javascript component library
    • No need to write Javascript period.

🦠 Current Status: Incubating / Alpha

Undead is currently in the "incubating" stage. It is probably not yet ready for production but "it's alive!" and a decent chunk of functionality is implemented along with pretty good documentation (especially the javadocs). If you aren't too afraid 👻 you can try it out and provide feedback. Check out working examples in the example code directory. You can run these examples by checking out this repository and running:

mvn package exec:exec

Then open your browser to http://localhost:1313 and you should see the examples.

⭐️ Stars, Feedback, and Signups Welcome

Please feel free to open an issue or PR if you have any feedback or suggestions. If you like this project, feel free to ⭐️ it! You can also signup for updates. (Only the cursed would share your email address.)

Adding Undead to your project

If you are brave enough to try it out, you can add Undead to your project by adding the following dependency to your pom.xml:


<dependency>
    <groupId>run.undead</groupId>
    <artifactId>undead-core</artifactId>
    <version>0.0.15</version>
</dependency>

Example Undead View

// Sample View that counts up and down 
public class UndeadCounter implements View {
  private int count;

  public UndeadCounter() {
    this.count = 0;
  }

  // Handle events from the browser
  public void handleEvent(Socket context, UndeadEvent event) {
    if ("inc".equals(event.type())) {
      this.count++;
    } else if ("dec".equals(event.type())) {
      this.count--;
    }
  }

  // Render the HTML based on the current state (e.g. count)
  public UndeadTemplate render(Meta meta) {
    return HTML."""
        <div class="flex flex-col space-y-4 mx-4">
          <h2 class="text-2xl">Count:
            <span class="\{ If(count > 0, HTML."text-success", HTML."text-warning") }">
              \{ count }
            </span>
          </h2>
          <div class="flex space-x-4">
            <button class="btn btn-primary" type="button" ud-click="dec">Decrement</button>
            <button class="btn btn-primary" type="button" ud-click="inc">Increment</button>
          </div>
          """;
  }

}

Undead Views

Undead Views are the lifeblood of the Undead framework. View provides a simple yet powerful interface that for handling events from the browser, updating state, and rendering HTML.

Undead View interface

The View interface defines the lifecycle callbacks for an Undead View. Views have a lifecycle that consists of a short, fast HTTP request/response and a long-lived WebSocket connection.

Implementation Note: Views should have a no-arg constructor as they are instantiated by reflection.

View Interface methods

  • View.mount - (optional) mount is where a View can be initialized based on session data and/or path or query parameters
  • View.handleParams - (optional) handleParams is called after mount and whenever there is a URI change
  • View.handleEvent - (optional) handleEvent is called when an event (click, keypress, etc) is received from the browser
  • View.handleInfo - (optional) handleInfo is called when an event (a.k.a info) is received from the server
  • View.render - (required) render returns an UndeadTemplate based on the state of the View
  • View.shutdown - (optional) shutdown is called when the View is shutting down and is a good place to clean up

As you can see the only required method is View.render which is called to render the View based on its state. The other methods are optional so you can implement only the callbacks that you need for your View.

Templating

Undead provides a String Templates-based template engine that make LiveViews possible.
String Templates are a new feature in Java 21 and therefore Undead only works on Java 21 (and theoretically above). String Templates have a slightly weird escape syntax (e.g. \{ count }) but they are very powerful, easy to use, type-safe, and can create whatever HTML you want. Undead provides a number of pre-built directives that make building complex HTML easy.

Example Undead Template

Undead.HTML."""
<div class="flex flex-col space-y-4 mx-4">
  <h2 class="text-2xl">Count:
    <span class="\{ If(count > 0, HTML."text-success", HTML."text-warning") }">
      \{ count }
    </span>
  </h2>
  <div class="flex space-x-4">
    <button class="btn btn-primary" type="button" ud-click="dec">Decrement</button>
    <button class="btn btn-primary" type="button" ud-click="inc">Increment</button>
  </div>
  """;

Undead.HTML Templates

The Undead.HTML processor is a String Template Processor that is used to build HTML template in a type-safe, LiveView-friendly way. Undead.HTML automatically escapes HTML entities in order to prevent XSS attacks. Beyond escaping HTML entities, it does no other parsing or validation of the HTML but it does take advantage of StringTemplates to optimize diff being sent over the wire.
A simple example of Undead.HTML in action is below:

// Single line
Undead.HTML."Hello, \{ name }!";

// Multiline
Undead.HTML."""
  <div class="flex flex-col space-y-4 mx-4">
    <h2 class="text-2xl">Hello, \{ name }!</h2>      
  </div>
""";

You can read more about String Templates here and here. But you really don't need to know much about them to use Undead.HTML templates other than how to embed values (i.e. \{ myValue }). Note, you can statically import Undead.HTML to shorten it to HTML.

Undead Template Directives

Undead provides template directives for common needs like if statements, switch statements, mapping over a collection, ranges, etc. Basically all the normal templating things you'd expect. You can also easily add your own template directives and/or custom functions that can be used in your templates. Below is a list of the built-in directives:

  • If Directive - If models an if statement in a template. If the provided condition is true the trueCase template is returned otherwise an empty template is returned. There is also an If directive that can return either the trueCase or falseCase template.
  • Switch Directive - Switch models a switch statement in a template. The provided value is compared to each case and if there is a match the corresponding template is returned. If there is no match, the default template is returned (or an empty template if there is no default).
  • For Directive - For enables transforming a collection of values into a collection of templates. The provided collection is iterated applying the provided template function to each value in the collection.
  • Range Directive - Range enables iterating over a range of integer values optionally by a given step.
  • Join Directive - Join enabled joining a collection of templates together with a given separator template.

There are typically two types of logic directive, those that take a simple boolean condition (e.g. x == 1) and those that take a Predicates which are used into lambda form (e.g. x -> x

View on GitHub
GitHub Stars60
CategoryDevelopment
Updated15h ago
Forks2

Languages

JavaScript

Security Score

85/100

Audited on Apr 2, 2026

No findings