In this section, we will start by adding an index.html and wiring our server to server static content. We want a tracer bullet to for our web client. This will get the process of generating and serving our web UI in place. We will then add in more complexity for resources and js to get, set, and display data.

(explain tracer bullet more) (add link to webpage about it)


We are going to add an index.html file, so first we make sure it will be generated from a template. We update our server generator to add index.html to the OnceFiles.


		// Generator definition
#HofGenerator: gen.#HofGenerator & {
	OnceFiles: [...gen.#File] & [
			TemplatePath: "index.html"
			Filepath:     "\(Outdir)/client/index.html"


Create an index.html. This displays a minimal welcome message.


<!DOCTYPE html>
<html lang="en">
    <meta charset="utf-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />

    <title>{{ .SERVER.Name }}</title>

    <link href="" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <div class="main">
      <div class="container pt-3">
        <div class="row">
          Welcome to the {{ $.SERVER.Name }} client

    <!-- scripts -->
    <script src=""></script>
    <script src="" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>


In order to serve our HTML, we need to adjust our API routes. First we need to move our existing routes to /api, to make room for our static content route Second, we need to server our static content from / so index.html behaves correctly in the browser.


func setupRouter(e *echo.Echo) error {

	// Internal routes and Prometheus

	// Static content
	e.Static("/", "client")

	// API routes
	g := e.Group("/api")

	// routes and resources

	return nil

Regen, Rebuild, Rerun

(the three Re’s)

Breaking down index into partials

  • break down now, prep for next section and reuse
  • add navbar while we are at it
2022 Hofstadter, Inc