Skip to content

Commit dba2fb7

Browse files
authored
fix: add ESM support and update documentation (#25)
Add comprehensive ES Modules support with dual package configuration ## Changes ### ESM Support - Added dual package support (CommonJS + ES Modules) - Created tsconfig.esm.json for ES module compilation - Updated package.json with proper module and exports fields - Build outputs both CJS (build/cjs/) and ESM (build/esm/) - Added package.json marker in build/esm/ for ES module type - Fixed ESM imports with proper .js extensions - Fixed directory imports to resolve to /index.js ### Testing - Added 22 ESM integration tests - Tests validate static imports, runtime resolution, and functionality - CI/CD pipeline updated with ESM validation on Node.js 18, 20, 22 - All 518 unit tests passing, 95.08% coverage maintained ### Documentation - Updated SECURITY.md (v4.0.0+ support only) - Created test/ESM_TESTING.md guide - Created INTEGRATION_SUMMARY.md ### Code Quality - Fixed GitHub Advanced Security code scanning alerts - Removed unused imports and functions - Removed temporary test files - Updated .gitignore ## Benefits - Better tree-shaking for modern bundlers - Smaller bundle sizes for ES module consumers - Proper bundle analysis on bundlephobia.com - Backward compatible with existing CommonJS consumers All CI checks passing ✅
1 parent 8a87054 commit dba2fb7

15 files changed

Lines changed: 1658 additions & 373 deletions

.github/workflows/ci.yml

Lines changed: 148 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,25 @@ on: [push, pull_request]
44

55
jobs:
66
test:
7+
name: Unit Tests & Coverage
78
runs-on: ubuntu-latest
89
steps:
9-
- uses: actions/checkout@v4
10+
- name: Checkout code
11+
uses: actions/checkout@v4
1012
with:
1113
fetch-depth: 0 # Fetch all history for better coverage comparison
1214

13-
- uses: actions/setup-node@v4
15+
- name: Setup Node.js
16+
uses: actions/setup-node@v4
1417
with:
1518
node-version: 20
1619
cache: 'npm'
1720

18-
- run: npm ci
19-
- run: npm run build --if-present
20-
- run: npm test
21+
- name: Install dependencies
22+
run: npm ci
23+
24+
- name: Run unit tests with coverage
25+
run: npm test
2126

2227
- name: Upload coverage reports to Codecov
2328
uses: codecov/codecov-action@v5
@@ -29,3 +34,141 @@ jobs:
2934
fail_ci_if_error: false
3035
verbose: true
3136

37+
esm-validation:
38+
name: ESM Build Validation
39+
runs-on: ubuntu-latest
40+
needs: test # Run after unit tests pass
41+
strategy:
42+
matrix:
43+
node-version: [18, 20, 22] # Test on multiple Node.js versions
44+
steps:
45+
- name: Checkout code
46+
uses: actions/checkout@v4
47+
48+
- name: Setup Node.js ${{ matrix.node-version }}
49+
uses: actions/setup-node@v4
50+
with:
51+
node-version: ${{ matrix.node-version }}
52+
cache: 'npm'
53+
54+
- name: Install dependencies
55+
run: npm ci
56+
57+
- name: Build project (CJS + ESM)
58+
run: npm run build
59+
60+
- name: Verify ESM build artifacts exist
61+
run: |
62+
echo "Checking ESM build artifacts..."
63+
test -d build/esm || (echo "❌ ESM build directory not found" && exit 1)
64+
test -f build/esm/index.js || (echo "❌ ESM entry point not found" && exit 1)
65+
test -f build/esm/package.json || (echo "❌ ESM package.json marker not found" && exit 1)
66+
echo "✅ ESM build artifacts verified"
67+
68+
- name: Verify ESM package.json type marker
69+
run: |
70+
echo "Checking ESM package.json marker..."
71+
grep -q '"type".*"module"' build/esm/package.json || (echo "❌ ESM package.json missing type:module" && exit 1)
72+
echo "✅ ESM package.json type marker verified"
73+
74+
- name: Run ESM integration tests
75+
run: npm run test:esm
76+
77+
- name: Test ESM import in Node.js (smoke test)
78+
run: |
79+
echo "Testing direct ESM import..."
80+
node -e "import('./build/esm/index.js').then(m => { console.log('✅ ESM import successful'); console.log('Exports:', Object.keys(m).join(', ')); }).catch(e => { console.error('❌ ESM import failed:', e.message); process.exit(1); })"
81+
82+
- name: Upload ESM test results
83+
if: always()
84+
uses: actions/upload-artifact@v4
85+
with:
86+
name: esm-test-results-node-${{ matrix.node-version }}
87+
path: |
88+
build/esm/**/*.js
89+
build/esm/package.json
90+
retention-days: 7
91+
92+
esm-validation-summary:
93+
name: ESM Validation Summary
94+
runs-on: ubuntu-latest
95+
needs: esm-validation
96+
if: always() && github.event_name == 'pull_request'
97+
steps:
98+
- name: Comment PR with ESM validation results
99+
uses: actions/github-script@v7
100+
with:
101+
script: |
102+
const conclusion = '${{ needs.esm-validation.result }}';
103+
const nodeVersions = ['18', '20', '22'];
104+
105+
let statusIcon = conclusion === 'success' ? '✅' : '❌';
106+
let statusText = conclusion === 'success' ? 'All ESM validation checks passed!' : 'ESM validation failed!';
107+
108+
const body = `## ${statusIcon} ESM Build Validation
109+
110+
**Status:** ${statusText}
111+
112+
### Test Matrix Results
113+
114+
| Node.js Version | Status |
115+
|-----------------|--------|
116+
${nodeVersions.map(v => `| ${v} | ${conclusion === 'success' ? '✅ Passed' : '❌ Failed'} |`).join('\n')}
117+
118+
### Validation Steps
119+
120+
- ${conclusion === 'success' ? '✅' : '❌'} ESM build artifacts generated
121+
- ${conclusion === 'success' ? '✅' : '❌'} \`package.json\` type marker present
122+
- ${conclusion === 'success' ? '✅' : '❌'} All imports have proper \`.js\` extensions
123+
- ${conclusion === 'success' ? '✅' : '❌'} Runtime import tests passed
124+
- ${conclusion === 'success' ? '✅' : '❌'} Functionality tests passed
125+
126+
### What This Validates
127+
128+
The ESM validation suite ensures:
129+
130+
1. **Import Resolution**: All relative imports have proper \`.js\` extensions for Node.js ESM compatibility
131+
2. **Directory Imports**: Directory imports correctly resolve to \`/index.js\`
132+
3. **Package Structure**: ESM build includes \`package.json\` with \`"type": "module"\`
133+
4. **Runtime Compatibility**: Package can be imported and used in Node.js 18, 20, and 22
134+
5. **Export Completeness**: All expected exports are accessible
135+
6. **Functionality**: Imported code executes correctly
136+
137+
${conclusion === 'success'
138+
? '✅ **The package is ready for ESM consumption!**'
139+
: '❌ **Please fix ESM issues before merging.**'}
140+
141+
---
142+
143+
*This validation prevents issues like missing \`.js\` extensions, broken directory imports, and \`ERR_MODULE_NOT_FOUND\` errors.*`;
144+
145+
// Find existing ESM validation comment
146+
const { data: comments } = await github.rest.issues.listComments({
147+
issue_number: context.issue.number,
148+
owner: context.repo.owner,
149+
repo: context.repo.repo,
150+
});
151+
152+
const botComment = comments.find(comment =>
153+
comment.user.type === 'Bot' &&
154+
comment.body.includes('ESM Build Validation')
155+
);
156+
157+
if (botComment) {
158+
// Update existing comment
159+
await github.rest.issues.updateComment({
160+
comment_id: botComment.id,
161+
owner: context.repo.owner,
162+
repo: context.repo.repo,
163+
body: body
164+
});
165+
} else {
166+
// Create new comment
167+
await github.rest.issues.createComment({
168+
issue_number: context.issue.number,
169+
owner: context.repo.owner,
170+
repo: context.repo.repo,
171+
body: body
172+
});
173+
}
174+

.github/workflows/release.yml

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,41 @@ jobs:
1313
release:
1414
runs-on: ubuntu-latest
1515
steps:
16-
- uses: actions/checkout@v4
16+
- name: Checkout code
17+
uses: actions/checkout@v4
1718
with:
1819
fetch-depth: 0
1920
persist-credentials: false
20-
- uses: actions/setup-node@v4
21+
22+
- name: Setup Node.js
23+
uses: actions/setup-node@v4
2124
with:
2225
node-version: 20
2326
cache: 'npm'
24-
- run: npm ci
25-
- run: npm run build --if-present
26-
- run: npm test
27-
- run: npx semantic-release
27+
28+
- name: Install dependencies
29+
run: npm ci
30+
31+
- name: Build project (CJS + ESM)
32+
run: npm run build
33+
34+
- name: Run unit tests
35+
run: npm test
36+
37+
- name: Run ESM integration tests
38+
run: npm run test:esm
39+
40+
- name: Verify package integrity before release
41+
run: |
42+
echo "Verifying package structure..."
43+
test -d build/cjs || (echo "❌ CJS build missing" && exit 1)
44+
test -d build/esm || (echo "❌ ESM build missing" && exit 1)
45+
test -f build/esm/package.json || (echo "❌ ESM package.json missing" && exit 1)
46+
grep -q '"type".*"module"' build/esm/package.json || (echo "❌ ESM type marker missing" && exit 1)
47+
echo "✅ Package structure verified"
48+
49+
- name: Semantic Release
50+
run: npx semantic-release
2851
env:
2952
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3053
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ node_modules
33
coverage
44
build
55
bench-results.json
6+
benchmark-*.txt
67

78
# Ignore compiled JavaScript files in src directory
89
# (TypeScript source files only, compiled output goes to dist/)

0 commit comments

Comments
 (0)