Photo by Goran Ivos on Unsplash

I like Go. I don’t like JavaScript. So I posed the question…

How could I write a reactive single page app without using the JavaScript or it’s ecosystem?

Here’s what I came up with:

package main import "github.com/elliotchance/pepper" type Counter struct {

Number int

}

return `

Counter: {{ .Number }}<br/>

<button

`, nil

} func (c *Counter) Render() (string, error) {return `Counter: {{ .Number }}

@click ="AddOne">+ `, nil func (c *Counter) AddOne() {

c.Number++

} func main() {

panic(pepper.StartServer(func() pepper.Component {

return &Counter{}

}))

}

That code encapsulates the entire stack. If you have Go installed, you can try it right now:

go get -u github.com/elliotchance/pepper/examples/ex01_counter

ex01_counter

Now open http://localhost:8080 in your browser… Or, just peek at this screenshot:

OK, so it’s not going to win any design awards, but clicking the + button does increment the number as expected.

So What Is Really Going On Here?

Counter is a component, because it has a Render() method. Render returns a html/template that will be properly rendered for the client. It can reference any state, such as the Number or bind an event to a method, such as @click="AddOne" .

The architecture is very simple. When the browser opens the page (http://localhost:8080) it’s returned an almost empty page. This page contains a single empty div and a few functions to connect through a websocket.

Immediately after the page loads the websocket will connect. Upon connecting the server will render the component and send the HTML down, which will be placed on the page.

So this is just backend rendering? Well, yes and no. It is effectively rendering the whole component, and sending the whole HTML down the websocket. However, that’s only because that’s easy right now. The server could be optimized to send a diff, or avoid rendering unchanged components entirely.

Can I Use It?

pepper is still extremely experimental. It requires a constant connection to the server (for the websocket) so it wouldn’t work for anything that must function offline, or used in cases where the internet is flaky.

I imagine some good use cases for pepper would be:

Showing real time data. Streaming metrics, graphs, logs, dashboards, etc. Apps that rely on a persistent connection. Such as chat clients, timed interactive exams, etc. Apps that would benefit from persistent state. The entire state can be saved or restored into a serialized format like JSON. Great for forms or surveys with many questions/steps. Prototyping a frontend app. It’s super easy to get up and running and iterate changes without setting up a complex environment, build tools and dependencies.

Are There More Complex Examples?

Yes! Walk through the examples on the main repository page where it covers forms, nested components and probably more by the time you read this.