Files
RenewCMS/docs/development.md
T

75 lines
4.6 KiB
Markdown

# Development
## Prerequisites
| Tool | Version | Install |
|-------------------------------|----------------------------|----------------------------------------------------------|
| [Go](https://go.dev/dl/) | 1.27+ (see `go.mod`) | |
| [Node.js](https://nodejs.org) | 20.19+ or 22.12+ (22 LTS recommended) | `nvm install 22` — Vite and vue-tsc run on Node |
| [Bun](https://bun.sh) (package manager and script runner) | 1.x | `powershell -c "irm bun.sh/install.ps1 \| iex"` or `curl -fsSL https://bun.sh/install \| bash` |
| [Task](https://taskfile.dev) | 3.43+ | `go install github.com/go-task/task/v3/cmd/task@latest` |
| Git | any | |
`task setup` installs the rest: [air](https://github.com/air-verse/air) for hot reload, [gremlins](https://github.com/go-gremlins/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
```sh
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.proxy` in [`web/vite.config.ts`](../web/vite.config.ts)). The browser therefore sees a single origin, so the `jwt` cookie works and no CORS setup is needed. In the frontend, call the API with relative URLs (`/v1/...`) and never hardcode `localhost:8080`.
- **air** rebuilds and restarts the API when a `.go` or `.html` file (such as a mail template) changes. Its config is in [`.air.toml`](../.air.toml).
- Run the two halves separately with `task dev:api` and `task dev:web` if 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
```sh
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/`](../test) (package `test`, black-box). They use in-memory fakes of the domain `Repository` interfaces, so they need no database, SMTP server or network.
- HTTP-level tests use `net/http/httptest` against a chi router. Call `validator.InitValidator()` before invoking a handler.
- The frontend has no test runner yet. `task lint:web` runs 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.