Skip to content

Latest commit

 

History

History

livefiber

⚡ livefiber

Real-time user experiences with server-rendered HTML in Go using Fiber. Inspired by and borrowing from Phoenix LiveViews.

Live is intended as a replacement for React, Vue, Angular etc. You can write an interactive web app just using Go and its templates.

The structures provided in this package are compatible with github.com/gofiber/fiber/v2.

See the main repository here for more info and docs.

See the examples for usage.

First handler

Here is an example demonstrating how we would make a simple thermostat.

// +build example

package livefiber

import (
	"context"
	"log"

	"github.com/gofiber/adaptor/v2"
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/session"
	"github.com/gofiber/template/html"
	"github.com/jfyne/live"
)

// Model of our thermostat.
type ThermoModel struct {
	C float32
}

// Helper function to get the model from the socket data.
func NewThermoModel(s live.Socket) *ThermoModel {
	m, ok := s.Assigns().(*ThermoModel)
	// If we haven't already initialised set up.
	if !ok {
		m = &ThermoModel{
			C: 19.5,
		}
	}
	return m
}

// thermoMount initialises the thermostat state. Data returned in the mount function will
// automatically be assigned to the socket.
func thermoMount(ctx context.Context, s live.Socket) (interface{}, error) {
	return NewThermoModel(s), nil
}

// tempUp on the temp up event, increase the thermostat temperature by .1 C. An EventHandler function
// is called with the original request context of the socket, the socket itself containing the current
// state and and params that came from the event. Params contain query string parameters and any
// `live-value-` bindings.
func tempUp(ctx context.Context, s live.Socket, p live.Params) (interface{}, error) {
	model := NewThermoModel(s)
	model.C += 0.1
	return model, nil
}

// tempDown on the temp down event, decrease the thermostat temperature by .1 C.
func tempDown(ctx context.Context, s live.Socket, p live.Params) (interface{}, error) {
	model := NewThermoModel(s)
	model.C -= 0.1
	return model, nil
}

// Example shows a simple temperature control using the
// "live-click" event.
func Example() {

	// Setup the handler.
	h := live.NewHandler(WithViewsRenderer("view"))

	// Mount function is called on initial HTTP load and then initial web
	// socket connection. This should be used to create the initial state,
	// the socket Connected func will be true if the mount call is on a web
	// socket connection.
	h.HandleMount(thermoMount)

	// This handles the `live-click="temp-up"` button. First we load the model from
	// the socket, increment the temperature, and then return the new state of the
	// model. Live will now calculate the diff between the last time it rendered and now,
	// produce a set of diffs and push them to the browser to update.
	h.HandleEvent("temp-up", tempUp)

	// This handles the `live-click="temp-down"` button.
	h.HandleEvent("temp-down", tempDown)

	// Setup fiber.
	app := fiber.New(fiber.Config{
		Views: html.New("./views", ".html"),
	})

	app.Get("/thermostat", NewHandler(session.New(), h).Handlers()...)

	// This serves the JS needed to make live work.
	app.Get("/live.js", adaptor.HTTPHandler(live.Javascript{}))

	log.Fatal(app.Listen(":8080"))
}

views/view.html

<!doctype html>
<html>
    <body>
        <div>{{.Assigns.C}}</div>
        <button live-click="temp-up">+</button>
        <button live-click="temp-down">-</button>
        <!-- Include to make live work -->
        <script src="/live.js"></script>
    </body>
</html>