Skip to content

Commit

Permalink
Add HTMX and Air (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidNix authored Nov 12, 2023
1 parent 754cdfa commit 560976a
Show file tree
Hide file tree
Showing 20 changed files with 482 additions and 72 deletions.
47 changes: 47 additions & 0 deletions .air.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"

[build]
args_bin = ["--addr=localhost:3000"]
bin = "./tmp/main"
cmd = "GOEXPERIMENT=loopvar go build -race -o ./tmp/main"
delay = 1000
# Exluding ent because it causes Air to infinitely detect changes
exclude_dir = ["assets", "tmp", "vendor", "testdata", "ent"]
exclude_file = []
exclude_regex = ["_test.go", ".*_templ.go"]
exclude_unchanged = true
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html", "templ"]
include_file = []
kill_delay = "1s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = ["go generate ./..."]
rerun = false
rerun_delay = 1000
send_interrupt = true
stop_on_error = true

[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"

[log]
main_only = false
time = false

[misc]
clean_on_exit = false

[screen]
clear_on_rebuild = false
keep_scroll = true
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@

# Go workspace file
go.work

# Air artifacts
/tmp
2 changes: 1 addition & 1 deletion .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ linters:
- errorlint
- exportloopref
- forbidigo
- forcetypeassert
# - forcetypeassert
- gochecknoinits
- gocritic
- gofumpt
Expand Down
17 changes: 11 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,28 @@ setup: ## Setup your local dev environment. Run this once after cloning the repo

.PHONY: run
run: ## Run the app
@GOEXPERIMENT=loopvar go run -mod=readonly -race .
@GOEXPERIMENT=loopvar go run -mod=readonly -race . --addr localhost:3000

.PHONY: vet
vet: ## Run vet and linters
@golangci-lint run
golangci-lint run

.PHONY: test
test: ## Run unit tests
@go test -mod=readonly -race -cover -timeout=60s ./...

.PHONY: ent
ent: ## Run ent codegen. E.g. make ent new User
@go run -mod=mod entgo.io/ent/cmd/ent $(filter-out $@,$(MAKECMDGOALS))

.PHONY: gen
gen: ## Generate code
@go generate ./...

AIR = go run -mod=readonly github.com/cosmtrek/air
.PHONY: watch
watch: ## Watch and reload code changes
@$(AIR)

.PHONY: ent
ent: ## Run ent codegen. E.g. make ent new User
@go run -mod=readonly entgo.io/ent/cmd/ent $(filter-out $@,$(MAKECMDGOALS))

%: # Catch-all target to allow passing arguments to targets without workarounds like ARGS="1 2 3"
@:
63 changes: 55 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# WARNING: THIS IS A WIP!

# Indie
An opinionated Go stack for the indie hacker or early stage projects.

Opinionated Go boilerplate for the indie hacker or early stage projects.

![indie-logo.png](indie-logo.png)

Expand All @@ -14,11 +13,14 @@ Why not Rails, Django, or Phoenix?
Sure, if you enjoy the hell that is dynamically typed languages.

## The Stack

- Go (duh)
- [Viper](https://github.com/spf13/viper) and [Cobra](https://github.com/spf13/cobra) for configuration and CLI
- [Fiber](https://gofiber.io) for web server
- [Cobra](https://github.com/spf13/cobra) for cli
- [Echo](https://echo.labstack.com) for web server and router
- [HTMX](https://htmx.org) for dynamic web pages
- [Ent](https://entgo.io) for ORM
- [Ent](https://entgo.io) for database/ORM
- [Testify](https://github.com/stretchr/testify) for test matchers
- [Air](https://github.com/cosmtrek/air) for live reload

## Use as Project Template

Expand All @@ -39,20 +41,65 @@ gonew github.com/DavidNix/indie github.com/<YOUR_USER>/<YOUR_PROJECT_NAME>
All funneled through `make`.

To see what you can do:

```sh
make
```

Then (assumes you have homebrew installed):
```

```sh
make setup
```

## OMG an ORM?!?!
Generate code:
```sh
make gen
```

Run the server:

```sh
make run
```

Live reload:

```sh
make watch
```
Caveat: Any ent (data model) changes will require a manual restart.

# Features

## Development Speed

Using ent allows automatic migrations. At scale, this is bad. But for iterating quickly, it's great.

Ent lets us use an in-memory sqlite database for unit tests. This is a huge win for speed.

## Reasonable Security

The license still stands that this software is provided **as-is with no warranty**.

But I've tried to make reasonable security decisions such as server timeouts, CSRF protection, and secure headers.

# Design Decisions

## Why Echo?

I first tried [Fiber](https://github.com/gofiber/fiber) which uses [fasthttp](https://github.com/fasthttp/router) as the
router. Unfortunately, fasthttp has a [nasty race condition](https://twitter.com/davidnix_/status/1720454052973044188)
when using database/sql. Also, Fiber makes you choose between `c.Context()` and `c.UserContext()` which is confusing.

Also, Echo is one of the older Go http frameworks, so hopefully has the Lindy Effect.

## Wait, an ORM?!

Those who know me will be shocked I'm using an ORM. (I typically despise them.)

But hear me out. In this context (getting a project off the ground at light speed), it's a good fit:

- Validation out of the box.
- Unit tests with in-memory sqlite.
- Automatic migrations.
Expand Down
15 changes: 15 additions & 0 deletions ent/seed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package ent

import (
"context"
)

// Seed adds sample data to the database.
func Seed(ctx context.Context, c *Client) error {
_, err := c.User.CreateBulk(
c.User.Create().SetName("Alice"),
c.User.Create().SetName("Bob"),
c.User.Create().SetName("Zod"),
).Save(ctx)
return err
}
39 changes: 27 additions & 12 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,67 @@ go 1.21

require (
entgo.io/ent v0.12.4
github.com/a-h/templ v0.2.432
github.com/cosmtrek/air v1.49.0
github.com/labstack/echo/v4 v4.11.2
github.com/mattn/go-sqlite3 v1.14.17
github.com/samber/lo v1.38.1
github.com/samber/slog-echo v1.8.0
github.com/spf13/cobra v1.7.0
github.com/spf13/viper v1.17.0
github.com/stretchr/testify v1.8.4
)

require (
ariga.io/atlas v0.14.1-0.20230918065911-83ad451a4935 // indirect
dario.cat/mergo v1.0.0 // indirect
github.com/a-h/lexical v0.0.53 // indirect
github.com/a-h/parse v0.0.0-20230402144745-e6c8bc86e846 // indirect
github.com/a-h/protocol v0.0.0-20230224160810-b4eec67c1c22 // indirect
github.com/agext/levenshtein v1.2.1 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/bep/godartsass v0.16.0 // indirect
github.com/bep/golibsass v1.1.0 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cli/browser v1.2.0 // indirect
github.com/cli/safeexec v1.0.0 // indirect
github.com/creack/pty v1.1.18 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fatih/color v1.14.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-openapi/inflect v0.19.0 // indirect
github.com/gohugoio/hugo v0.111.3 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/hcl/v2 v2.13.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/labstack/gommon v0.4.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/natefinch/atomic v1.0.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/sagikazarmark/locafero v0.3.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/samber/lo v1.38.1 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/segmentio/encoding v0.3.6 // indirect
github.com/spf13/afero v1.10.0 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tdewolff/parse/v2 v2.6.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/zclconf/go-cty v1.8.0 // indirect
go.lsp.dev/jsonrpc2 v0.10.0 // indirect
go.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2 // indirect
go.lsp.dev/uri v0.3.0 // indirect
go.opentelemetry.io/otel v1.19.0 // indirect
go.opentelemetry.io/otel/trace v1.19.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/mod v0.12.0 // indirect
Expand All @@ -60,6 +74,7 @@ require (
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.13.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading

0 comments on commit 560976a

Please sign in to comment.