diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e6aaa6..4c70baf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. +## [1.5.2] - 2026-07-10 + +### Changed + +- **Switch from `transformWithEsbuild` to `transformWithOxc`** — Zero-coverage generation now uses Vite's OXC-based transform (bundled inside Vite via Rolldown) instead of esbuild. OXC is called with `jsx: { runtime: 'automatic' }` to force JSX transformation regardless of the project's `tsconfig.json` (Next.js projects typically set `"jsx": "preserve"` which OXC respects when auto-discovering tsconfig, producing far fewer statements). OXC does not constant-fold `process.env.NODE_ENV` without an explicit `define`, so all branches are preserved. This eliminates the need for `esbuild` as a direct dependency. + +### Fixed + +- **Remove `esbuild` direct dependency** — No longer needed now that `transformWithOxc` handles TypeScript/TSX compilation. `esbuild` was added in v1.5.1 as a workaround for Vite 8 removing its bundled esbuild; the switch to OXC resolves this cleanly with no extra dependency. + ## [1.5.1] - 2026-07-10 ### Fixed diff --git a/README.md b/README.md index ab71fbb..236bfae 100644 --- a/README.md +++ b/README.md @@ -82,8 +82,6 @@ npm install nextcov --save-dev npm install @playwright/test --save-dev ``` -> **Note:** `esbuild` is included as a direct dependency of nextcov (required since Vite 8 no longer bundles it). It will be installed automatically — no manual installation needed. - ## Quick Setup with `nextcov init` The fastest way to get started is with the `init` command: diff --git a/package-lock.json b/package-lock.json index bad39a8..1590d57 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nextcov", - "version": "1.5.1", + "version": "1.5.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nextcov", - "version": "1.5.1", + "version": "1.5.2", "license": "MIT", "dependencies": { "@babel/parser": "^7.24.0", @@ -17,7 +17,6 @@ "ast-v8-to-istanbul": "^1.0.4", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", - "esbuild": ">=0.21.0", "glob": "^11.1.0", "istanbul-lib-coverage": "^3.2.0", "istanbul-lib-report": "^3.0.1", @@ -2739,6 +2738,7 @@ "version": "0.27.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "devOptional": true, "hasInstallScript": true, "license": "MIT", "bin": { diff --git a/package.json b/package.json index dc9f5ed..5e75ebb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nextcov", - "version": "1.5.1", + "version": "1.5.2", "description": "Collect test coverage for Playwright E2E tests in Next.js applications", "author": "Steve Zhang", "license": "MIT", @@ -63,7 +63,6 @@ "ast-v8-to-istanbul": "^1.0.4", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", - "esbuild": ">=0.21.0", "glob": "^11.1.0", "istanbul-lib-coverage": "^3.2.0", "istanbul-lib-report": "^3.0.1", diff --git a/src/converter/index.ts b/src/converter/index.ts index 699e92a..b922c6b 100644 --- a/src/converter/index.ts +++ b/src/converter/index.ts @@ -7,7 +7,7 @@ import { existsSync } from 'node:fs' import { resolve, sep } from 'node:path' -import { parseAstAsync, transformWithEsbuild } from 'vite' +import { parseAstAsync, transformWithOxc } from 'vite' import _astV8ToIstanbul from 'ast-v8-to-istanbul' import libCoverage from 'istanbul-lib-coverage' import libSourceMaps from 'istanbul-lib-source-maps' @@ -955,14 +955,14 @@ export class CoverageConverter { /** * Create empty coverage entry for an uncovered file. * - * Uses the same esbuild pipeline as Vitest: transformWithEsbuild compiles - * TypeScript/TSX → JavaScript with a source map, then parseAstAsync parses - * the compiled JS, and astV8ToIstanbul maps positions back to the original - * source via the source map. + * Uses Vite's OXC transform: transformWithOxc compiles TypeScript/TSX → + * JavaScript with a source map, then parseAstAsync parses the compiled JS, + * and astV8ToIstanbul maps positions back to the original source via the + * source map. * - * Because the positions come from esbuild (identical to unit/component - * coverage), a subsequent `nextcov merge` rebase always finds exact - * line:col matches — no fallback, no misattribution. + * Because the positions come from OXC (matching Vitest's pipeline), + * a subsequent `nextcov merge` rebase always finds exact line:col matches — + * no fallback, no misattribution. */ private async createEmptyCoverage( filePath: string, @@ -971,18 +971,19 @@ export class CoverageConverter { try { const fileUrl = toFileUrl(filePath, this.projectRoot) - // Transform TypeScript/TSX → JS using esbuild (same as Vitest's pipeline). + // Transform TypeScript/TSX → JS using OXC (bundled in Vite via Rolldown). // sourcemap:true gives us the position mapping back to the original source. // - // IMPORTANT: Use platform:'neutral' so esbuild does NOT constant-fold - // process.env.NODE_ENV branches. With the default platform ('browser'), - // esbuild sees NODE_ENV='production' in the env and eliminates the - // 'else' arm of `NODE_ENV === 'production' ? A : B`, producing fewer - // branches in the zero-coverage map than Vitest (which uses platform:'browser' - // but runs with NODE_ENV='test', so no constant-folding occurs there). - const { code: compiledCode, map } = await transformWithEsbuild(code, filePath, { + // We explicitly set jsx.runtime:'automatic' to force JSX transformation + // regardless of the project's tsconfig.json. Next.js projects typically + // have "jsx":"preserve" in tsconfig, which OXC respects when auto-discovering + // it — leaving JSX untransformed and producing far fewer statements than + // Vitest's pipeline (which overrides the tsconfig via its own OXC config). + // OXC does not constant-fold process.env.NODE_ENV without an explicit + // define, so all branches are preserved — matching Vitest's behavior. + const { code: compiledCode, map } = await transformWithOxc(code, filePath, { sourcemap: true, - platform: 'neutral', + jsx: { runtime: 'automatic' }, }) // Parse the compiled JS with Vite's fast Rollup-based parser