Verify every integration against its real host, before tagging 0.4.0 - #20
Merged
Conversation
`require('eaa-kit/webpack')` — the line the docs print — failed with
ERR_PACKAGE_PATH_NOT_EXPORTED. Every subpath export named an `import`
condition and nothing else, so CommonJS resolution found no way in.
That is most of these hosts. A webpack.config.js is ordinarily CommonJS,
so are docusaurus.config.js and .eleventy.js, and none of them could
load the integration written for them. It was a documented feature that
did not work as documented, which is worse than not shipping it.
Each subpath now names a `require` condition beside `import`, pointing
at the same file. Node's require(esm) loads it on every version in
`engines`, so nothing is compiled twice and the package stays ESM-only.
The one thing that would break it again is a top-level await anywhere in
a graph an integration pulls in — require(esm) refuses those. So the
packaged harness now loads all six entries both ways, and a future
top-level await fails there rather than in somebody's build.
Verified against a real `npm pack` install: the webpack config exactly
as the docs print it now loads and yields a plugin with an apply().
Also bumps the two GitHub Action pins from v0.3.0 to v0.4.0, which the
docs tell people to set to an exact release tag.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HKU933TcRaKinharQxrNht
It sat under Unreleased, which would have tagged v0.4.0 with a changelog saying part of the release was not in it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HKU933TcRaKinharQxrNht
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
The plugin makes three claims about somebody else's software: that `afterEmit` fires with every file on disk, that `compilation.errors` says whether the build failed, and that `compiler.watchMode` separates a one-shot run from a dev server. The Nuxt module shipped in this branch with a wrong claim of exactly that kind — it read a field Nuxt never populates, and its hand-written stand-in agreed with the bug — so these are now checked against webpack itself rather than a stub. All three held. The suite covers a failing compile, a clean build, `failBuild: false`, the resolved output directory (deliberately not `dist`, so a guess would audit nothing), and the watch-mode skip. `watchMode` is sampled inside the watch callback: `close()` puts it back to false, so reading it afterwards would report that the guard had nothing to act on when it did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HKU933TcRaKinharQxrNht
The Docusaurus hook is the cleanest of any builder here — `postBuild` runs when the whole site is on disk and hands over `outDir` — and the plugin written against it cannot work, for a reason outside its own code. Docusaurus loads plugins through jiti, which intercepts dynamic `import()`; axe-core then reaches jiti's module evaluator instead of Node's and is evaluated without the globals it expects, so the audit dies on `Cannot read properties of undefined (reading 'document')` at the end of a build that otherwise succeeded. Its unit tests passed because they call the plugin directly and jiti is never in the picture. Shipping it would have meant a documented integration that fails in every real project, which for an accessibility check is worse than having none — the same reasoning that already keeps a Next.js plugin out. So the same answer: `docusaurus build && eaa-kit audit`, which needs no directory argument because the project is recognised and its output is known to be `build/`. Both halves of that were run against the CLI, not assumed: it reported "Found a build in build/" and mapped `docs/intro.html` back to `docs/intro.md`. Detection and route mapping are untouched; only the build-time hook is gone. That leaves Vite as the one integration never driven by its real host, so it is now. Four of its claims about Vite were checked rather than believed, and all four held: `configResolved` and `closeBundle` are called, `build.outDir` arrives relative to the root (so the plugin's `path.resolve` is load-bearing — a plugin using it as given would audit the working directory), `apply: 'build'` keeps it out of a dev server's resolved plugin list, and a throw in `closeBundle` rejects the build. The `enforce: 'post'` case is ordered so only `enforce` can save it: this plugin is declared first and a page-emitting plugin after it. Stripping `enforce` makes that build pass over an unaudited broken page, which is what the test exists to catch. Every shipped integration is now driven by a real build of its host: Astro, Vite, Eleventy, webpack, Nuxt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HKU933TcRaKinharQxrNht
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Everything needed before
v0.4.0is tagged. Found while checking release readiness after #19 merged.The CommonJS blocker
require('eaa-kit/webpack')— the exact linedocs/integrations.mdprints — failed withERR_PACKAGE_PATH_NOT_EXPORTED. Every subpath export named animportcondition and nothing else, so CommonJS resolution had no way in. That is most of these hosts: awebpack.config.jsis ordinarily CommonJS, and so is.eleventy.js.Each subpath now names a
requirecondition besideimport, pointing at the same file. Node'srequire(esm)loads it on every version inengines(^22.22.2 || ^24.15.0 || >=26.0.0), so nothing is compiled twice and the package stays ESM-only.The one thing that would break it again is a top-level
awaitanywhere in a graph an integration pulls in —require(esm)refuses those. Soscripts/test-packaged.mjsnow loads every entry both ways, and a future top-levelawaitfails there rather than in somebody's build.Every integration now driven by its real host
#19 shipped a Nuxt module that could never have worked: it read a field Nuxt never populates, and its hand-written stand-in agreed with the bug, so the suite was green over a module that would have thrown on every build. That is a gap in method, not a one-off, so the remaining assumptions were checked the same way.
webpack — correct as written. Probed against a real compiler. All three claims held:
afterEmitfires with every file on disk,compilation.errorsreports a failed build, andcompiler.watchModeseparates a one-shot run from a dev server.watchModeis sampled inside the watch callback, becauseclose()puts it back to false.Vite — correct, and one line is load-bearing. Four claims checked, four held.
build.outDirarrives relative to the root (zielordner, not an absolute path), so the plugin'spath.resolve(config.root, …)is doing real work — a plugin using the value as given would audit the working directory and find nothing.apply: 'build'is verified against Vite's own resolved plugin list forservevsbuildrather than by reading the object, and a throw incloseBundlerejects the build.The
enforce: 'post'case is ordered so onlyenforcecan save it: this plugin is declared first and a page-emitting plugin after it. Strippingenforcemakes that same build pass over an unaudited broken page, which is what the test exists to catch.Docusaurus — withdrawn. The hook is the cleanest of any builder here:
postBuildruns when the whole site is on disk and hands overoutDir. The plugin still cannot work, for a reason outside its own code. Docusaurus loads plugins through jiti, which intercepts dynamicimport(); axe-core then reaches jiti's module evaluator instead of Node's and is evaluated without the globals it expects, so the audit dies onCannot read properties of undefined (reading 'document')at the end of a build that otherwise succeeded. Its unit tests passed because they call the plugin directly, and jiti is never in the picture.Shipping it would have meant a documented integration that fails in every real project, which for an accessibility check is worse than having none — the same reasoning that already keeps a Next.js plugin out of this release. So the same answer, and it was run rather than assumed:
No directory argument needed: the project is recognised and its output is known to be
build/, and pages still map back to their Markdown. Detection and route mapping are untouched — only the build-time hook is gone.Also here
v0.3.0→v0.4.0, which the docs tell people to set to an exact release tag.0.4.0section rather than left under Unreleased, so tagging does not ship a release whose changelog says part of it is unreleased.Verification
lint,typecheck,smokeclean. 1031 tests pass, 13 skipped.test:packagedloads all five integration entries by bothimportandrequirefrom a realnpm packinstall.Per suite: astro 17, vite 19, eleventy 4, webpack 5, nuxt 5, adapters 17 — Astro, Vite, Eleventy, webpack and Nuxt are each driven by a real build of their host.
The one local test failure is this container's Playwright expecting Chromium build 1234 against the 1194 it ships; it is green on CI, which installs Chromium itself.
Not in this PR
Two carried-over cleanups, neither a release blocker: running the real-build suites on one matrix job instead of four (~3 min/push), and folding the four separate
detectFramework+readPackageJsoncall sites into one (~3 ms, tidiness).🤖 Generated with Claude Code
https://claude.ai/code/session_01HKU933TcRaKinharQxrNht