Templiér is a Go web frontend development environment for Templ
- Watches your
.templfiles and rebuilds them. - Watches all non-template files, rebuilds and restarts the server ✨.
- Automatically reloads your browser tabs when the server restarts or templates change.
- Runs golangci-lint if enabled.
- Reports all errors directly to all open browser tabs ✨.
- Shuts your server down gracefully.
- Displays application server console logs in the terminal.
- Supports templ's debug mode for fast live reload.
- Avoids reloading when files didn't change by keeping track of checksums.
- Allows arbitrary CLI commands to be defined as custom watchers ✨.
- example: Bundle JavaScript
- example: Rebuild CSS
- example: Restart on config change
Install Templiér:
go install github.com/romshark/templier@latestThen copy-paste example-config.yml to your project source folder as templier.yml, edit to your needs and run:
templier --config ./templier.ymlℹ️ Templiér automatically detects templier.yml and templier.yaml in the directory its running in without the explicit --config flag.
As you may already know, templ supports live reload
out of the box using templ generate --watch --proxy="http://localhost:8080" --cmd="go run .",
which is great, but Templiér provides even better developer experience:
- 🥶 Templiér doesn't become unresponsive when the Go code fails to compile, instead it prints the compiler error output to the browser tab and keeps watching. Once you fixed the Go code, Templiér will reload and work as usual with no intervention. In contrast, templ's watcher needs to be restarted manually.
- 📁 Templiér watches all file changes recursively
(except for those that match
app.exclude), recompiles and restarts the server (unless prevented by a custom watcher). Editing an embedded.jsonfile in your app? Updating go mod? Templiér will notice, rebuild, restart and reload the browser tab for you automatically! - 🖥️ Templiér shows Templ, Go compiler and golangci-lint errors (if any), and any errors from custom watchers in the browser. Templ's watcher just prints errors to the stdout and continues to display the last valid state.
- ⚙️ Templiér provides more configuration options (TLS, debounce, exclude globs, etc.).
Custom configurable watchers allow altering the behavior of Templiér for files
that match any of the include globs and they can be used for various use cases
demonstrated below.
The requires option allows overwriting the default behavior:
- empty field/string: no action, just execute Cmd.
reload: Only reloads all browser tabs.restart: Restarts the server without rebuilding.rebuild: Requires the server to be rebuilt and restarted (standard behavior).
If custom watcher A requires reload but custom watcher B requires rebuild then
rebuild will be chosen once all custom watchers have finished executing.
The following custom watcher will watch for .js file updates and automatically run
the CLI command npm run js:bundle, after which all browser tabs will be reloaded
using requires: reload. fail-on-error: true specifies that if eslint or esbuild
fail in the process, their error output will be shown directly in the browser.
custom-watchers:
- name: Bundle JS
cmd: npm run bundle:js
include: ["*.js"]
exclude: ["path/to/your/dist.js"]
fail-on-error: true
debounce:
# reload browser after successful bundling
requires: reloadThe cmd above refers to a script defined in package.json scripts:
"scripts": {
"bundle:js": "eslint . && esbuild --bundle --minify --outfile=./dist.js server/js/bundle.js",
"lint:js": "eslint ."
},TailwindCSS and PostCSS are often used to simplify CSS styling and a custom watcher enables Templiér to hot-reload the styles on changes:
First, configure postcss.config.js:
module.exports = {
content: [
"./server/**/*.templ", // Include any .templ files
],
plugins: [require("tailwindcss"), require("autoprefixer")],
};and tailwind.config.js:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./**/*.{html,js,templ}"],
theme: {
extend: {},
},
plugins: [require("tailwindcss"), require("autoprefixer")],
};Create a package.json file and install all necessary dev-dependencies
npm install tailwindcss postcss postcss-cli autoprefixer --save-devAdd the scripts to package.json (where input.css is your main CSS
file containing your global custom styles and public/dist.css is the built CSS
output file that's linked to in your HTML):
"scripts": {
"build:css": "postcss ./input.css -o ./public/dist.css",
"watch:css": "tailwindcss -i ./input.css -o ./public/dist.css --watch"
},Finally, define a Templiér custom watcher to watch all Templ and CSS files and rebuild:
- name: Build CSS
cmd: npm run build:css
include: ["*.templ", "input.css"]
exclude: ["path/to/your/dist.css"]
fail-on-error: true
debounce:
requires: reloadNOTE: if your dist.css is embedded, you may need to use requires: rebuild.
Normally, Templiér rebuilds and restarts the server when any file changes (except for
.templ and _templ.txt files). However, when a config file changes we don't usually
require rebuilding the server. Restarting the server may be sufficient in this case:
- name: Restart server on config change
cmd: # No command, just restart
include: ["*.toml"] # Any TOML file
exclude:
fail-on-error:
debounce:
requires: restartTempliér acts as a file watcher, proxy server and process manager.
Once Templiér is started, it runs templ generate --watch in the background and begins
watching files in the app.dir-src-root directory.
On start and on file change, it automatically builds your application server executable
saving it in the OS' temp directory (cleaned up latest before exiting) assuming that
the main package is specified by the app.dir-cmd directory.
Custom Go compiler arguments can be specified with compiler. Once built, the application server
executable is launched with app.flags CLI parameters and the working directory
set to app.dir-work. When necessary, the application server process is shut down
gracefully, rebuilt, linted and restarted.
On .templ file changes Templiér only tries to compile and lint the server code
without refreshing the page.
On _templ.txt file changes Templiér refreshes the page.
Templiér hosts your application under the URL specified by templier-host and proxies
all requests to the application server process that it launched injecting Templiér
JavaScript that opens a websocket connection to Templiér from the browser tab to listen
for events and reload or display necessary status information when necessary.
In the CLI console logs, all Templiér logs are prefixed with 🤖,
while application server logs are displayed without the prefix.
Run the tests using go test -race ./... and use the latest version of
golangci-lint to ensure code integrity.
You can build Templiér using the following command:
go build -o templier ./bin/templierIf you're adding bin library to your path, you can just execute the binary.
zsh:
export PATH=$(pwd)/bin:$PATHfish:
fish_add_path (pwd)/bin- Templiér currently doesn't support Windows.
- When measuring performance, make sure you're not running against the Templiér proxy
that injects the JavaScript for auto-reloading because it will be slower and should
only be used for development. Instead, use the direct host address of your application
server specified by
app.hostin yourtemplier.ymlconfiguration. - Templiér's JavaScript injection uses the
GET /__templier/eventsHTTP endpoint for its websocket connection. Make sure it doesn't collide with your application's paths.