Skip to content

Instantly share code, notes, and snippets.

@eins78
Last active March 6, 2026 22:50
Show Gist options
  • Select an option

  • Save eins78/a0e826595b3a78ee8cd6ed0841f10364 to your computer and use it in GitHub Desktop.

Select an option

Save eins78/a0e826595b3a78ee8cd6ed0841f10364 to your computer and use it in GitHub Desktop.

Barrel Exports + Shortest Valid Import Codemod

2026-03-06 by Showboat

What changed

PR #846 (CDSTLZ-193-esm) migrates webbloqs to native ESM with nodenext module resolution. Consumer repo audits revealed that @webbloqs/react has 9 flat files at src/ root (i18n, models, validation, etc.) imported 518+ times across ewz repos — but with no explicit barrel exports. Under strict ESM, these require .js extensions.

Two complementary fixes:

  1. Barrel exports generator (scripts/generate-barrel-exports.mjs) now auto-detects flat .ts files at each package's src/ root and generates explicit publishConfig.exports entries. This makes extensionless imports valid under strict ESM.

  2. Codemod (packages/codemods/transforms/esm-migration/index.ts) now reads the package's exports map and skips adding .js when an explicit barrel entry exists — producing the shortest valid import for each specifier.

Barrel export counts

Package Barrel dirs Flat files Total exports
@webbloqs/elements 57 0 57
@webbloqs/react 33 9 42
@webbloqs/css-runtime 4 1 5

Flat files in @webbloqs/react

create-component, global, i18n, media, models, option, properties, tracking, validation

Verification

Codemod unit tests (18 tests)

pnpm --filter @webbloqs/codemods test 2>&1 | grep -E "(PASS|FAIL|Tests:|Test Suites:)"
PASS __tests__/esm-migration.test.ts
Test Suites: 1 passed, 1 total
Tests:       18 passed, 18 total

ESM smoke test

pnpm run test:esm 2>&1 | grep -E "^(---|  |===)"
--- Step 1: Building packages ---
--- Step 2: Packing tarballs ---
--- Step 3: Creating consumer project ---
--- Step 4: Testing imports via esbuild (bundler) ---
  esbuild bundle: OK
--- Step 4b: Testing imports via Webpack 5 (fullySpecified) ---
  Building with Webpack 5...
  Webpack 5 build: OK
--- Step 4c: Testing consumer-specific import patterns ---
  package.json metadata reads: OK
--- Step 5: Testing TypeScript type resolution ---
  TypeScript types: OK
--- Step 6: Verifying package metadata ---
--- Step 6b: Verifying .js extensions in compiled imports ---
  All relative imports have .js extensions: OK
=== ESM Smoke Test PASSED ===

Consumer repo integration tests

All 4 consumer repos tested with updated tarballs from /tmp/webbloqs-esm-tarballs/. The codemod now produces the shortest valid import — flat file imports with barrel exports are left extensionless, only deep subpath imports get .js added.

Repo Files changed Build Previous run
mchweb 5 PASS was 55
cpq-cds 3 PASS (webpack) was 119+58
ewz-webportal-components 14 n/a (codemod only) was 107
ewz-kus-portal 7 n/a (codemod only) was 60
Total 29 was 399

~93% reduction in codemod-modified files. The remaining 29 files are all deep subpath imports (e.g., @webbloqs/elements/lib/icon/spritemap@webbloqs/elements/lib/icon/spritemap.js) that genuinely need .js extensions.

Key validation points

  • mchweb: Webpack client + server builds pass with ESM tarballs
  • cpq-cds: Webpack build passes (pnpm run build exit code 0)
  • ewz repos: Codemod runs without errors, all transforms correct
  • Zero errors across all consumer repos

CI verification

Full CI (pnpm run ci) passed: 2189+ unit tests, 35 E2E tests, all builds green.

Commits

5c12057bd F!! Add flat file barrel exports to publishConfig.exports
fb7001d03 F!! Teach codemod to prefer shortest valid import via exports map
3620b3dd3 E: Expand ESM smoke test with flat file barrel imports
bbc8c59c4 B: Fix WbComponentProps type reference in ESM smoke test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment