Skip to content

v11: release major (Node 22 baseline, lockfile repair) - #2903

Merged
srod merged 161 commits into
mainfrom
develop
Sep 2, 2026
Merged

v11: release major (Node 22 baseline, lockfile repair)#2903
srod merged 161 commits into
mainfrom
develop

Conversation

@srod

@srod srod commented Sep 2, 2026

Copy link
Copy Markdown
Owner

v11 release: merge develop into main

149 commits. Merging this triggers the Changesets action on main, which opens a "Version Packages" PR bumping all 22 published packages 10.5.0 → 11.0.0. Publishing to npm happens when that PR is merged — not this one.

Release-readiness fixes included

Two blockers were found while validating and are fixed in this branch:

1. Corrupt lockfile broke CI (27074d53)

The Astro v7 security bump (#2880) wrote a bun.lock referencing @napi-rs/wasm-runtime as a prod dependency of @astrojs/compiler-binding-wasm32-wasi without emitting the corresponding package entry:

error: Failed to resolve prod dependency '@napi-rs/wasm-runtime'
InvalidLockfile: failed to parse lockfile: 'bun.lock'
error: lockfile had changes, but lockfile is frozen

bun install --frozen-lockfile failed, so every job on develop was red. Regenerating repaired the entry and deduped a stale nested @astrojs/cloudflare/astro tree (net -428 lines, all duplicate transitive deps — no top-level dependency lost).

2. Untested EOL Node baseline (3f77cc81) — breaking

Node 20 was dropped from the CI matrix in 8360cab so Astro v6 docs could build, but all 22 packages still declared engines.node >=20.0.0. v11 would have shipped a compatibility promise no CI run verified, for a runtime that hit EOL on 2026-04-30.

Baseline raised to >=22.0.0 to match what is actually tested (22.x, 24.x): engines bumped across root + 22 packages (packages/sharp was >=20.3.0), documented in the migration guide and getting-started, setup-node examples in the action docs retargeted to 22, and the break recorded in the changeset.

3. node-minify doctor shipped undocumented (e5aadfeb, 5de85b42)

The flagship v11 CLI command was named once in passing in the migration guide, with no usage, sample output or exit-code reference anywhere in the CLI docs or READMEs. Added a Doctor Command section to the CLI docs (usage, real captured output, exit codes so it can gate CI), a short section to the CLI package README, and Requirements (Node 22, ESM-only) plus a v11 upgrade link to the root README, which stated neither.

Sample output is copied verbatim from real doctor runs. The first draft was both inaccurate (doctor prints Use terser instead., not Use @node-minify/terser instead.) and tripped the removed-compressor CI guard, which treats scoped @node-minify/<removed> names as real usage while migration docs use bare names.

4. doctor missed 3 of 5 breaking changes (168428b0)

The command only understood compressor removals. A project depending on @node-minify/run, importing the removed CompressorReturnType/MinifyOptions aliases, and declaring engines.node >=18.0.0 printed nothing and exited 0 — reading as "v11-ready" when it would fail outright. Added three detectors: @node-minify/run in deps and imports (error), removed type aliases in TypeScript named imports (error, handles multi-line blocks and as renames), and engines.node ranges admitting Node below 22 (warning). Finding now carries a prebuilt message plus an error/warning severity instead of a compressor-registry status, so non-compressor diagnostics share one reporting and exit-code path. 9 new tests, each verified to fail without the implementation.

Verification

Full bun run ci locally plus CI green on all 4 matrix legs (ubuntu/windows × Node 22/24) at 27074d53:

Gate Result
bun install --frozen-lockfile pass
build (incl. docs) pass
lint / typecheck pass
test 1036 passed (70 files)
check-exports pass
removed-compressor guard pass

Also changed

Branch protection on main required test (*, 20.x) contexts the workflow can no longer produce — any PR would have blocked forever on missing checks. Required contexts now match the real matrix (22.x, 24.x).

Notes, not blocking

  • All open high-severity Dependabot alerts (postcss, sharp) are already resolved on develop — installed postcss@8.5.26 (patched 8.5.18), sharp@0.35.4 (patched 0.35.0). They are stale against main and this merge clears them.
  • @astrojs/cloudflare@13.7.0 peer-warns against astro@7.2.10 (wants ^6.3.0); adapter v14 supports Astro 7. Docs-only, private: true, not published, and the docs build passes. Worth a separate Renovate bump.
  • packages/action/action.yml still declares using: "node20". That is the GitHub Action runner runtime on the independent srod/node-minify@v1 line, not the npm packages; changing it forces an action major bump, so it is deliberately out of scope here.

srod and others added 30 commits March 8, 2026 19:14
Use a distinct temp output file for each benchmark warmup iteration so repeated warmups do not reuse the same path on Windows. Add a regression test for runWarmup and keep benchmark temp-file cleanup aligned with the generated warmup outputs.
Reformat the mocked compressor setup in utils tests to match the repository's formatter style without changing behavior.
* main:
  Version Packages
  Version Packages
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
chore(deps): update dependency tsdown to ^0.21.0
fix(deps): update dependency oxc-minify to ^0.117.0
fix(deps): update dependency oxc-minify to ^0.119.0
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
fix(deps): update dependency oxc-minify to ^0.120.0
chore(deps): update dependency bun to v1.3.11
fix(deps): update dependency oxc-minify to ^0.121.0
BREAKING CHANGE: 5 deprecated compressor packages deleted.
Removed all cross-references from cli config, core tests,
examples, compressor-resolver, and compressor-registry.
- Replace @node-minify/run + google-closure-compiler-java with google-closure-compiler@20240317.0.0
- Use Compiler class JS API: options object + stdin pipe instead of raw process spawning
- Add wrapMinificationError for consistent error handling
- Repurpose types.d.ts for google-closure-compiler module declaration
- Remove runCommandLine mocks from tests, add in-memory + invalid JS tests
- All 25 tests pass, typecheck clean
isRemovedCompressor() needs these entries for CLI fail-fast and doctor command.
renovate Bot and others added 7 commits August 27, 2026 22:47
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…e entry

The astro v7 security bump (#2880) wrote a bun.lock referencing
@napi-rs/wasm-runtime as a prod dependency of
@astrojs/compiler-binding-wasm32-wasi without emitting the corresponding
package entry, so `bun install --frozen-lockfile` failed to parse the
lockfile and CI on develop went red.

Regenerating also dedupes a stale nested @astrojs/cloudflare/astro tree.
Node 20 reached end-of-life on 2026-04-30 and was dropped from the CI
matrix in 8360cab so the Astro v6 docs could build, leaving every
package advertising engines.node >=20.0.0 that no CI run verified.

Align the declared baseline with what is actually tested (22.x, 24.x):
- Bump engines.node to >=22.0.0 across the root and all 22 published
  packages (packages/sharp was >=20.3.0).
- Document the requirement in the v11 migration guide and getting
  started, and retarget the setup-node examples in the action docs.
- Record the break in the v11 changeset.

BREAKING CHANGE: Node.js 22 or later is now required.
@changeset-bot

changeset-bot Bot commented Sep 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1d8484c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 25 packages
Name Type
@node-minify/minify-html Major
@node-minify/core Major
@node-minify/action Major
@node-minify/benchmark Major
@node-minify/cli Major
@node-minify/imagemin Major
@node-minify/sharp Major
@node-minify/examples Major
@node-minify/docs Major
@node-minify/clean-css Major
@node-minify/cssnano Major
@node-minify/csso Major
@node-minify/esbuild Major
@node-minify/google-closure-compiler Major
@node-minify/html-minifier Major
@node-minify/jsonminify Major
@node-minify/lightningcss Major
@node-minify/no-compress Major
@node-minify/oxc Major
@node-minify/svgo Major
@node-minify/swc Major
@node-minify/terser Major
@node-minify/types Major
@node-minify/uglify-js Major
@node-minify/utils Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 167 files, which is 17 over the limit of 150.

To get a review, reduce the PR to 150 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: de476554-79c5-45f5-9fb0-6dac9d97ae90

📥 Commits

Reviewing files that changed from the base of the PR and between 566a766 and 1d8484c.

⛔ Files ignored due to path filters (4)
  • .changeset/fix-minify-html-esm-interop.md is excluded by !.changeset/**
  • .changeset/v11-cleanup-major.md is excluded by !.changeset/**
  • bun.lock is excluded by !**/*.lock
  • packages/yui/src/binaries/yuicompressor-2.4.7.jar is excluded by !**/*.jar
📒 Files selected for processing (167)
  • .gitattributes
  • .github/actions/node-minify/README.md
  • .github/actions/node-minify/action.yml
  • .github/actions/node-minify/minify.ts
  • .github/workflows/codeql.yml
  • .github/workflows/publish.yml
  • .github/workflows/release-action.yml
  • .github/workflows/test-action.yml
  • .github/workflows/test.yml
  • AGENTS.md
  • Readme.md
  • SKILL.md
  • action.yml
  • biome.json
  • docs/package.json
  • docs/plans/2026-03-14-v11-plan.md
  • docs/plans/2026-06-22-v12-backlog.md
  • docs/src/consts.ts
  • docs/src/content.config.ts
  • docs/src/content/docs/cli.md
  • docs/src/content/docs/compressors/babel-minify.md
  • docs/src/content/docs/compressors/clean-css.md
  • docs/src/content/docs/compressors/crass.md
  • docs/src/content/docs/compressors/cssnano.md
  • docs/src/content/docs/compressors/csso.md
  • docs/src/content/docs/compressors/esbuild.md
  • docs/src/content/docs/compressors/gcc.md
  • docs/src/content/docs/compressors/html-minifier.md
  • docs/src/content/docs/compressors/imagemin.md
  • docs/src/content/docs/compressors/jsonminify.md
  • docs/src/content/docs/compressors/lightningcss.md
  • docs/src/content/docs/compressors/minify-html.md
  • docs/src/content/docs/compressors/no-compress.md
  • docs/src/content/docs/compressors/oxc.md
  • docs/src/content/docs/compressors/sharp.md
  • docs/src/content/docs/compressors/sqwish.md
  • docs/src/content/docs/compressors/svgo.md
  • docs/src/content/docs/compressors/swc.md
  • docs/src/content/docs/compressors/terser.md
  • docs/src/content/docs/compressors/uglify-es.md
  • docs/src/content/docs/compressors/uglify-js.md
  • docs/src/content/docs/compressors/yui.md
  • docs/src/content/docs/getting-started.md
  • docs/src/content/docs/github-action.md
  • docs/src/content/docs/guides/v11-migration.md
  • docs/src/content/docs/introduction.md
  • docs/src/content/docs/options.md
  • docs/src/pages/[...slug].astro
  • examples/package.json
  • examples/server.js
  • package.json
  • packages/action/AGENTS.md
  • packages/action/README.md
  • packages/action/__tests__/annotations.test.ts
  • packages/action/__tests__/benchmark.test.ts
  • packages/action/__tests__/comment.test.ts
  • packages/action/__tests__/index.test.ts
  • packages/action/__tests__/inputs.test.ts
  • packages/action/__tests__/reporters/summary.test.ts
  • packages/action/__tests__/runAutoMode.test.ts
  • packages/action/action.yml
  • packages/action/package.json
  • packages/action/src/inputs.ts
  • packages/action/src/types.ts
  • packages/babel-minify/CHANGELOG.md
  • packages/babel-minify/LICENSE
  • packages/babel-minify/README.md
  • packages/babel-minify/__tests__/babel-minify.test.ts
  • packages/babel-minify/package.json
  • packages/babel-minify/src/index.ts
  • packages/babel-minify/src/types.d.ts
  • packages/babel-minify/tsconfig.json
  • packages/babel-minify/vitest.config.ts
  • packages/benchmark/__tests__/runner-warmup.test.ts
  • packages/benchmark/package.json
  • packages/benchmark/src/runner.ts
  • packages/clean-css/package.json
  • packages/cli/README.md
  • packages/cli/__tests__/cli.test.ts
  • packages/cli/__tests__/doctor.test.ts
  • packages/cli/__tests__/spinner.test.ts
  • packages/cli/package.json
  • packages/cli/src/bin/cli.ts
  • packages/cli/src/config.ts
  • packages/cli/src/doctor.ts
  • packages/cli/src/index.ts
  • packages/core/__tests__/compress-paths.test.ts
  • packages/core/__tests__/core.test.ts
  • packages/core/__tests__/setup.test.ts
  • packages/core/package.json
  • packages/crass/CHANGELOG.md
  • packages/crass/LICENSE
  • packages/crass/README.md
  • packages/crass/__tests__/crass-error.test.ts
  • packages/crass/__tests__/crass.test.ts
  • packages/crass/package.json
  • packages/crass/src/index.ts
  • packages/crass/src/types.d.ts
  • packages/crass/tsconfig.json
  • packages/crass/vitest.config.ts
  • packages/cssnano/package.json
  • packages/csso/package.json
  • packages/esbuild/package.json
  • packages/google-closure-compiler/__tests__/google-closure-compiler.test.ts
  • packages/google-closure-compiler/__tests__/runner-edge-cases.test.ts
  • packages/google-closure-compiler/package.json
  • packages/google-closure-compiler/src/index.ts
  • packages/google-closure-compiler/src/types.d.ts
  • packages/html-minifier/package.json
  • packages/imagemin/package.json
  • packages/jsonminify/package.json
  • packages/lightningcss/package.json
  • packages/minify-html/__tests__/minify-html-error.test.ts
  • packages/minify-html/package.json
  • packages/minify-html/src/index.ts
  • packages/no-compress/package.json
  • packages/oxc/package.json
  • packages/run/CHANGELOG.md
  • packages/run/LICENSE
  • packages/run/README.md
  • packages/run/__tests__/run.test.ts
  • packages/run/package.json
  • packages/run/src/index.ts
  • packages/run/tsconfig.json
  • packages/run/vitest.config.ts
  • packages/sharp/package.json
  • packages/sqwish/CHANGELOG.md
  • packages/sqwish/LICENSE
  • packages/sqwish/README.md
  • packages/sqwish/__tests__/sqwish-error.test.ts
  • packages/sqwish/__tests__/sqwish.test.ts
  • packages/sqwish/package.json
  • packages/sqwish/src/index.ts
  • packages/sqwish/src/types.d.ts
  • packages/sqwish/tsconfig.json
  • packages/sqwish/vitest.config.ts
  • packages/svgo/package.json
  • packages/swc/package.json
  • packages/terser/package.json
  • packages/types/package.json
  • packages/types/src/types.d.ts
  • packages/uglify-es/CHANGELOG.md
  • packages/uglify-es/LICENSE
  • packages/uglify-es/README.md
  • packages/uglify-es/__tests__/uglify-es.test.ts
  • packages/uglify-es/package.json
  • packages/uglify-es/src/index.ts
  • packages/uglify-es/tsconfig.json
  • packages/uglify-es/vitest.config.ts
  • packages/uglify-js/package.json
  • packages/utils/__tests__/compressor-registry.test.ts
  • packages/utils/__tests__/compressor-resolver.test.ts
  • packages/utils/__tests__/filesize-error-paths.test.ts
  • packages/utils/__tests__/utils.test.ts
  • packages/utils/package.json
  • packages/utils/src/compressor-registry.ts
  • packages/utils/src/compressor-resolver.ts
  • packages/utils/src/index.ts
  • packages/yui/CHANGELOG.md
  • packages/yui/LICENSE
  • packages/yui/README.md
  • packages/yui/__tests__/yui.test.ts
  • packages/yui/package.json
  • packages/yui/src/index.ts
  • packages/yui/tsconfig.json
  • packages/yui/vitest.config.ts
  • scripts/ci-guard-removed-compressors.sh

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

13 issues found across 163 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/utils/__tests__/filesize-error-paths.test.ts">

<violation number="1" location="packages/utils/__tests__/filesize-error-paths.test.ts:29">
P3: Each test run leaks a unique `nm-filesize-*` directory (with `f.js`) into the OS temp dir because the `mkdtempSync` directory is never removed. Add an `afterAll` cleanup that removes `dir` recursively so runs don't accumulate temp artifacts.</violation>
</file>

<file name="package.json">

<violation number="1" location="package.json:24">
P3: `unrun` is added to root devDependencies but is never referenced by any script, workflow, or config in the repo (the only match for "unrun" anywhere is the package.json entry itself). Either wire it into the build/CI scripts it was intended for, or drop it to avoid a dead dependency and the extra lockfile weight.</violation>
</file>

<file name="docs/src/content/docs/compressors/cssnano.md">

<violation number="1" location="docs/src/content/docs/compressors/cssnano.md:6">
P3: The new 'Status: Recommended' label on 8 compressor docs conflicts with Readme.md, which designates only terser and lightningcss as recommended (cssnano/esbuild/oxc/sharp/svgo/swc are listed without that label). Decide whether 'Recommended' means the top pick per category (matching the README) or the entire preferred set, and align both surfaces so the guidance isn't contradictory.</violation>
</file>

<file name="packages/benchmark/src/runner.ts">

<violation number="1" location="packages/benchmark/src/runner.ts:53">
P2: When a compressor returns multiple outputs, cleanup tracks only the base warmup path while core writes format-suffixed files, so warmups leave artifacts on disk. Track the resolved output paths for multi-output compressors before cleanup.</violation>
</file>

<file name="docs/package.json">

<violation number="1" location="docs/package.json:24">
P2: When this package installs with Astro 7, `@astrolib/analytics@0.6.1` has a peer range ending at Astro 5, so the docs project receives an incompatible peer dependency. Upgrade `@astrolib/analytics` to an Astro 7-compatible release or replace it with an explicitly compatible integration before adopting Astro 7.</violation>
</file>

<file name="docs/plans/2026-03-14-v11-plan.md">

<violation number="1" location="docs/plans/2026-03-14-v11-plan.md:31">
P3: The support-tier list only puts `jsonminify` under `Legacy`, but the shipped v11 registry `packages/utils/src/compressor-registry.ts` marks `no-compress` as `legacy` too (Legacy (2): jsonminify, no-compress), and `docs/plans/2026-06-22-v12-backlog.md` item 5 repeats the same pairing. This plan is merged as part of the v11 release, so its tier enumeration misleads readers about which compressors are legacy. Add `no-compress` to the Legacy tier.</violation>

<violation number="2" location="docs/plans/2026-03-14-v11-plan.md:71">
P3: The plan's `doctor` scope lists deprecated type-alias detection and Java-sensitive GCC/YUI guidance as v11 deliverables, but neither was shipped. `packages/cli/src/doctor.ts` only scans package.json, source imports, and workflow YAML for removed/legacy compressors (severity is `removed`/`legacy` only); `docs/plans/2026-06-22-v12-backlog.md` item 1 explicitly records that these two detections (plan lines 70-71) and the 'GCC runtime-guidance messaging' test were not implemented in v11 and deferred to v12. Merging this plan with the v11 release overstates what `node-minify doctor` does, so future readers will expect capabilities v11 does not have. Annotate these as deferred-to-v12 (or drop them) so the plan matches the shipped scope.</violation>
</file>

<file name=".github/actions/node-minify/action.yml">

<violation number="1" location=".github/actions/node-minify/action.yml:76">
P2: When a workflow passes `compressor: yui`, the install step still runs `bun add @node-minify/yui` (the yui entry remains in compressor-registry), but the yui Java setup and its deprecation warning were removed. yui requires Java, so remaining users get no explicit Java provisioning and no guidance, and fail only at minification time. Since yui is being dropped, fail fast instead: reject the `yui` input with a clear error in the alias mapping, or keep the Java setup and warning.</violation>
</file>

<file name="packages/google-closure-compiler/__tests__/google-closure-compiler.test.ts">

<violation number="1" location="packages/google-closure-compiler/__tests__/google-closure-compiler.test.ts:169">
P3: This unit test shells out to `bun run build` and depends on the `bun` executable being on PATH, so running the package's `vitest run` via npm (a Node-only environment) fails this file with ENOENT even though the compressor works. It also regenerates `dist/` in the working tree on every test run. Prefer importing the source under test (`../src/index.ts`, already imported for `applyOptions`) or gating the built-package smoke check behind a separate CI step, so a missing `bun` or a build failure can't fail the unit suite.</violation>
</file>

<file name="docs/plans/2026-06-22-v12-backlog.md">

<violation number="1" location="docs/plans/2026-06-22-v12-backlog.md:18">
P3: The claim that the compressor registry "already carries" the GCC runtime caveat via a `notes` field is inaccurate. `CompressorEntry` in `packages/utils/src/compressor-registry.ts` only has `name`, `status`, `packageName`, and optional `replacement`; there is no `notes` field and no Java/runtime-caveat text anywhere in the registry. A v12 implementer following this backlog would look for a field that does not exist and may assume the GCC guidance is already captured. Either add the `notes` field (with the GCC caveat) or reword this to say the note still needs to be added.</violation>
</file>

<file name="packages/cli/src/index.ts">

<violation number="1" location="packages/cli/src/index.ts:42">
P3: The fail-fast check runs before custom-compressor resolution, so it blocks any custom npm package whose name exactly matches a removed registry entry (e.g. a user's own package named 'crass' or 'yui') with a false 'removed in v11' error, even though the CLI documents custom npm compressor support. Gate the removed-compressor check to only fire when the entry actually corresponds to a built-in that can't resolve, or narrow the match so arbitrary custom packages aren't blocked.</violation>
</file>

<file name=".github/actions/node-minify/minify.ts">

<violation number="1" location=".github/actions/node-minify/minify.ts:112">
P3: yui still requires a type: @node-minify/yui@10.5.0 throws "You must specify a type: js or css" when `type` is absent, so removing yui from this guard does not relax a real requirement. It only moves the failure from the action's clear pre-flight error into a less specific "Minification failed" message thrown from inside the compressor. Keep yui in the requiresType check (and fix action.yml which claims type is required only for esbuild).</violation>
</file>

<file name="packages/action/__tests__/runAutoMode.test.ts">

<violation number="1" location="packages/action/__tests__/runAutoMode.test.ts:107">
P2: This test claims to verify outputDir normalization, but for outputDir "./" the ignore glob is "**/./**" whether or not the normalization code in src/index.ts runs, so the assertion passes even if the normalization regresses or is removed. Use outputDir "" as the input instead — the case the normalization fallback actually handles, where the un-normalized glob would be the invalid "**//**" — so the test provides real regression coverage for the behavior it names.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic


// Track the path before minifying so a mid-loop failure still lets the
// caller delete the partial file instead of orphaning it.
collected.push(warmupOutput);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When a compressor returns multiple outputs, cleanup tracks only the base warmup path while core writes format-suffixed files, so warmups leave artifacts on disk. Track the resolved output paths for multi-output compressors before cleanup.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/benchmark/src/runner.ts, line 53:

<comment>When a compressor returns multiple outputs, cleanup tracks only the base warmup path while core writes format-suffixed files, so warmups leave artifacts on disk. Track the resolved output paths for multi-output compressors before cleanup.</comment>

<file context>
@@ -32,23 +32,36 @@ import type {
+
+        // Track the path before minifying so a mid-loop failure still lets the
+        // caller delete the partial file instead of orphaning it.
+        collected.push(warmupOutput);
+
         await minify({
</file context>

Comment thread packages/cli/src/doctor.ts Outdated
Comment thread packages/cli/src/doctor.ts Outdated
Comment thread scripts/ci-guard-removed-compressors.sh Outdated
Comment thread docs/package.json
"@astrolib/analytics": "0.6.1",
"@types/node": "^22.19.15",
"astro": "^5.18.0",
"astro": "^7.1.0",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When this package installs with Astro 7, @astrolib/analytics@0.6.1 has a peer range ending at Astro 5, so the docs project receives an incompatible peer dependency. Upgrade @astrolib/analytics to an Astro 7-compatible release or replace it with an explicitly compatible integration before adopting Astro 7.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/package.json, line 24:

<comment>When this package installs with Astro 7, `@astrolib/analytics@0.6.1` has a peer range ending at Astro 5, so the docs project receives an incompatible peer dependency. Upgrade `@astrolib/analytics` to an Astro 7-compatible release or replace it with an explicitly compatible integration before adopting Astro 7.</comment>

<file context>
@@ -16,16 +16,16 @@
     "@astrolib/analytics": "0.6.1",
     "@types/node": "^22.19.15",
-    "astro": "^5.18.0",
+    "astro": "^7.1.0",
     "preact": "^10.28.4"
   },
</file context>

Comment thread docs/src/content/docs/options.md
Comment thread AGENTS.md
Comment thread package.json
"rimraf": "6.1.3",
"tsdown": "^0.22.0",
"typescript": "5.9.3",
"unrun": "^0.3.1",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: unrun is added to root devDependencies but is never referenced by any script, workflow, or config in the repo (the only match for "unrun" anywhere is the package.json entry itself). Either wire it into the build/CI scripts it was intended for, or drop it to avoid a dead dependency and the extra lockfile weight.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At package.json, line 24:

<comment>`unrun` is added to root devDependencies but is never referenced by any script, workflow, or config in the repo (the only match for "unrun" anywhere is the package.json entry itself). Either wire it into the build/CI scripts it was intended for, or drop it to avoid a dead dependency and the extra lockfile weight.</comment>

<file context>
@@ -12,30 +12,30 @@
+    "rimraf": "6.1.3",
+    "tsdown": "^0.22.0",
     "typescript": "5.9.3",
+    "unrun": "^0.3.1",
     "vite-tsconfig-paths": "^6.1.1",
     "vitest": "^4.0.18"
</file context>

description: "cssnano for node-minify"
---

**Status:** Recommended

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The new 'Status: Recommended' label on 8 compressor docs conflicts with Readme.md, which designates only terser and lightningcss as recommended (cssnano/esbuild/oxc/sharp/svgo/swc are listed without that label). Decide whether 'Recommended' means the top pick per category (matching the README) or the entire preferred set, and align both surfaces so the guidance isn't contradictory.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/src/content/docs/compressors/cssnano.md, line 6:

<comment>The new 'Status: Recommended' label on 8 compressor docs conflicts with Readme.md, which designates only terser and lightningcss as recommended (cssnano/esbuild/oxc/sharp/svgo/swc are listed without that label). Decide whether 'Recommended' means the top pick per category (matching the README) or the entire preferred set, and align both surfaces so the guidance isn't contradictory.</comment>

<file context>
@@ -3,6 +3,8 @@ title: "cssnano"
 description: "cssnano for node-minify"
 ---
 
+**Status:** Recommended
+
 `cssnano` can compress only CSS files.
</file context>

Comment thread .github/workflows/test.yml
The v11 `node-minify doctor` command shipped undocumented: it was
referenced only in passing in the migration guide, with no usage, output
or exit-code reference anywhere in the CLI docs or READMEs.

- Add a Doctor Command section to the CLI docs covering usage, sample
  output and exit codes (1 on removed compressors, 0 on legacy-only)
  so it can be used as a CI gate.
- Add a short Doctor section to the CLI package README.
- Add Requirements (Node 22, ESM-only) and a v11 upgrade link to the
  root README, which previously stated neither.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 2, 2026

Copy link
Copy Markdown

Deploying node-minify-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: ad0d150
Status: ✅  Deploy successful!
Preview URL: https://2237b0de.node-minify-docs.pages.dev
Branch Preview URL: https://develop.node-minify-docs.pages.dev

View logs

The doctor example in the CLI docs used a scoped @node-minify/babel-minify
name, which the removed-compressor CI guard treats as a real usage
reference (migration docs use bare names by convention), turning every
test job red.

Replace both lines with output captured verbatim from real doctor runs;
the removed-compressor line now uses the bare workflow-YAML form. The
previous sample was also inaccurate: doctor prints "Use terser instead.",
not "Use @node-minify/terser instead."

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 3 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/cli/README.md Outdated
Comment thread Readme.md Outdated
Comment thread docs/src/content/docs/cli.md Outdated
doctor covered only compressor removals, so it was silent on 3 of v11's
5 breaking changes. A project depending on @node-minify/run, importing
the removed type aliases and declaring engines.node >=18 produced no
output and exited 0, reading as "v11-ready" when it was not.

Add three detectors:
- @node-minify/run in dependencies and source imports (error)
- CompressorReturnType / MinifyOptions in TypeScript named imports,
  matched across multi-line blocks and resolving `as` renames (error)
- engines.node ranges admitting a release below 22 (warning)

Finding now carries a prebuilt message and an error/warning severity
rather than a compressor-registry status, so non-compressor diagnostics
share one reporting and exit-code path.

Exempt doctor.ts from the guard's scoped scan and cli.md from its docs
scan: as the removal detector and its documentation, both must name the
packages they report on. Verified the guard still fails on a real
violation elsewhere.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 6 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/cli/src/doctor.ts">

<violation number="1" location="packages/cli/src/doctor.ts:180">
P2: When `engines.node` uses an upper-bound or wildcard range, `checkNodeEngine` can report the project as clean even though the range allows Node below 22. Parse the range semantically, or conservatively warn for ranges that do not guarantee `>=22`.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

const nodeRange = (engines as Record<string, unknown>).node;
if (typeof nodeRange !== "string") return undefined;

const majors = [...nodeRange.matchAll(/(\d+)(?:\.\d+)*/g)]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When engines.node uses an upper-bound or wildcard range, checkNodeEngine can report the project as clean even though the range allows Node below 22. Parse the range semantically, or conservatively warn for ranges that do not guarantee >=22.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/doctor.ts, line 180:

<comment>When `engines.node` uses an upper-bound or wildcard range, `checkNodeEngine` can report the project as clean even though the range allows Node below 22. Parse the range semantically, or conservatively warn for ranges that do not guarantee `>=22`.</comment>

<file context>
@@ -78,13 +109,89 @@ function buildEntryMap(
+    const nodeRange = (engines as Record<string, unknown>).node;
+    if (typeof nodeRange !== "string") return undefined;
+
+    const majors = [...nodeRange.matchAll(/(\d+)(?:\.\d+)*/g)]
+        .map((match) => Number(match[1]))
+        .filter((major) => Number.isFinite(major));
</file context>

Comment thread packages/cli/src/doctor.ts Outdated
Comment thread packages/cli/src/doctor.ts Outdated
srod added 2 commits September 2, 2026 12:50
@minify-html/node is a CommonJS native addon, so Node's ESM loader
exposes its exports only via the default export. The compressor read
`minify` off the namespace object, which is always undefined there, so
the published package threw "minifyHtmlLib.minify is not a function" on
every input when used from real Node.

CI never caught it: the error test mocked @minify-html/node with a flat
{ minify } shape that does not match the real module, and Vitest's CJS
interop resolved the namespace differently than Node. All 15 tests
passed against a package that could not run.

Also fix the docs this audit surfaced:
- options.md was entirely CommonJS require() with a removed `callback`
  option, a removed `sync` option and a missing comma; rewritten as ESM
  and awaited, with every example executed against the built packages.
- Add the missing minify-html and no-compress compressor pages and wire
  them into the sidebar; minify-html is recommended tier yet had no page.
- List minify-html in the README HTML sections.
Codecov flagged doctor.ts line 154 (the newline counter in
lineNumberAt) as the only uncovered line in the patch: every existing
type-alias fixture put the import on line 1, where the loop body never
runs.

Add a fixture whose removed-alias import starts on line 4 and assert the
reported location. Verified the test fails when the newline counter is
removed.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 8 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="docs/src/content/docs/options.md">

<violation number="1" location="docs/src/content/docs/options.md:109">
P3: The new `buffer` section claims the option caps how much output a spawned compressor process may produce, but I found no code path that consumes `settings.buffer`: setup.ts only stores the default `1000 * 1024`, and core/utils never apply it. The example uses google-closure-compiler, whose implementation reads `settings.timeout` but not `settings.buffer`, so passing `buffer` there has no effect. Verify whether any compressor honors `buffer`; if not, reword the section (or drop the example) so the docs don't promise behavior the library doesn't implement.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

## Max Buffer Size (only for Java)
## Max Buffer Size

Some compressors spawn a child process. `buffer` caps how much output that process may produce before it is killed. The default is `1000 * 1024` bytes, which is enough for most files; raise it when minifying very large inputs.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The new buffer section claims the option caps how much output a spawned compressor process may produce, but I found no code path that consumes settings.buffer: setup.ts only stores the default 1000 * 1024, and core/utils never apply it. The example uses google-closure-compiler, whose implementation reads settings.timeout but not settings.buffer, so passing buffer there has no effect. Verify whether any compressor honors buffer; if not, reword the section (or drop the example) so the docs don't promise behavior the library doesn't implement.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/src/content/docs/options.md, line 109:

<comment>The new `buffer` section claims the option caps how much output a spawned compressor process may produce, but I found no code path that consumes `settings.buffer`: setup.ts only stores the default `1000 * 1024`, and core/utils never apply it. The example uses google-closure-compiler, whose implementation reads `settings.timeout` but not `settings.buffer`, so passing `buffer` there has no effect. Verify whether any compressor honors `buffer`; if not, reword the section (or drop the example) so the docs don't promise behavior the library doesn't implement.</comment>

<file context>
@@ -123,21 +104,34 @@ When `allowEmptyOutput: true`:
-## Max Buffer Size (only for Java)
+## Max Buffer Size
+
+Some compressors spawn a child process. `buffer` caps how much output that process may produce before it is killed. The default is `1000 * 1024` bytes, which is enough for most files; raise it when minifying very large inputs.
+
+```js
</file context>
Suggested change
Some compressors spawn a child process. `buffer` caps how much output that process may produce before it is killed. The default is `1000 * 1024` bytes, which is enough for most files; raise it when minifying very large inputs.
Some compressors spawn a child process. If minifying very large inputs, you may need to raise the `buffer` size (default `1000 * 1024` bytes); verify that the chosen compressor actually honors it.

srod added 2 commits September 2, 2026 13:50
Addresses cubic review findings on #2903, each reproduced first.

npx (P1): every documented `npx node-minify doctor` resolves the
unrelated unscoped node-minify@3.6.0, which ships its own node-minify
bin, so the v11 scan never ran. Use
`npx --package=@node-minify/cli -- node-minify doctor` in all five
files, including the pre-existing occurrence in the changeset.

Detection gaps (P2) — a project hitting all three exited 0:
- side-effect `import "@node-minify/crass"` was invisible; IMPORT_REGEX
  now covers the bare import form.
- `export type { MinifyOptions } from ...` was invisible;
  NAMED_IMPORT_REGEX now matches export declarations too.
- `{ compressor : "yui" }` was invisible; COMPRESSOR_REGEX now allows
  whitespace before the colon.

Verified each new test fails against the old regexes, and that valid
v11 code still produces no findings.
Two further cubic findings on #2903, both reproduced first.

A migration example written in a doc comment was matched as a real
import, so doctor failed with an ERROR on correct code — the worst
failure mode for a migration aid. Comments are now blanked before the
type-alias scan, replacing each comment character with a space so byte
offsets and reported line numbers are unchanged.

engines.node ranges naming no version at all ("*", "x") produced no
finding, because the major-version scan found nothing and returned
early. Such a range places no floor on the runtime, so it is now
reported rather than assumed safe.

Verified a real import following commented examples is still flagged,
with the correct line number.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 7 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/cli/src/doctor.ts
More cubic findings on #2903, each verified.

oxc-minify@0.148.0 requires `^20.19.0 || >=22.12.0`, but the package
declared `>=22.0.0`, so on Node 22.0-22.11 it installs and then refuses
to run. Since aligning the Node baseline is this release's point, set
@node-minify/oxc to >=22.12.0. Checked every other runtime dependency;
oxc is the only one with a floor above 22.0.0.

The Windows CI legs run the removed-compressor guard through Git Bash.
With no .gitattributes, Git for Windows checks out CRLF by default and
the script dies on `set -euo pipefail\r` — reproduced locally as
`set: pipefail: invalid option name`. Pin *.sh to LF.

Docs: github-action.md recommended setup-node@v4 while the migration
guide recommended v6 for the same Node 22 step; align on v6. AGENTS.md
still claimed Node >=20.0.0.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 7 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/cli/src/doctor.ts">

<violation number="1" location="packages/cli/src/doctor.ts:468">
P2: When a source file contains `//` or `/*` inside a string, template, or regex literal before a real type import, `stripComments` blanks the literal text as a comment and the doctor misses the removed alias. Use a syntax-aware comment stripper that ignores comment markers inside literals.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

// migration example in a doc comment is not reported as a real
// import; blanking preserves offsets so line numbers stay correct.
if (TYPE_SOURCE_EXTENSIONS.has(extname(relPath))) {
const code = stripComments(content);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When a source file contains // or /* inside a string, template, or regex literal before a real type import, stripComments blanks the literal text as a comment and the doctor misses the removed alias. Use a syntax-aware comment stripper that ignores comment markers inside literals.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/doctor.ts, line 468:

<comment>When a source file contains `//` or `/*` inside a string, template, or regex literal before a real type import, `stripComments` blanks the literal text as a comment and the doctor misses the removed alias. Use a syntax-aware comment stripper that ignores comment markers inside literals.</comment>

<file context>
@@ -435,9 +461,12 @@ async function scanSourceImports(cwd: string): Promise<Finding[]> {
+            // import; blanking preserves offsets so line numbers stay correct.
             if (TYPE_SOURCE_EXTENSIONS.has(extname(relPath))) {
-                for (const match of content.matchAll(NAMED_IMPORT_REGEX)) {
+                const code = stripComments(content);
+                for (const match of code.matchAll(NAMED_IMPORT_REGEX)) {
                     const specifiers = match[1];
</file context>

Comment thread docs/src/content/docs/cli.md Outdated
srod added 4 commits September 2, 2026 14:08
The regex-based stripper had both failure directions. `/*` and `*/`
appearing inside string literals formed a false comment spanning the
code between them, hiding a real import (verified: a file with
`const open = "/*"`, an import, then `const close = "*/"` reported
nothing). A migration example embedded in a template literal was
reported as a real import.

Replace it with a single-pass scanner that walks quoted strings without
altering them — an import specifier lives inside quotes and must still
match — and blanks comment and template-literal bodies, preserving byte
offsets so reported line numbers stay correct.

Also scope the CLI docs note: only the type-alias check ignores
comments, not every scanner.
The removed-compressor guard only scanned .ts/.js/.json/.md/.mdx/.yml/
.yaml, so an import of a removed package from .tsx, .jsx, .mjs, .cjs,
.mts, .cts or an .astro file passed CI silently — verified for each
extension. Add them to both the scoped and bare-name scans.

README compressor comments predated the v11 support tiers and
contradicted them: cssnano, esbuild, swc, oxc, sharp and svgo are
'recommended' in the registry but read as second-tier alternatives,
while html-minifier and jsonminify carried no tier at all. Label every
entry with its registry status.
The guard is a static grep over source, docs and action files with no OS
or Node-version dependence, so running it on all four legs produced four
identical results. Gate it to ubuntu/22.x, matching the existing
runner.os condition on the Codecov step.
Codecov flagged doctor.ts:200-201 (the backslash branch in
stripComments) as the only uncovered lines in the patch.

The branch is load-bearing, not defensive: removing it and rebuilding
makes doctor miss a real import entirely. Given
`const quoted = "he said \\" /*";`, the escaped quote ends the string
early, so the trailing /* opens a comment that swallows the import on
the next line — verified as exit 0 with no findings.

Add a fixture for that shape and assert the import is still reported.
Verified the test fails when the branch is removed.
@codecov

codecov Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.64%. Comparing base (566a766) to head (1d8484c).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2903      +/-   ##
==========================================
+ Coverage   95.25%   99.64%   +4.38%     
==========================================
  Files          73       69       -4     
  Lines        1770     1961     +191     
  Branches      552      599      +47     
==========================================
+ Hits         1686     1954     +268     
+ Misses         84        7      -77     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@srod
srod merged commit 68d19da into main Sep 2, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant