Skip to content

Modernize monorepo: ESM, Node 24, npm workspaces#397

Open
veged wants to merge 12 commits intomasterfrom
claude/update-dependencies-plan-ifYsx
Open

Modernize monorepo: ESM, Node 24, npm workspaces#397
veged wants to merge 12 commits intomasterfrom
claude/update-dependencies-plan-ifYsx

Conversation

@veged
Copy link
Member

@veged veged commented Feb 25, 2026

Summary

  • CJS → ESM: Migrated ~300+ files across all 22 packages to native ES modules
  • Node 24 + npm workspaces: Replaced Lerna with npm workspaces, set engines: ">=24", type: "module"
  • ~35 dependencies replaced with native Node.js APIs (only 3 production deps remain: cosmiconfig, fast-xml-parser, change-case)
  • Test infrastructure updated: mocha 11, chai 6, sinon 21, esmock (replaces proxyquire), c8 (replaces nyc)
  • ESLint 10 flat config (replaces ESLint 4 + tslint)
  • GitHub Actions CI (replaces Travis CI + AppVeyor)

Key dependency replacements

Removed Replacement
pinkie-promise, es6-promisify Native Promise / node:fs/promises
graceful-fs, mz/fs node:fs/promises
lodash.* (8 packages) Native APIs (structuredClone, isDeepStrictEqual, etc.)
glob, is-glob node:fs globSync
debug node:util debuglog
depd process.emitWarning
betterc cosmiconfig
stringify-object node:util inspect
proxyquire esmock
nyc c8

Test plan

  • All 1153 tests passing, 0 failures
  • 0 ESLint errors
  • Verify CI passes on GitHub Actions

🤖 Generated with Claude Code

claude and others added 12 commits February 23, 2026 17:21
Analyze all 22 packages in the monorepo, compare current vs latest
versions of all dependencies, and document a phased update strategy:
- Phase 0: Migrate from Lerna to npm workspaces, Travis/AppVeyor to GH Actions
- Phase 1-2: Update test/lint tooling (mocha, eslint, replace tslint)
- Phase 3: Update prod deps, replace 16 packages with native Node.js 18+ APIs
- Phase 4: Update sub-package dev deps
- Phase 5: Optional CJS→ESM migration

https://claude.ai/code/session_011Gd38T7faQEEqyRNjyU6ha
Add CRITICAL INSTRUCTION marker and bilingual reinforcement to ensure
the model consistently responds in Russian from the start of every session.

https://claude.ai/code/session_011Gd38T7faQEEqyRNjyU6ha
User prefers to keep project CLAUDE.md minimal and handle language
settings via global config/hooks instead.

https://claude.ai/code/session_011Gd38T7faQEEqyRNjyU6ha
…deps

- Lerna → npm workspaces, Travis/Appveyor → GitHub Actions CI
- CJS → ESM: all 300+ files converted (import/export, node: prefix, .js extensions)
- Replace ~35 dependencies with native Node.js APIs:
  pinkie-promise, es6-promisify, graceful-fs, mz/fs, es6-error, async-each,
  hash-set, ho-iter, depd, debug, lodash.*, glob, is-glob, betterc→cosmiconfig,
  node-eval→node:vm, stringify-object→node:util, json5→inline,
  xamel→fast-xml-parser, camel-case+pascal-case→change-case
- Dev stack: mocha 11, chai 6, sinon 21, esmock (replaces proxyquire),
  c8 (replaces nyc), ESLint 10 flat config (replaces eslint 4 + tslint)
- TypeScript 5.9, .d.ts files updated to direct exports
- Only 3 production deps remain: cosmiconfig, fast-xml-parser, change-case

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix react.js preset: restore correct base (origin-react) and pattern
- Add Symbol.for('nodejs.util.inspect.custom') to BemCell and BemFile
- Fix merge.js: skip undefined values to match lodash.mergeWith behavior
- Fix save.test.js: writeFile stub must return Promise (resolves())
- Fix walkers.test.js: include sdk stub in mock default export
- Fix config library tests: use .bemrc.json mock instead of betterc injection
- Add naming.presets exports field for ESM subpath imports
- Fix workspace version refs for @bem/sdk.naming.presets
- Remove invalid mocha imports (describe/it are globals)
- Fix chai 6 imports (no default export)
- Add chai-subset dev dependency

All 1153 tests passing, 0 failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace obj.hasOwnProperty() with Object.hasOwn() (10 files)
- Remove useless variable assignments (7 files)
- Fix unused variables: prefix with _ or remove empty catch params
- Remove unnecessary try/catch wrapper in keyset
- Attach cause to re-thrown errors in keyset
- Fix async promise executor in deps/gather.js
- Replace xit() with it.skip() in bemjson-to-jsx test
- Add structuredClone and xit to ESLint globals

0 errors, 1153 tests passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Old @types/node@8.x is blocked on npm registry (403 Forbidden).
Removed per-package devDependencies (covered by root), updated root
to match Node 24 target.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ueue

- Remove @types/node ^8.0 from packages (blocked on npm registry)
- Update root @types/node to ^24.0.0 to match Node target
- Update c8 to ^11.0.0
- Override yocto-queue to ^1.2.0 (0.1.0 blocked on npm)
- Regenerate package-lock.json with clean dependency tree

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Overriding yocto-queue directly broke p-limit@3's API (Queue is not
a constructor). Instead, override p-limit to ^4.0.0 which natively
uses yocto-queue ^1.0.0, avoiding the blocked 0.1.0 version.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GitHub Actions blocks old transitive deps with known CVEs (403 on
emoji-regex@8, yocto-queue@0.1.0, etc). These come from deep chains
in mocha/c8 that can't be cleanly overridden. Using npm install lets
npm resolve fresh versions. Also removed p-limit override.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use escaped double quotes for mocha glob in package.json so
  PowerShell passes the pattern to mocha without mangling it
- Delete .eslintignore (ESLint 10 uses ignores in eslint.config.js)
- Remove all 45 unused eslint-disable directives via --fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

3 participants