Skip to content

Configure package for npm publishing with dual ESM/CJS output - #5

Merged
stevekrenzel merged 1 commit into
mainfrom
npm_publishing
Dec 22, 2025
Merged

Configure package for npm publishing with dual ESM/CJS output#5
stevekrenzel merged 1 commit into
mainfrom
npm_publishing

Conversation

@stevekrenzel

@stevekrenzel stevekrenzel commented Dec 22, 2025

Copy link
Copy Markdown
Contributor

Summary

  • Rename package from intent to @with-logic/intent for scoped npm publishing
  • Add custom esbuild-based build script producing dual ESM (.mjs) and CJS (.cjs) bundles
  • Configure package.json with proper npm publishing metadata and export maps

Problem

The library needed to be prepared for public npm distribution with proper:

  • Scoped package naming (@with-logic/intent)
  • Dual module format support for both ESM and CommonJS consumers
  • Correct export configuration for modern bundlers and Node.js

Solution

Package Configuration:

  • Set private: false with publishConfig.access: public for scoped publishing
  • Add comprehensive metadata (keywords, repository, bugs, homepage)
  • Configure dual exports via main (CJS), module (ESM), types, and conditional exports map
  • Add sideEffects: false for tree-shaking optimization
  • Include prepublishOnly and release scripts for safe publishing workflow

Build System:

  • New scripts/build.mjs using esbuild for fast bundling
  • Produces dist/index.mjs (ESM) and dist/index.cjs (CommonJS)
  • TypeScript declarations generated via tsc --emitDeclarationOnly
  • Externalized dependencies (groq-sdk, dotenv) to avoid bundling
  • Targets Node 18+

TypeScript Configuration:

  • Updated moduleResolution to Bundler for modern tooling compatibility
  • Added verbatimModuleSyntax for explicit import/export type handling
  • Removed esModuleInterop (not needed with verbatim module syntax)

🤖 Generated with Claude Code

@stevekrenzel stevekrenzel changed the title Configure package for npm publishing with dual ESM/CJS ou… Configure package for npm publishing with dual ESM/CJS output Dec 22, 2025
@claude

claude Bot commented Dec 22, 2025

Copy link
Copy Markdown

Claude finished @stevekrenzel's task —— View job


PR Review Complete

Tasks

  • Read and analyze changed files
  • Review against code quality standards
  • Check documentation requirements
  • Verify TypeScript best practices
  • Provide actionable feedback

Overall Assessment

This PR successfully configures the package for npm publishing with a clean, straightforward implementation. The changes are well-structured and the dual ESM/CJS output setup is solid. However, there are several documentation and code quality issues that need to be addressed to meet the Intent library's strict engineering standards.

Summary: ✅ Functional and correct | ⚠️ Documentation improvements needed


Critical Issues

1. Missing JSDoc Documentation (scripts/build.mjs)

Severity: High - Violates core requirement that "every function (public and private) must have JSDoc"

All functions have basic JSDoc comments, but they lack the required detail and formatting standards specified in CLAUDE.md:

  • Lines 33-36 (clean): Missing @returns tag and detailed explanation

    /**
     * Clean the output directory.
     * 
     * Removes the dist/ directory and all its contents. This ensures a fresh build
     * without artifacts from previous builds.
     * 
     * @returns {void}
     */
  • Lines 41-55 (buildBundles): Missing @returns, @throws, and detailed parameter explanations

    /**
     * Build ESM and CJS bundles with esbuild.
     * 
     * Creates two separate bundles:
     * - dist/index.mjs for ESM consumers (import syntax)
     * - dist/index.cjs for CommonJS consumers (require syntax)
     * 
     * Both bundles share the same configuration (platform, target, sourcemaps)
     * and externalize dependencies to avoid bundling them.
     * 
     * @returns {Promise<void>} Resolves when both bundles are built successfully
     * @throws {Error} If esbuild encounters compilation errors
     */
  • Lines 60-65 (buildDeclarations): Missing @returns, @throws, and detailed explanation

    /**
     * Generate TypeScript declaration files using tsc.
     * 
     * Runs the TypeScript compiler with --emitDeclarationOnly to produce .d.ts files
     * for the bundled output. This provides type information for TypeScript consumers
     * without including implementation code.
     * 
     * @returns {void}
     * @throws {Error} If TypeScript compilation fails or tsc is not available
     */
  • Lines 70-80 (main): Missing @returns, @throws, and detailed explanation of the build flow

    /**
     * Main build process.
     * 
     * Orchestrates the complete build pipeline:
     * 1. Cleans the output directory
     * 2. Builds ESM and CJS bundles in parallel
     * 3. Generates TypeScript declaration files
     * 
     * If any step fails, the process exits with code 1 to signal build failure
     * to CI/CD systems and npm scripts.
     * 
     * @returns {Promise<void>} Resolves when the entire build completes successfully
     */

