Skip to content

perf(core): lazy-load config deps & treeshake barrel exports#123

Merged
zrosenbauer merged 10 commits intomainfrom
perf/treeshake-barrel-exports
Mar 29, 2026
Merged

perf(core): lazy-load config deps & treeshake barrel exports#123
zrosenbauer merged 10 commits intomainfrom
perf/treeshake-barrel-exports

Conversation

@zrosenbauer
Copy link
Copy Markdown
Member

@zrosenbauer zrosenbauer commented Mar 29, 2026

Summary

  • Treeshake barrel exports (4b176df): Replace wildcard export * re-exports in @kidd-cli/utils/fp with explicit named exports, enabling bundler tree-shaking
  • Lazy-load config layer: Dynamic import() the config loader (c12yaml, jiti, confbox) in both cli.ts and runtime.ts so the ~15K-line dependency chain is only parsed when actually running a command — not during --help/--version rendering

These two changes together eliminate the dominant startup cost identified in CPU profiling (42ms compileSourceTextModule for the 30K-line bundle).

Files changed

  • packages/utils/src/fp/index.ts — explicit named re-exports instead of export *
  • packages/core/src/cli.ts — dynamic import('@kidd-cli/config/loader') inside resolveCommandsFromConfig()
  • packages/core/src/runtime/runtime.ts — dynamic import('@/lib/config/index.js') inside resolveConfig()

Test plan

  • pnpm check passes (typecheck + lint + format)
  • pnpm test --filter=@kidd-cli/core — all 856 tests pass
  • Verify --help and --version startup time improvement with profiling

…in fp barrel

The `export * from 'es-toolkit'` and `export * from 'ts-pattern'` in the fp
barrel module prevented tree-shaking in downstream CLI bundles. Only 7 es-toolkit
functions are used across the codebase, but all 193 modules were bundled.

Narrows exports to the specific functions consumed: attempt, attemptAsync,
isFunction, isNil, isPlainObject, isString, noop, match, P.

Co-Authored-By: Claude <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
oss-kidd Ignored Ignored Preview Mar 29, 2026 11:54pm

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 29, 2026

🦋 Changeset detected

Latest commit: 5a19f17

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@kidd-cli/utils Minor
@kidd-cli/bundler Patch
@kidd-cli/cli Patch
@kidd-cli/config Patch
@kidd-cli/core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 29, 2026

Merging this PR will create unknown performance changes

🎉 Hooray! exec-harness just leveled up to 1.2.0!

A heads-up, this is a breaking change and it might affect your current performance baseline a bit. But here's the exciting part - it's packed with new, cool features and promises improved result stability 🥳!
Curious about what's new? Visit our releases page to delve into all the awesome details about this new version.

🆕 2 new benchmarks
⏩ 2 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
🆕 WallTime icons status N/A 411.9 ms N/A
🆕 WallTime icons --help N/A 392.6 ms N/A

Comparing perf/treeshake-barrel-exports (5a19f17) with main (9a6fa77)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 29, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaced a wildcard export from ts-pattern with explicit exports match and P in packages/utils/src/fp/index.ts. Converted two previously top-level static imports into dynamic imports: loadConfig is imported inside resolveCommandsFromConfig in packages/core/src/cli.ts, and createConfigClient is imported inside resolveConfig in packages/core/src/runtime/runtime.ts. Tests and helpers were updated: tests/helpers.ts adds CliRunResult, CliRunnerOptions, SubprocessRunner, InProcessRunner, a new createInProcessRunner implementation, and adjusts createExampleRunner types; tests/bench/icons.bench.ts switches to createInProcessRunner and awaits runner results.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the two main changes: performance optimization through lazy-loading config dependencies and treeshaking barrel exports via explicit named exports.
Description check ✅ Passed The description clearly relates to the changeset, providing specific details about treeshaking barrel exports and lazy-loading config dependencies with file paths and rationale.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/treeshake-barrel-exports

Comment @coderabbitai help to get the list of available commands and usage tips.

