Live Rendering

Spark provides rich, real-time user experiences with server-rendered HTML

Introduction

Spark will re-render the relevant parts of its HTML template and push it to the browser, which updates itself in the most efficient manner. This means developers write Spark templates as any other server-rendered HTML and Spark does the hard work of tracking changes and sending the relevant diffs to the browser.

At the end of the day, a Spark is nothing more than a process that receives events as messages and updates its state. The state itself is nothing more than functional and immutable Crystal data structures.

This architecture eliminates the complexity imposed by full-stack front-end frameworks without abandoning high-performance reactive user experiences. With Spark, small teams can do big things faster than ever before. We invite you to explore a fresh alternative to the Single Page App (SPA).

Server Side Web Socket Connection

To enable Spark live rendering you must first mount the /live-view. In your main application crystal file simple add the following snippet.

module MyApp
  include Azu
  
  # Defines a Spark websocket connection
  router.ws "/live-view", Spark.new
end

With this snippet we define the the Server side Web Socket connection will be used to render all your spark components.

Client Side Web Socket Connection

In order for Spark to communicate with the Browser we must define a Web Socket connection on the Client side. This is done by including the spark javascript.

<script src="/assets/js/live-view.js" type="module"></script>

Spark Components Overview

Spark Components decompose response content into small independent contexts that can be lazily loaded.

Defining Components

Components are defined by including Azu::Component and are mounted/rendered by calling YourComponent.mount in a parent Azu::Response. Components run inside the Response object, but may have their own state and event handling.

Example Spark Component

class TitleComponent
  include Azu::Component

  def initialize(@name : String)
  end

  def mount
    every(5.seconds) { refresh }
  end

  def content
    h1 { random_name_generator }
  end
  
  private def random_name_generator
    ["John", "Doe", "Karen"].sample.first
  end
end

The Mount Method

The most basic way to render a Spark component on a page is using the component mount method

You begin by rendering a Spark component typically from your Response class. A Spark component's mount method gets called on the initial page load and every subsequent component update.

Example Azu Response rendering a Spark Component

class Dashboard::IndexPage
  include Response
  include Template::Renderable
  
  TEMPLATE = "templates/layout.jinja"
  
  def render
    render TEMPLATE, { "title": TitleComponent.mount }
  end
end

Initializing Properties

A Spark component can be initialize with properties using the mount method. For this to work simply define an initialize method with the name properties as you would normally do with any Crystal class.

The use of properties enables re-usability of the components create.

class ProcessingCounter
  include Azu::Component
  
  # Spark Component Properties
  def initialize(@title : String, @count : Int32)
  end
  
  def mount
    every(1.seconds) { refresh }
  end

  def content
    h6 @title, class: "mg-b-0"
    text @count
  end
end

Mounting the component above would look like

ProcessingCounter.mount(title: "Total Jobs", count: 100)

Refreshing the component

Spark components comes with the refresh and every methods and allows you to define the refresh interval for a given component

def mount
  every(5.seconds) { refresh }
end

Component Content

With every Spark Component you must define a content method. The body of the method it's what gets rendered when the component is mounted to the page.

Spark components are meant to render dynamic content, at the same time components must be reusable and easy to maintain, for these reason Spark components have Markup, a lean html dsl written in Crystal to allow you write HTML natively.

Markup is intuitive to use and fast to render.

def content
  div class: "card" do
    div class: "card-header" do
      h6 "Processing", class: "mg-b-0"
    end

    div class: "card-body tx-center" do
      h4 class: "tx-normal tx-rubik tx-40 tx-spacing--1 mg-b-0" do
        text processing_count
        small " jobs"
      end

      div "Jobs currently busy", class: "divider-text"
    end
  end
end

While you can use Markup to write your html code is not limited. You can use docstrings, templates or what suits your needs bests.

Last updated