Recommendation: Add comprehensive JSDoc to all functions following the standards in CLAUDE.md. Documentation should explain "why" not just "what", include edge cases, and use complete sentences.


Moderate Issues

2. Single-Line If Statement Without Braces (scripts/build.mjs:82)

Severity: Moderate - Directly violates "Always use braces: No single-line if statements"

Location: scripts/build.mjs:82

main();

Actually, upon closer inspection, there are no single-line if statements without braces in the code. This is correct. ✅

3. Console.log Statements (scripts/build.mjs)

Severity: Low-Moderate - The checklist states "No console.log statements"

Locations: Lines 34, 42, 49, 61, 75, 77

The build script uses console.log for progress reporting (lines 34, 42, 49, 61, 75) and console.error for error handling (line 77).

Analysis: This is actually appropriate for a build script. The "no console.log" rule applies to library code, not build/development tooling. Build scripts should provide feedback about their progress.

Recommendation: These console statements are acceptable. Consider this a false positive from the checklist. ✅

4. Error Handling Could Be More Specific (scripts/build.mjs:76-79)

Severity: Low

Location: scripts/build.mjs:76-79

} catch (error) {
  console.error("Build failed:", error);
  process.exit(1);
}

Issue: The catch block uses implicit any type for error and doesn't include structured error type checking.

Recommendation: Follow test error handling pattern from CLAUDE.md:

} catch (error) {
  console.error(
    "Build failed:",
    error instanceof Error ? error.message : String(error)
  );
  process.exit(1);
}

This ensures proper type safety and consistent error message formatting.


Minor Issues / Observations

5. package.json Configuration

Observations:

  • ✅ Export map correctly configured with conditional exports for types/import/require
  • sideEffects: false properly set for tree-shaking
  • ✅ Publishing scripts include quality checks (prepublishOnly runs lint, typecheck, test, build)
  • ✅ Repository metadata is complete and accurate
  • ✅ Keywords are relevant and helpful for npm discovery

Note: The files array only includes dist (line 38-40). Make sure you don't want to include README.md, LICENSE, or CHANGELOG.md in the published package. Common practice is to include documentation files.

Recommendation (optional): Consider adding documentation files to the files array:

"files": [
  "dist",
  "README.md",
  "LICENSE"
],

6. TypeScript Configuration

Observations:

  • moduleResolution: "Bundler" is correct for modern tooling
  • verbatimModuleSyntax: true enforces explicit type imports
  • ✅ Strict mode flags are comprehensive

No issues found in tsconfig.json.

7. Build Script Structure

Observations:

  • ✅ Functions are appropriately sized (under 30 lines each)
  • ✅ Single responsibility principle followed
  • ✅ No nested conditionals or complex control flow
  • ✅ Early exit on error (line 78)
  • ✅ Uses const for all declarations

Strong points:

  • Clean separation of concerns (clean, bundle, declarations)
  • Shared esbuild options extracted to constant
  • Straightforward async/await usage

Testing Considerations

Question: Should the build script have tests?

The build script is not covered by tests (build scripts are typically not unit tested). However, the PR should verify:

  • Does npm run build produce the expected outputs?
  • Do the ESM and CJS bundles work correctly?
  • Are declaration files generated properly?
  • Can consumers import using both require() and import?

Recommendation: While not blocking for merge, consider adding an integration test or manual verification checklist in the PR description confirming the build outputs work as expected.


