Install ESLint and prettier with yarn 4 through corepack (closes #493)
check / check (push) Successful in 3m37s

yarn 1, which the node image ships and which is no longer developed,
printed node's url.parse() deprecation warning during the js-deps
install. package.json now pins yarn 4.18.1 by version and hash in its
packageManager field; the js-deps stage enables it with the node
image's own corepack and runs `yarn install --immutable`. yarn.lock is
regenerated in yarn 4's format from the old lockfile, so every package
keeps the version it had. The new .yarnrc.yml keeps the install in
node_modules/, where the lint and Markdown stages run the tools from.

Model: opus-5-5
This commit is contained in:
2026-10-03 04:36:34 +00:00
parent 935e18c6f1
commit 91aa0abea9
5 changed files with 638 additions and 433 deletions
+3
View File
@@ -0,0 +1,3 @@
# Install into node_modules/: the Dockerfile's lint and Markdown stages run
# ESLint and prettier from node_modules/.bin.
nodeLinker: node-modules
+12 -7
View File
@@ -67,15 +67,20 @@ RUN sed 's/}/}\n/g' static/css/tailwind.css > /tmp/committed.css \
# JavaScript lint stages: ESLint, at the version package.json and yarn.lock # JavaScript lint stages: ESLint, at the version package.json and yarn.lock
# pin, checks static/js/ against eslint.config.mjs. js-deps installs it, and # pin, checks static/js/ against eslint.config.mjs. js-deps installs it, and
# prettier for the Markdown stages below, and stays cached until those two # prettier for the Markdown stages below, and stays cached until package.json,
# files change. script/lint forces only js-lint to re-run, and the build stage # yarn.lock or .yarnrc.yml changes. script/lint forces only js-lint to re-run,
# below runs it too. COPY . . brings in the CI cache barrier described in the # and the build stage below runs it too. COPY . . brings in the CI cache
# lint stage above. # barrier described in the lint stage above.
# node:24.21.0-alpine (LTS, with yarn 1.22.22), 2026-09-18 #
# The image's own corepack runs the yarn that package.json's packageManager
# field names, yarn 4.18.1 (released 2026-09-24), and checks it against the
# hash there. The image also ships yarn 1, which `corepack enable yarn`
# replaces.
# node:24.21.0-alpine (LTS), 2026-09-18
FROM node:24.21.0-alpine@sha256:ebfe2f90462722a7a4de65e91990e97fe0d401c70e0e762c5b53302f905ec1c1 AS js-deps FROM node:24.21.0-alpine@sha256:ebfe2f90462722a7a4de65e91990e97fe0d401c70e0e762c5b53302f905ec1c1 AS js-deps
WORKDIR /src WORKDIR /src
COPY package.json yarn.lock ./ COPY package.json yarn.lock .yarnrc.yml ./
RUN yarn install --frozen-lockfile --ignore-scripts RUN corepack enable yarn && yarn install --immutable --mode=skip-build
FROM js-deps AS js-lint FROM js-deps AS js-lint
COPY . . COPY . .
+16 -10
View File
@@ -3062,7 +3062,8 @@ webhooker/
├── Dockerfile.browser # Browser test image built by script/test-browser ├── Dockerfile.browser # Browser test image built by script/test-browser
├── Makefile # 13 of 19 targets shim script/; 6 are inline ├── Makefile # 13 of 19 targets shim script/; 6 are inline
├── go.mod / go.sum ├── go.mod / go.sum
├── package.json / yarn.lock # ESLint and prettier, pinned, for the JavaScript lint and Markdown stages ├── package.json / yarn.lock # ESLint, prettier and yarn, pinned, for the JavaScript lint and Markdown stages
├── .yarnrc.yml # yarn settings: install into node_modules/
├── eslint.config.mjs # ESLint configuration for static/js/ ├── eslint.config.mjs # ESLint configuration for static/js/
├── .prettierrc # prettier settings for the Markdown ├── .prettierrc # prettier settings for the Markdown
└── .golangci.yml # golangci-lint configuration └── .golangci.yml # golangci-lint configuration
@@ -3350,13 +3351,17 @@ 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 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 `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 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 `js-deps` stage before it installs ESLint with `yarn install --immutable`, which
changes, so only the lint step re-runs and ESLint is not downloaded again. fails rather than change `yarn.lock`. The yarn it runs is the one the
`eslint.config.mjs` turns on the rules of the JavaScript styleguide `packageManager` field in `package.json` pins by version and hash, which the
`REPO_POLICIES.md` links to that a linter can check: `no-var` and node image's own corepack fetches and checks. The stage stays cached until
`prefer-const`. ESLint prints nothing on a pass, so `script/lint` has no summary `package.json`, `yarn.lock` or `.yarnrc.yml` changes, so only the lint step
line to look for; it names the stage once for both `--target` and re-runs and ESLint is not downloaded again. `eslint.config.mjs` turns on the
`--no-cache-filter`, and `--target` fails on a name that matches no stage. 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.
prettier formats the Markdown, and it never runs on the host either. It is prettier formats the Markdown, and it never runs on the host either. It is
pinned in `package.json` and `yarn.lock` beside ESLint, installed by the same pinned in `package.json` and `yarn.lock` beside ESLint, installed by the same
@@ -3382,8 +3387,9 @@ independently of the compiler's:
`@source` lines name. `css-check` fails when the committed file differs from `@source` lines name. `css-check` fails when the committed file differs from
the generated one, and `make css` writes the generated file out from the generated one, and `make css` writes the generated file out from
`css-output` (see [Stylesheet](#stylesheet)). `css-output` (see [Stylesheet](#stylesheet)).
3. **JavaScript lint stages** (`node:24.21.0-alpine`, with yarn) — `js-deps` 3. **JavaScript lint stages** (`node:24.21.0-alpine`, with the yarn
installs ESLint and prettier from `yarn.lock` and `js-lint` runs ESLint over `package.json` pins, run through the image's corepack) — `js-deps` installs
ESLint and prettier from `yarn.lock` and `js-lint` runs ESLint over
`static/js/` (see [Linting](#linting)). `static/js/` (see [Linting](#linting)).
4. **Markdown stages** (on `js-deps`) — `markdown-check` runs prettier over the 4. **Markdown stages** (on `js-deps`) — `markdown-check` runs prettier over the
Markdown and fails on any file it would change, and `make fmt` writes the Markdown and fails on any file it would change, and `make fmt` writes the
+2 -1
View File
@@ -3,5 +3,6 @@
"devDependencies": { "devDependencies": {
"eslint": "10.11.0", "eslint": "10.11.0",
"prettier": "3.9.9" "prettier": "3.9.9"
} },
"packageManager": "yarn@4.18.1+sha512.b2e1e7524f654f2749d32b4ebcb4622473cb5bcbc485df2007e12a154e50162a4d795526768bc5f5b8f81717bfd79deb2472813d86fb5ae2eb551fa9c872b08f"
} }
+605 -415
View File
File diff suppressed because it is too large Load Diff