Skip to content

PR: ESM Migration, Vite 8 Upgrade, and Dependency Overhaul#1649

Open
onemen wants to merge 29 commits intoraineorshine:mainfrom
onemen:pr/esm-v21.0.0
Open

PR: ESM Migration, Vite 8 Upgrade, and Dependency Overhaul#1649
onemen wants to merge 29 commits intoraineorshine:mainfrom
onemen:pr/esm-v21.0.0

Conversation

@onemen
Copy link
Copy Markdown
Contributor

@onemen onemen commented Apr 5, 2026

Description

This PR transitions the project to a native ESM architecture while maintaining dual-build support (ESM/CJS) via Vite. It includes a major overhaul of the development toolchain, upgrading core dependencies to their 2026 standards, and significantly modernizing the internal logic.

Key Changes

  • Module System & Interop:
    • Converted the project to Pure ESM.
    • Replaced all dynamic imports with static ESM imports.
    • Configured Vite to build exports for both CLI and index in ESM and CJS formats.
    • Testing: Updated Mocha to use tsx for module loading (e.g., via --import tsx), ensuring seamless TypeScript support in an ESM context.
  • Major Upgrades:
    • Vite v8: Transitioned to the new Rust-based Rolldown bundler (10-30x faster builds).
    • TypeScript v6.0: Adopted the latest type-system features and performance improvements.
  • Tooling & CI/CD:
    • Switched to ts-json-schema-generator and implemented in-process Prettier formatting.
    • Moved build options directly into vite build and replaced vite-node with tsx.
    • Replaced strip-ansi with the Node.js built-in node:util/stripVTControlCharacters.
    • Enhanced quality gates: Added typecheck to pre-push hooks and the linting action.

⚠️ Breaking Changes

This is a major breaking change and requires a major version bump:

  • Node.js & npm Requirements:
    • Node.js: Now requires ^20.19.0 || ^22.12.0 || >=24.0.0. This is strictly required by Vite 8 for native require(esm) support and the Rolldown engine.
    • npm: Minimum version increased to >=10.0.0.
  • Pure ESM Dependencies: Several key dependencies have been updated to their latest Pure ESM versions, dropping support for older CJS environments:
    Package Old Version New Version
    camelcase ^6.3.0 ^9.0.0
    chai ^4.3.10 ^6.2.2
    chai-as-promised ^7.1.2 ^8.0.2
    find-up 5.0.0 8.0.0
    p-map ^4.0.0 ^7.0.4
    untildify ^4.0.0 ^6.0.0

Note on Mocha + tsx

Since the project is now ESM, we are using tsx to handle the TypeScript transformation during test execution. If you are running tests manually, ensure you are using the new command structure:
mocha --node-option import=tsx 'test/**/*.test.ts' (or your defined script in package.json).

onemen added 19 commits April 1, 2026 21:09
 - update vite config
 - use lodash-es instead of lodash
 - use memoize instead of old fast-memoize
ES Modules cannot be stubbed
To allow stubbing of npm functions in tests, we export the functions that
need to be stubbed as properties of an object (npmApi, pnpmApi, yarnApi) that can be
imported and stubbed in tests without affecting the rest of the module. (+1 squashed commits)

use tsx instead of ts-node with mocha
- Update major devDependencies to latest.
- Remove `legacy-peer-deps=true` to ensure strict, modern resolution.
- Implement surgical `overrides` to resolve peer dependency conflicts
  across the ESLint, Microsoft, and Verdaccio toolchains.
- Fix hoisting issue where `ajv/dist/core` was missing in nested
  node_modules under Node 25.
- Remove legacy __dirname in favor of getDirname(import.meta.url).
- Enable Mocha --exit to ensure clean termination on Node 25.
- Clean up listener guards and diagnostic hooks.
- Successfully verified 530+ tests across modern Node environments.
update vite config
remove unused nodeExternals, we see ssr.noExternal=true so we don't want to exclude node modules from the bundle
update export
use tsx instead of vite-node
…ation warning: `url.parse()` in node 24"

The issue was fixed in parse-github-url v1.0.4

This reverts commit 02e99e4.
@onemen onemen marked this pull request as draft April 5, 2026 08:44
onemen added 4 commits April 5, 2026 15:50
- Replace custom 'test/bun-install.sh' with 'oven-sh/setup-bun@v2' action.
- Add 'check-environment' before-hook to provide helpful install links.
- Fix TypeScript 'Property does not exist' errors via namespace imports.
- Resolve ESLint 'Parsing error' in VS Code using tsconfigRootDir.
- Update test logic to use node:child_process for better cross-platform compatibility.
    Update resolveConfig to use a file path instead of a directory to correctly load .prettierrc.json in ESM.

    Re-generate src/types/RunOptions.json with correct project formatting.

    Fixes pre-push hook failures caused by formatting mismatches.
Update mocha configuration to ignore test/bun/* during unit tests. This prevents CI failures in environments where Bun is not yet installed.
    Build: Update Vite config to use explicit output arrays for es and cjs formats.

    Build: Force .cjs extensions for CommonJS chunks to prevent Node.js from parsing them as ESM in "type: module" projects.

    E2E: Fix TypeError in ESM E2E tests by aligning namespace imports with the new build output.

    E2E: Add Windows fallback for lsof in test/e2e.sh using netstat and taskkill to allow local registry cleanup on Windows 11.
@onemen onemen marked this pull request as ready for review April 5, 2026 15:52
@onemen
Copy link
Copy Markdown
Contributor Author

onemen commented Apr 5, 2026

@raineorshine

let me know if there are any documentation that need update

- Update CONTRIBUTING.md with source map documentation
- Add Development section with Node.js requirements and test instructions
- Update Executable Stack Trace section to reflect generated source maps
- Add v21.0.0 entry to CHANGELOG.md documenting breaking changes
- Add Requirements section to README.md with Node.js and npm version constraints
@onemen
Copy link
Copy Markdown
Contributor Author

onemen commented Apr 5, 2026

@raineorshine

check the updates in ab34e63

Copy link
Copy Markdown
Owner

@raineorshine raineorshine left a comment

Choose a reason for hiding this comment

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

Thanks so much!

Comment on lines +538 to +546
{
/**
* Because this function depends on both the first object AND the options object,
* we must provide a cacheKey. Modern memoize provides both args in an array.
*/
cacheKey: ([configs, options]) => {
return JSON.stringify([configs, options.packageFile, options.cwd, options.registry, options.timeout])
},
},
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Explicit cache keys are going to be fragile and hard to maintain. If the function changes to use additional options in the future, there is no compile-time check to ensure these cache keys stay in sync, resulting in hard-to-catch caching bugs.

Instead, we should use a default serializer like fast-memoize did. Perhaps JSON.stringify would suffice?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You also use JSON.stringify in fetchUpgradedPackumentMemo
do you want to modify both

by Perhaps JSON.stringify would suffice did you mean JSON.stringify([configs, options])

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Just cacheKey: JSON.stringify I believe. You can use this same pattern in all the memoize calls to preserve the existing behavior and avoid explicitly listing the inputs.

@onemen onemen mentioned this pull request Apr 9, 2026
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.

2 participants