Lint static/js/ with ESLint in Docker (closes #120)
check / check (push) Successful in 3m29s
check / check (push) Successful in 3m29s
ESLint, pinned by package.json and yarn.lock, runs in a new js-lint stage of the Dockerfile on the pinned node 24 LTS image. It starts from a js-deps stage that installs ESLint and stays cached until those two files change. script/lint builds js-lint after the Go lint, and the build stage depends on it, so make check and the image build both fail on a violation. eslint.config.mjs turns on the styleguide's checkable rules: no-var and prefer-const. Model: opus-5-5
This commit is contained in:
@@ -26,7 +26,9 @@ before deploying one.
|
||||
golangci-lint is not a prerequisite and must not be installed on the
|
||||
host: `script/bootstrap` does not install it, and `make lint` runs the
|
||||
digest-pinned linter image via `Dockerfile.lint`. The same holds for
|
||||
tailwindcss (see [Stylesheet](#stylesheet)).
|
||||
tailwindcss (see [Stylesheet](#stylesheet)). ESLint, node and yarn are
|
||||
not prerequisites either, and `make lint` never uses a host copy of them
|
||||
(see [Linting](#linting)).
|
||||
|
||||
### Quick Start
|
||||
|
||||
@@ -58,7 +60,7 @@ make setup # Bootstrap + install git pre-commit hook
|
||||
make assets # Extract Alpine.js from 3p/ (test, check, build, dev run it)
|
||||
make fmt # Format code (gofmt + goimports)
|
||||
make fmt-check # Fail if gofmt would change anything (writes nothing)
|
||||
make lint # Run golangci-lint in Docker (Dockerfile.lint)
|
||||
make lint # Run golangci-lint and ESLint in Docker
|
||||
make test # Run tests with race detection
|
||||
make test-browser # Run the browser test in Docker (Dockerfile.browser)
|
||||
make check # test + lint + fmt-check + css-check (CI gate)
|
||||
@@ -1318,7 +1320,8 @@ We provide:
|
||||
- `script/test` — run the test suite
|
||||
- `script/test-browser` — run the browser test in Docker (see
|
||||
[Third-party browser assets](#third-party-browser-assets))
|
||||
- `script/lint` — run golangci-lint in Docker (see Linting below)
|
||||
- `script/lint` — run golangci-lint and ESLint in Docker (see Linting
|
||||
below)
|
||||
- `script/fmt` — format all code (writes)
|
||||
- `script/fmt-check` — check formatting (read-only)
|
||||
- `script/css` — regenerate `static/css/tailwind.css` in Docker (writes;
|
||||
@@ -3206,12 +3209,14 @@ webhooker/
|
||||
│ └── js/alpine.min.js # Alpine.js CSP build, extracted from 3p/ by make assets, not committed
|
||||
├── templates/ # Go HTML templates (base, login, sources, etc.)
|
||||
├── script/ # Scripts to Rule Them All entrypoints
|
||||
├── Dockerfile # Stages: lint, stylesheet, test+build, Alpine runtime
|
||||
├── Dockerfile # Stages: lint, stylesheet, JavaScript lint, test+build, Alpine runtime
|
||||
├── Dockerfile.lint # Lint-only image built by script/lint
|
||||
├── Dockerfile.browser # Browser test image built by script/test-browser
|
||||
├── Makefile # 13 of 19 targets shim script/; 6 are inline
|
||||
├── go.mod / go.sum
|
||||
└── .golangci.yml # Linter configuration
|
||||
├── package.json / yarn.lock # ESLint, pinned, for the JavaScript lint stage
|
||||
├── eslint.config.mjs # ESLint configuration for static/js/
|
||||
└── .golangci.yml # golangci-lint configuration
|
||||
```
|
||||
|
||||
### Dependency Injection
|
||||
@@ -3521,6 +3526,20 @@ Three properties are load-bearing:
|
||||
`golangci-lint run` silently ignores config keys it does not
|
||||
recognize, so a typo would disable a setting with no warning.
|
||||
|
||||
ESLint never runs on the host either. It lints `static/js/` (not the
|
||||
extracted Alpine.js) in the Dockerfile's `js-lint` stage, which
|
||||
`script/lint` builds after `Dockerfile.lint` and the image build runs
|
||||
before the builder stage. Its version is pinned in `package.json` and
|
||||
every package's hash in `yarn.lock`. The `js-deps` stage before it
|
||||
installs ESLint and stays cached until either file changes, so only the
|
||||
lint step re-runs and ESLint is not downloaded again.
|
||||
`eslint.config.mjs` turns on the rules of the JavaScript styleguide
|
||||
`REPO_POLICIES.md` links to that a linter can check: `no-var` and
|
||||
`prefer-const`. ESLint prints nothing on a pass, so `script/lint` has no
|
||||
summary line to look for; it names the stage once for both `--target`
|
||||
and `--no-cache-filter`, and `--target` fails on a name that matches no
|
||||
stage.
|
||||
|
||||
### Docker
|
||||
|
||||
The Dockerfile uses a multi-stage build. Each stage is pinned by
|
||||
@@ -3539,8 +3558,12 @@ linter's version is fixed independently of the compiler's:
|
||||
`css-check` fails when the committed file differs from the generated
|
||||
one, and `make css` writes the generated file out from `css-output`
|
||||
(see [Stylesheet](#stylesheet)).
|
||||
3. **Builder stage** (`golang:1.26.1-bookworm`) — depends on the lint
|
||||
and `css-check` stages passing (it copies a file from each), runs
|
||||
3. **JavaScript lint stages** (`node:24.21.0-alpine`, with yarn) —
|
||||
`js-deps` installs ESLint from `yarn.lock` and `js-lint` runs it over
|
||||
`static/js/` (see [Linting](#linting)).
|
||||
4. **Builder stage** (`golang:1.26.1-bookworm`) — depends on the lint,
|
||||
`css-check` and `js-lint` stages passing (it copies a file from
|
||||
each), runs
|
||||
`make test` and `make build` (both extract Alpine.js from `3p/`
|
||||
first), and finally
|
||||
rebuilds the binary with `CGO_ENABLED=1` and static linking so it
|
||||
@@ -3550,7 +3573,7 @@ linter's version is fixed independently of the compiler's:
|
||||
given, otherwise derived from the `.git` in the context, and the
|
||||
stage fails if a context with `.git` would stamp `unknown` (see
|
||||
[Version stamping](#version-stamping)).
|
||||
4. **Runtime stage** (`alpine:3.21`) — copies the static binary and
|
||||
5. **Runtime stage** (`alpine:3.21`) — copies the static binary and
|
||||
`deploy/docker-entrypoint.sh`, creates the `/var/lib/webhooker`
|
||||
directory for all SQLite databases, exposes port 8080, and includes
|
||||
a health check against `/.well-known/healthcheck`. It sets no
|
||||
@@ -3570,8 +3593,9 @@ linked, which is what lets it run on the Alpine runtime image.
|
||||
`script/cibuild` — `docker build .` — is the CI gate: the checks run
|
||||
inside the image, so a build that succeeds is a repo that is formatted,
|
||||
linted, tested and compiled, with a current stylesheet. `script/lint`
|
||||
also uses Docker (`Dockerfile.lint`, see Linting above), so `make lint`
|
||||
and `make check` run the same pinned linter version the gate does; of
|
||||
also uses Docker (`Dockerfile.lint` and the `js-lint` stage, see Linting
|
||||
above), so `make lint` and `make check` run the same pinned linter
|
||||
versions the gate does; of
|
||||
the steps `make check` runs, only `script/test` and `script/fmt-check`
|
||||
run on the host.
|
||||
|
||||
@@ -3585,8 +3609,8 @@ the hash of the commit being checked, so every commit, docs-only ones
|
||||
and a squash merge whose tree matches an already-built branch included,
|
||||
gets a new fingerprint, invalidates the `COPY . .` layer of every check
|
||||
stage, and really runs `make fmt-check`, `golangci-lint`, the stylesheet
|
||||
check, `make test`, and `make build`. A run that reports success ran
|
||||
them.
|
||||
check, ESLint, `make test`, and `make build`. A run that reports success
|
||||
ran them.
|
||||
|
||||
The module download layer sits above `COPY . .` and stays cached.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user