Dynamic import() the config loader (c12 → yaml, jiti, confbox) only when
actually needed — not during yargs setup/help rendering. This cuts ~15K
lines from the startup parse path for --help and --version.

Co-Authored-By: Claude <noreply@anthropic.com>
@zrosenbauer zrosenbauer changed the title perf(utils): fix tree-shaking for es-toolkit and ts-pattern perf(core): lazy-load config deps & treeshake barrel exports Mar 29, 2026
zrosenbauer and others added 3 commits March 29, 2026 18:17
es-toolkit declares "sideEffects": false, so export * tree-shakes
correctly. Explicit named exports just add maintenance burden.

Co-Authored-By: Claude <noreply@anthropic.com>
Add createInProcessRunner that dynamically imports the built CLI entry
with process.argv/exit/stdout/stderr stubs. This runs benchmarks in the
same V8 process so CodSpeed can resolve interpreted frame symbols and
generate flamegraphs.

Switch icons benchmark from subprocess (createExampleRunner) to
in-process (createInProcessRunner) to fix "Execution profile not
available" in CodSpeed.

Co-Authored-By: Claude <noreply@anthropic.com>
Keep updateSettings from main, keep loadConfig lazy-loaded from our branch.

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/helpers.ts`:
- Around line 98-99: The code builds entryPath (const entryPath =
`${EXAMPLES_DIR}/${example}/${distPath}`) and then passes it directly to
import(), which breaks on Windows; instead convert the filesystem path to a
file:// URL using pathToFileURL(entryPath) and add the cache-bust query via the
returned URL's searchParams before calling import(); update usages around
entryPath and the dynamic import to call pathToFileURL and use
url.searchParams.append(...) so import(url.toString()) receives a proper file://
URL.
- Around line 100-141: The createInProcessRunner function mutates process
globals (process.argv/process.exit/process.stdout.write/process.stderr.write)
making it re-entrancy unsafe; wrap the section that applies and restores these
global patches and imports entryPath in a single-flight/async-mutex so only one
runner can monkeypatch at a time, await the mutex before applying the patches,
release it in the finally block after restoring originals, and ensure the lock
is held across the await import(`${entryPath}?t=${Date.now()}`) to prevent
interleaving between concurrent invocations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6f418f2e-62a5-43ac-8ca4-cd9677cbfe0d

📥 Commits

Reviewing files that changed from the base of the PR and between 1e213ec and 2a08444.

📒 Files selected for processing (2)
  • tests/bench/icons.bench.ts
  • tests/helpers.ts

Comment thread tests/helpers.ts Outdated
Comment thread tests/helpers.ts Outdated
… calls

- Convert filesystem paths to file:// URLs via pathToFileURL for Windows compat
- Add promise-based queue to serialize createInProcessRunner invocations,
  preventing re-entrancy issues with process-global patches

Co-Authored-By: Claude <noreply@anthropic.com>
zrosenbauer and others added 4 commits March 29, 2026 19:39
Remove the vitest bench + in-process runner setup that monkeypatched
process globals (argv, exit, stdout, stderr) in favor of CodSpeed's
official `codspeed exec` CLI which benchmarks the built CLI as a
normal subprocess.

- Delete createInProcessRunner and related types from tests/helpers.ts
- Delete tests/bench/icons.bench.ts and vitest.bench.config.ts
- Remove @codspeed/vitest-plugin dependency and test:bench script
- Update CI workflow to use codspeed exec --mode walltime

Co-Authored-By: Claude <noreply@anthropic.com>
The action already instruments commands via perf — running codspeed exec
inside the action causes a sudo/perf conflict. Define benchmark targets
in codspeed.yml and let the action (v4.9.0+) pick them up directly.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@zrosenbauer zrosenbauer merged commit 687e8a1 into main Mar 29, 2026
7 checks passed
@zrosenbauer zrosenbauer deleted the perf/treeshake-barrel-exports branch March 29, 2026 23:58
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