Home

Awesome

<a href="https://goreportcard.com/report/github.com/romshark/templier"> <img src="https://goreportcard.com/badge/github.com/romshark/templier" alt="GoReportCard"> </a> <br> <br> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/romshark/templier/5c68f5b74984b6a2c6aec66912f6852819acbf9e/logo_white.svg"> <img src="https://raw.githubusercontent.com/romshark/templier/5c68f5b74984b6a2c6aec66912f6852819acbf9e/logo_color.svg" alt="Logo" width="400"> </picture>

Templiér is a Go web frontend development environment for Templ

ℹ️ Make sure you stop Templiér before you commit your git changes! Templiér uses templ's watcher internally which rebuilds all _templ.go files for production when it exits. All _templ.go files are optimized for development speed (hot-reload using _templ.txt files) while Templiér is running.

Quick Start

Install Templiér:

go install github.com/romshark/templier@latest

Then 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.

How is Templiér different from templ's own watch mode?

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:

Custom Watchers 👁️👁️

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:

If custom watcher A requires reload but custom watcher B requires rebuild then rebuild will be chosen once all custom watchers have finished executing.

Custom Watcher Example: JavaScript Bundler

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: reload

The 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 ."
},

Custom Watcher Example: TailwindCSS and PostCSS

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-dev

Add 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: reload

NOTE: if your dist.css is embedded, you may need to use requires: rebuild.

Custom Watcher Example: Reload on config change.

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: restart

How Templiér works

Templié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. Any custom Go compiler CLI arguments can be specified by app.go-flags. 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.

Templiér ignores changes made to .templ, _templ.go and _templ.txt files and lets templ generate --watch do its debug mode magic allowing for lightning fast reloads when a templ template changed with no need to rebuild the server.

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.

Development

Run the tests using go test -race ./... and use the latest version of golangci-lint to ensure code integrity.

Building

You can build Templiér using the following command:

go build -o templier ./bin/templier

If you're adding bin library to your path, you can just execute the binary.

zsh:

export PATH=$(pwd)/bin:$PATH

fish:

fish_add_path (pwd)/bin