tinka alpha

Development environment setup

This guide covers the development environment for Tinka Apps. You will learn how to:

Overview

While you work, the App should follow your edits without you stopping and starting it. act serve builds the App, runs it, and watches its files. When you save a change, it builds the new App while the old one keeps serving, then restarts it in a few milliseconds. Requests that arrive during the restart wait instead of failing, and pages open in your browser reload.

act serve runs the App's own binary, the one that runs in production, built with the same go build. Nothing is generated before the build, and nothing about the App changes in development: shutdown hooks run on each restart exactly as they do when your platform stops the App.

Run the dev server

Run act serve from the App's directory:

Terminal
act serve
Output
  INFO  Watching for changes (inotify, 12 directories)
  INFO  Built in 2.0s, serving http://localhost:3000

Open the address it prints. Building and running the App runs its code, so the first time, act asks whether you trust the App's directory. See act trust.

act serve serves on localhost:3000. Pass --addr for another address, such as --addr :8080 to accept connections from other machines on your network:

Terminal
act serve --addr localhost:8080

The App's own Addr doesn't apply under act serve: the dev server decides where the App listens, and passes it the listener.

act serve answers requests for localhost, its subdomains such as blog.localhost, and IP addresses. A request for any other name gets a 403, because a web page you visit could otherwise point a name of its own at your machine and read your App through your browser. To open the App under a name of your own, such as one in /etc/hosts, allow it:

Terminal
act serve --allow-host blog.test

What happens on a change

act serve reacts to the files a build reads: Go files, go.mod, go.sum and files your code embeds. A save that changes none of them, such as an editor's swap file, starts no build. For a change that does:

  1. Build

    The new App is built while the old one keeps serving the previous code. A change made during a build cancels it and starts again from the newest files.

  2. Stop the old App

    The old App receives SIGTERM and shuts down gracefully: requests in flight finish and shutdown hooks run. It is killed if it hasn't stopped after 15 seconds.

  3. Start the new App

    The new App starts on the same listener. Requests that arrived in between wait in the queue, so none fails.

Output
  INFO  Built in 1.3s, restarted in 37ms

When the App stops on its own, such as when it fails to connect to its database at startup, act serve shows its output and starts it again on your next change.

Read build errors

When a build fails, the old App keeps running and act serve prints the compiler's errors:

Output
  ERROR  The build failed after 412ms; the App keeps running its previous code
# example.com/blog
./posts.go:14:9: undefined: render

Pages you open in the browser show the same errors instead of the App, so you see them where you're looking. Requests that don't come from a browser page, such as fetch calls and API clients, still reach the old App. Fixing the error swaps the new App in.

Reload open pages

After each restart, and when a build fails, pages open in the browser reload on their own. act serve adds a small script, /__tinka/live.js, before the closing </body> of every full HTML page the App returns. Fragments, such as htmx's partial responses, and anything that isn't HTML are left as they are. The script is a file of its own, so a Content-Security-Policy of script-src 'self' allows it.

Watch network drives and containers

act serve learns about changes from the operating system on Linux and Windows. Some file systems never report changes, such as network drives, folders shared into a virtual machine or a container, and paths under /mnt in WSL. Pass --poll to check for changes on a timer instead:

Terminal
act serve --poll

On macOS, act serve always checks on a timer. A check takes a few milliseconds for an App of a few hundred files.

Serve without the proxy

act serve listens on --addr and forwards requests to the App, which is what lets it hold requests during a restart, show build errors and reload pages. Pass --no-proxy to give the App the address directly, with none of these:

Terminal
act serve --no-proxy

On Linux and macOS the port still stays open across restarts. On Windows, connections made during a restart fail.

Set up your editor

Tinka is plain Go, so every editor with Go support works. Install gopls, the Go team's language server, through your editor's Go extension, and turn on formatting on save, so every file stays gofmted.

See also: Commands reference, Application lifecycle, Configuration & Environment