Security Review

  • ✅ No secrets or credentials exposed
  • ✅ No unsafe file operations (rmSync uses safe options)
  • ✅ execSync usage is safe (no user input interpolation)
  • ✅ Dependencies are externalized (not bundled)

Checklist Against Standards

Based on the "Final Checklist" from the review instructions:

  • No functions over 50 lines (target: 20-30) ✅ All functions under 20 lines
  • All if statements use braces ✅ No single-line if statements
  • All functions have JSDoc documentation ⚠️ Documentation incomplete (see Critical Issue Initial implementation of the intent LLM reranker library. #1)
  • No any types without justification ✅ Implicit any in error handling (see Moderate Issue Intent ergonomics overhaul: unified API, explainable outputs, and smarter Groq defaults #4)
  • No hardcoded values that should be config ✅ Values properly extracted to constants
  • No commented-out code ✅ Clean code
  • No console.log statements ✅ Appropriate for build script
  • Type checking passes (npm run typecheck) - Not verified in PR
  • Linting passes (npm run lint:check) - Not verified in PR
  • Tests pass with 100% coverage (npm run test:unit) - Not verified in PR (build script not covered)
  • Build succeeds (npm run build) - Not verified in PR

Required Actions Before Merge

  1. Add comprehensive JSDoc to all functions in scripts/build.mjs following the standards detailed in Critical Issue Initial implementation of the intent LLM reranker library. #1
  2. Improve error handling in the catch block (Moderate Issue Intent ergonomics overhaul: unified API, explainable outputs, and smarter Groq defaults #4)
  3. Verify CI passes: Ensure all quality checks pass
  4. (Optional) Consider adding README.md and LICENSE to the files array (Minor Issue Configure package for npm publishing with dual ESM/CJS output #5)

Strengths of This PR

  • Clean, well-structured build script with excellent separation of concerns
  • Correct dual module format configuration
  • Proper npm publishing setup with quality gates
  • Modern TypeScript configuration
  • Small, focused functions following size guidelines
  • No premature optimization or over-engineering

Conclusion

This is a solid, functional PR that correctly implements npm publishing configuration. The main gap is documentation quality—specifically, JSDoc comments need to meet the library's comprehensive standards. Once the documentation is enhanced and the minor error handling improvement is made, this will be ready to merge.

Estimated effort to address: ~15 minutes to enhance JSDoc and improve error handling.


…tput

## Summary

- Rename package from `intent` to `@with-logic/intent` for scoped npm publishing
- Add custom esbuild-based build script producing dual ESM (`.mjs`) and CJS (`.cjs`) bundles
- Configure package.json with proper npm publishing metadata and export maps

## Problem

The library needed to be prepared for public npm distribution with proper:
- Scoped package naming (`@with-logic/intent`)
- Dual module format support for both ESM and CommonJS consumers
- Correct export configuration for modern bundlers and Node.js

## Solution

**Package Configuration:**
- Set `private: false` with `publishConfig.access: public` for scoped publishing
- Add comprehensive metadata (keywords, repository, bugs, homepage)
- Configure dual exports via `main` (CJS), `module` (ESM), `types`, and conditional `exports` map
- Add `sideEffects: false` for tree-shaking optimization
- Include `prepublishOnly` and `release` scripts for safe publishing workflow

**Build System:**
- New `scripts/build.mjs` using esbuild for fast bundling
- Produces `dist/index.mjs` (ESM) and `dist/index.cjs` (CommonJS)
- TypeScript declarations generated via `tsc --emitDeclarationOnly`
- Externalized dependencies (`groq-sdk`, `dotenv`) to avoid bundling
- Targets Node 18+

**TypeScript Configuration:**
- Updated `moduleResolution` to `Bundler` for modern tooling compatibility
- Added `verbatimModuleSyntax` for explicit import/export type handling
- Removed `esModuleInterop` (not needed with verbatim module syntax)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@stevekrenzel
stevekrenzel merged commit 5da3f40 into main Dec 22, 2025
1 check passed
@stevekrenzel
stevekrenzel deleted the npm_publishing branch December 22, 2025 10:06
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.

1 participant