4.6 KiB
Development
Prerequisites
| Tool | Version | Install |
|---|---|---|
| Go | 1.27+ (see go.mod) |
|
| Node.js | 20.19+ or 22.12+ (22 LTS recommended) | nvm install 22 — Vite and vue-tsc run on Node |
| Bun (package manager and script runner) | 1.x | powershell -c "irm bun.sh/install.ps1 | iex" or curl -fsSL https://bun.sh/install | bash |
| Task | 3.43+ | go install github.com/go-task/task/v3/cmd/task@latest |
| Git | any |
task setup installs the rest: air for hot reload, gremlins for mutation testing, Go modules and frontend dependencies. Make sure $(go env GOPATH)/bin is on your PATH.
No C compiler is needed. The SQLite driver (glebarez/sqlite, backed by modernc.org/sqlite) is pure Go, and every build runs with CGO_ENABLED=0.
First run
cp .env.example .env # set at least JWT_SECRET; SMTP is only needed to actually send mail
task setup
task dev
Open http://localhost:5173.
How the dev setup works
browser ──▶ http://localhost:5173 Vite dev server (HMR) task dev:web
│ /v1/*, /healthz
└──proxy──▶ http://localhost:8080 Go API via air task dev:api
- Always use the Vite URL (5173). The Vite dev server proxies API calls to Go (see
server.proxyinweb/vite.config.ts). The browser therefore sees a single origin, so thejwtcookie works and no CORS setup is needed. In the frontend, call the API with relative URLs (/v1/...) and never hardcodelocalhost:8080. - air rebuilds and restarts the API when a
.goor.htmlfile (such as a mail template) changes. Its config is in.air.toml. - Run the two halves separately with
task dev:apiandtask dev:webif you want their logs in separate terminals.
The nofrontend build tag
The production binary embeds the built SPA from internal/infrastructure/assets/dist/ (the //go:embed in assets_embed.go). That directory only exists after task build:web.
To keep Go work independent of the frontend toolchain, all dev and quality tasks build with -tags nofrontend. That tag compiles assets_stub.go instead of the embed. The resulting binary serves the API normally and answers / with a notice that points to Vite.
| Command | Tag | Needs the frontend built? |
|---|---|---|
task dev:api, test, cover, mutate, lint:go |
nofrontend |
no |
task build, release, run |
(none) | yes (the task builds it first) |
plain go build ./..., go vet ./... |
(none) | yes, so add -tags nofrontend |
If your editor reports pattern all:dist: no matching files found, either run task build:web once or set the gopls build flags to -tags=nofrontend. In VS Code, add this to settings.json: "gopls": { "buildFlags": ["-tags=nofrontend"] }.
Everyday commands
task --list # everything available
task test # Go tests; extra args pass through: task test -- -run TestCreateArticle -v
task cover # coverage of the use cases → tmp/coverage.out
task mutate # gremlins mutation testing → tmp/gremlins.json
task lint # gofmt check, go vet, eslint --fix, vue-tsc
task fmt # gofmt -w + prettier
task run # build the production binary and run it (SPA embedded) on :8080
task clean # remove bin/, tmp/ and the built SPA
Tests
- All Go tests live in
test/(packagetest, black-box). They use in-memory fakes of the domainRepositoryinterfaces, so they need no database, SMTP server or network. - HTTP-level tests use
net/http/httptestagainst a chi router. Callvalidator.InitValidator()before invoking a handler. - The frontend has no test runner yet.
task lint:webruns eslint and a type check.
Data
With the default configuration, local state lives in ./data/: renewcms.db and uploads/. The directory is gitignored. Delete it to start from scratch.