Serve the First Page
0. HTTPS self-signed certs
HTTP without SSL forces HTTP/1.1, which limits the number of parallel requests to a maximum of six.
It’s recommended (but not necessary) to use HTTPS in the development environment.
Generate Certs
In tutorial project dir:
# install package
$ go install filippo.io/mkcert@latest
# makes generated certs trustable by the system (removes browser warning for you), optional
$ mkcert -install
# create certs in the current folder
$ mkcert localhost 127.0.0.1 ::1
...
The certificate is at "./localhost+2.pem" and the key at "./localhost+2-key.pem"
1. General Page Template
First, let’s create a baseline template.
./common/page.templ
package common
import "github.com/doors-dev/doors"
// all our pages must be of this shape
type Page interface {
// method returns component for head insertion
Head() templ.Component
// method returns component for body insertion
Body() templ.Component
}
// now page template that takes `Page` as arg
templ Template(p Page) {
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="color-scheme" content="light dark"/>
// IMPORTANT: include framework script
@doors.Include()
// render page head
@p.Head()
</head>
<body>
// render page content
@p.Body()
</body>
</html>
}
2. Path Model
Refer to Path Model in the docs for an explanation of how it works.
Now we need to create a path model structure. Let’s put it in a common package so it can be imported into all other packages.
./common/path.go
package common
type HomePath struct {
Main bool `path:"/"` // match root
}
3. Home Page
Create a new package that will include everything related to the homepage.
Page Template and Page Request Handler
./home/page.templ
package home
import "github.com/doors-dev/doors"
import "github.com/derstruct/doors-tutorial/common"
// alias path for ease of use
type Path = common.HomePath
type homePage struct{}
// implement common.Page interface
templ (h *homePage) Head() {
<title>hello doors</title>
}
templ (h *homePage) Body() {
<h1>Yeah!</h1>
}
// Render method is neccessary for page declaration.
// doors.SourceBeam is used to subscribe to path changes
// (in case of home page there are no parameters or path variants, so we won't use it)
templ (p *homePage) Render(_ doors.SourceBeam[Path]) {
// use our template
@common.Template(p)
}
// we also need a handler function to serve our home page when the path matches Path
// pr provides routing options, r - http request wrapper
func Handler(p doors.PageRouter[Path], r doors.RPage[Path]) doors.PageRoute {
// just serve our home page
return p.Page(&homePage{})
}
Before proceeding, generate a .go
files from .templ
$ templ generate
3. Router
Now, let’s create doors router, attach our page handler, and serve.
./main.go
package main
import (
"github.com/derstruct/doors-tutorial/home"
"github.com/doors-dev/doors"
"net/http"
)
func main() {
// create doors router
r := doors.NewRouter()
// attach home handler
r.Use(doors.UsePage(home.Handler))
// start server with our self signed cert
err := http.ListenAndServeTLS(":8443", "localhost+2.pem", "localhost+2-key.pem", r)
if err != nil {
panic(err)
}
}
The file structure you should have by this point:
.
├── common
│ ├── page_templ.go // autogenerated
│ ├── page.templ
│ └── path.go
├── go.mod
├── go.sum
├── home
│ ├── page.templ
│ ├── page_templ.go // autogenerated
└── main.go
└── localhost+2.pem
└── localhost+2-key.pem
4. Done
$ templ generate && go run .
Then visit https://localhost:8443/ to check; you should see an empty page with a header and title.
If you didn’t install the CA (
mkcert -install
), you will see a warning first. Just proceed; it’s a self-signed certificate - you can trust it.
Next: Live Reloading