Skip to content

Conversation

@AbanoubGhadban
Copy link
Collaborator

@AbanoubGhadban AbanoubGhadban commented Nov 30, 2025

Summary

Add automated bundle size monitoring to CI using size-limit. This helps prevent unexpected bundle size regressions by comparing PR bundle sizes against the base branch.

How It Works

  1. CI checks out the base branch and measures bundle sizes
  2. CI checks out the PR branch and measures bundle sizes
  3. Compares sizes - fails if any package increases by more than 0.5KB
  4. Posts a size report comment on the PR

What Gets Measured

  • react-on-rails: Raw, gzip, and brotli compressed sizes
  • react-on-rails-pro: Raw, gzip, and brotli compressed sizes
  • react-on-rails-pro-node-renderer: Raw, gzip, and brotli compressed sizes
  • Webpack bundled imports: Client-side bundle sizes when importing via webpack

Local Testing

# Check current bundle sizes
pnpm run size

# Compare your branch against master
bin/compare-bundle-sizes

Bypassing the Check

For intentional size increases (e.g., adding new features):

bin/skip-bundle-size-check
git add .bundle-size-skip-branch
git commit -m "Skip bundle size check for intentional size increase"
git push

Pull Request checklist

  • Add/update test to cover these changes - N/A (CI workflow)
  • Update documentation - Added to CONTRIBUTING.md
  • Update CHANGELOG file

Summary by CodeRabbit

  • New Features

    • Automated bundle size CI monitoring compares PR bundle sizes against the base branch and fails if any package exceeds a 0.5KB growth threshold.
    • Added bypass mechanism for intentional bundle size increases.
  • Documentation

    • Bundle size checking and comparison commands documented.
    • Local tooling available to measure and compare package sizes against a base branch.
  • Chores

    • Bundle size monitoring workflow set up for CI.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 30, 2025

Walkthrough

This PR introduces automated bundle size monitoring to the CI pipeline. It adds a GitHub Actions workflow that measures bundle sizes across PR and base branches, compares them against configurable thresholds, and provides local tooling and a skip mechanism for intentional increases.

Changes

Cohort / File(s) Summary
Bundle Size CI Configuration
.bundle-size-skip-branch, .github/workflows/bundle-size.yml
Adds GitHub Actions workflow for automated bundle size checks with conditional skip logic based on skip-branch file. Implements two-job workflow: one checks if current branch should skip checks, the other measures base and PR bundle sizes, computes dynamic limits, and validates against thresholds.
Executable Tooling Scripts
bin/compare-bundle-sizes, bin/skip-bundle-size-check
Adds two shell scripts: compare-bundle-sizes stashes changes, measures sizes on base and current branches, then compares via Node script; skip-bundle-size-check creates a skip configuration file for the current branch.
Bundle Size Utilities
scripts/bundle-size.mjs
New Node.js script providing set-limits command (computes dynamic limits from base sizes) and compare command (outputs diff/percentage comparisons as table or JSON). Includes formatting, color-coding, and threshold-based validation.
Documentation
CONTRIBUTING.md, CHANGELOG.md
Documents new bundle size CI monitoring, local comparison commands, and skip mechanism. Adds entry to changelog referencing the feature.
Dependencies
package.json
Reorders globals dependency within devDependencies (no version change).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • .github/workflows/bundle-size.yml – Multi-job workflow with conditional execution, artifact handling, dynamic configuration generation, and integration between multiple steps; requires understanding of CI pipeline behavior.
  • scripts/bundle-size.mjs – Node.js logic for JSON parsing, size calculations, diff computation, color-coded formatting, CLI argument parsing, and error handling across multiple command branches.
  • bin/compare-bundle-sizes and bin/skip-bundle-size-check – Shell scripts with git operations, file I/O, error handling, and state management; correctness in stash/restore logic is critical.

Possibly related issues

  • Issue #2146 – Directly addresses bundle size CI implementation; these changes implement the workflow, scripts, and tooling described in that issue.

Possibly related PRs

  • PR #2148 – Both PRs modify or add components of the bundle size CI pipeline, including the GitHub Actions workflow, size-limit configuration, and supporting scripts.

Suggested labels

review-needed, full-ci

Suggested reviewers

  • Judahmeek

Poem

🐰 A rabbit hops through code so neat,
Bundle sizes, now complete!
CI checks with care and grace,
Keep those builds within their place. 🎯

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately summarizes the main change: adding an automated bundle size CI check using the size-limit tool.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/bundle-size-ci

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@claude
Copy link

claude bot commented Nov 30, 2025

Code Review: Empty Commit PR

Overview

This PR contains an empty commit merging feature/bundle-size-ci into feature/bundle-size-ci-base.

Stats:

  • 0 files changed
  • 0 additions
  • 0 deletions

Analysis

Purpose Assessment

Based on the PR title and content, this appears to be an intentional empty commit. Empty commits are sometimes used for:

  • Triggering CI/CD workflows
  • Testing pipeline configurations
  • Rebasing or synchronizing branches
  • Forcing a rebuild

Issues Identified

Critical:

  1. Missing PR Description - The PR body still contains the template text that should be removed. The summary section explicitly states: "Remove this paragraph and provide a general description..." but no actual description was provided.

  2. Incomplete Checklist - All checklist items are unchecked:

    • Add/update test to cover these changes
    • Update documentation
    • Update CHANGELOG file
  3. No Context - There's no explanation of:

    • Why an empty commit is needed
    • What this is testing or fixing
    • How this relates to bundle size CI (based on branch names)

Recommendations

If this is for testing CI workflows:

  • ✅ Add a clear explanation in the PR description explaining the purpose
  • ✅ Mark non-applicable checklist items as ~~ ~~ (strikethrough) per the template instructions
  • ✅ Consider using [skip ci] in commit message if you don't want to trigger full CI
  • ✅ Link to any related issues or PRs

If this was created accidentally:

  • ❌ Close this PR
  • Create a new PR with actual changes

General Best Practices:
Per CLAUDE.md:

  • Empty commits should have clear justification
  • All template instructions should be removed or replaced with actual content
  • Checklist items should be checked or marked as not applicable

Questions

  1. What is the purpose of this empty commit?
  2. Is this related to the bundle size CI workflow mentioned in the branch name?
  3. Should this PR be closed in favor of a PR with actual changes?

Review generated by Claude Code - following repository conventions from CLAUDE.md

@claude
Copy link

claude bot commented Nov 30, 2025

Code Review: Bundle Size CI Test

Overview

This PR adds a test file to verify that the bundle size CI workflow properly catches bundle size increases.

Changes:

  • Added packages/react-on-rails/src/bloat.ts with ~550 bytes of test data across 10 exported constants

Analysis

Purpose

Based on the branch name (feature/bundle-size-ci) and the file content, this appears to be testing whether the Bundle Size workflow (.github/workflows/bundle-size.yml) correctly detects and fails when bundle sizes increase beyond the threshold.

How It Works

  1. The bloat.ts file will be compiled by TypeScript to lib/bloat.js
  2. The bundle size config measures all files matching packages/react-on-rails/lib/*.js (per .size-limit.json lines 3-7)
  3. The CI workflow compares PR bundle size against base branch with a 0.5KB (512 byte) threshold
  4. This should trigger a size increase warning/failure

Issues & Recommendations

Critical:

  1. File is not imported/used anywhere

    • This is actually GOOD for testing - it will compile to lib/bloat.js and be included in size measurements without affecting runtime behavior
    • However, this means it's dead code that will ship to users if merged
  2. PR Description Missing

    • Template text still present
    • Should explain this is a test PR to verify bundle size CI works
    • Should note this is NOT intended to be merged
  3. Missing Documentation ⚠️

    • Consider adding a comment in the file explaining its purpose:
      // Test file to verify bundle size CI catches increases
      // This file should NOT be merged - it's only for testing the CI workflow
  4. Test Plan ⚠️

    • After CI runs and (hopefully) fails, the PR should be closed
    • The bloat file should be removed
    • Consider documenting the test results in an issue or discussion

Best Practices per CLAUDE.md:

  • ✅ File ends with newline (will be enforced by pre-commit hooks)
  • ⚠️ PR checklist items unchecked - should mark as not applicable with ~~item~~
  • ❌ No CHANGELOG entry - probably not needed for test PR, but should mark as not applicable
  • ⚠️ Should mark PR as [WIP] or [TEST] in title to prevent accidental merge

Security & Performance

  • ✅ No security concerns - just string constants
  • ✅ No runtime performance impact (code won't be imported/executed)
  • ⚠️ Adds ~0.5KB to bundle size - this is intentional for testing but should NOT be merged

Suggested Next Steps

  1. Update PR title to: [TEST] Verify bundle size CI catches increases
  2. Update PR description to clearly state:
    • This is a test PR for the bundle size CI workflow
    • Expected behavior: CI should fail due to size increase
    • This PR should be closed after verifying CI works
  3. After CI runs:
    • Document the results
    • Close this PR without merging
    • If CI fails to catch the increase, investigate and fix the workflow

Questions

  1. Is this PR intended to be merged, or is it a test that should be closed after CI runs?
  2. Should we add a .bundle-size-skip-branch entry to prevent the check, or do we want it to run and fail?
  3. Would it be better to test this in a separate repository to avoid polluting the PR history?

Overall Assessment: This appears to be a well-intentioned test of the bundle size CI, but it should be clearly marked as a test PR and should not be merged. The approach is sound for verifying the CI works correctly.

Review generated following repository conventions from CLAUDE.md

@github-actions
Copy link
Contributor

github-actions bot commented Nov 30, 2025

size-limit report 📦

Path Size
react-on-rails (raw) 40.67 KB (0%)
react-on-rails (gzip) 14.51 KB (0%)
react-on-rails (brotli) 12.16 KB (0%)
react-on-rails-pro (raw) 91.75 KB (0%)
react-on-rails-pro (gzip) 33.19 KB (0%)
react-on-rails-pro (brotli) 27.23 KB (0%)
react-on-rails-pro-node-renderer (raw) 24.64 KB (0%)
react-on-rails-pro-node-renderer (gzip) 7.62 KB (0%)
react-on-rails-pro-node-renderer (brotli) 6.52 KB (0%)
react-on-rails/client bundled (gzip) 62.33 KB (0%)
react-on-rails/client bundled (brotli) 53.48 KB (0%)
react-on-rails-pro/client bundled (gzip) 63.38 KB (0%)
react-on-rails-pro/client bundled (brotli) 54.44 KB (0%)
registerServerComponent/client bundled (gzip) 170.07 KB (0%)
registerServerComponent/client bundled (brotli) 83.46 KB (0%)
wrapServerComponentRenderer/client bundled (gzip) 164.61 KB (0%)
wrapServerComponentRenderer/client bundled (brotli) 78.58 KB (0%)

@AbanoubGhadban AbanoubGhadban changed the base branch from feature/bundle-size-ci-base to master November 30, 2025 18:35
@AbanoubGhadban AbanoubGhadban changed the title Empty commit Add bundle size CI check using size-limit Nov 30, 2025
@claude
Copy link

claude bot commented Nov 30, 2025

PR Review: Bundle Size CI Check

Thank you for adding bundle size monitoring! This is a valuable addition. Here is my detailed review:

Strengths

  1. Well-structured implementation with CI workflow, dynamic thresholds, local tools, and skip mechanism
  2. Good developer experience with bin/compare-bundle-sizes and bin/skip-bundle-size-check
  3. Comprehensive coverage of all packages with multiple compression formats
  4. Clean, well-documented code

Critical Issues

Missing PR Description: Still shows template. Please provide summary, motivation, and update checklist

Missing Tests: No unit tests for bundle-size.mjs script (parseArgs, formatSize, formatDiff). No validation tests for CI workflow

Medium Priority Issues

Path Dependencies: .size-limit.json has hardcoded paths that will silently fail if directories move. Add validation step and document in CLAUDE.md

Error Handling Issues:

  • bin/compare-bundle-sizes:52 - continues if both git checkout fail
  • scripts/bundle-size.mjs:91 - unnecessary return before process.exit
  • bin/compare-bundle-sizes:53-54 - || true suppresses critical errors

Documentation: Missing CHANGELOG entry, no CLAUDE.md docs, undocumented package.json scripts

Code Quality Issues

  1. scripts/bundle-size.mjs:217 - Empty results array breaks Math.max
  2. bin/compare-bundle-sizes:19 - No check for detached HEAD
  3. bundle-size.yml:27 - Skip regex strips ALL whitespace
  4. Missing dependency caching in workflow

Security

Good: Using frozen-lockfile. Consider: Pin size-limit-action to SHA not v1

Checklist Status

  • ❌ Add/update tests
  • ❌ Update documentation
  • ❌ Update CHANGELOG
  • ✅ Implementation complete

Before Merging

  1. Fill out PR description
  2. Add CHANGELOG.md entry
  3. Add unit tests
  4. Fix error handling
  5. Add path validation
  6. Document in CLAUDE.md

Test locally: pnpm install --frozen-lockfile && pnpm run build && pnpm run size && bundle exec rubocop

Overall solid foundation! Main gaps are docs and tests. 🚀

@claude
Copy link

claude bot commented Nov 30, 2025

PR Review: Bundle Size CI Check

Thank you for adding bundle size monitoring! Here is my comprehensive review:

Strengths

  • Well-structured with good separation of concerns
  • Dynamic threshold approach (base + 0.5KB) avoids stale limits
  • Skip mechanism provides good developer experience
  • Comprehensive coverage of raw and compressed sizes

Critical Issues (Must Fix)

1. Missing CHANGELOG Entry (BLOCKER)
Per CLAUDE.md, add entry to /CHANGELOG.md under Developer Experience section

2. Missing PR Description (BLOCKER)
Replace template with actual what/why/how/testing details

3. Path Verification Required
Per managing-file-paths.md, verify paths exist:

  • pnpm run build
  • ls packages/react-on-rails/lib/*.js
  • pnpm exec size-limit --json

4. Testing Documentation Missing
Per CLAUDE.md, document what you tested locally

5. Bug in Skip Check Logic
Line 28 in workflow: tr -d will concatenate multiple branches.
Use grep -qxF instead to match exact lines.

6. Removed globals Dependency
Explain why globals was removed from package.json

Suggestions

  • Narrow workflow triggers to packages//src/
  • Use RUNNER_TEMP instead of /tmp in Actions
  • Add set -euo pipefail to bash scripts
  • Add documentation to README
  • Run pnpm run format before pushing

Overall Assessment

Valuable feature with good code quality. Main gaps are documentation and testing verification per CLAUDE.md requirements. Once critical issues addressed, will be great addition!

AbanoubGhadban added a commit that referenced this pull request Nov 30, 2025
## Summary
- Add size-limit and its plugins (@size-limit/file, @size-limit/webpack)
to enable bundle size measurement
- Add `size` and `size:json` npm scripts for local bundle size checking

This is a prerequisite for the bundle size CI workflow in PR #2149.

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

Co-authored-by: Claude <noreply@anthropic.com>
@claude
Copy link

claude bot commented Nov 30, 2025

Code Review Feedback

Thank you for adding bundle size monitoring to the project! This is a valuable addition that will help prevent unexpected size regressions. Here is my detailed review:

✅ Strengths

  1. Well-designed dynamic threshold system: The approach of comparing against the base branch with a configurable threshold (default 512 bytes) is excellent and prevents false positives from normal changes.

  2. Comprehensive coverage: Tracking both raw and compressed (gzip/brotli) sizes for all packages is thorough.

  3. Good developer tooling: The bin/compare-bundle-sizes script and bin/skip-bundle-size-check utility provide great local testing capabilities.

  4. Clean script organization: The scripts/bundle-size.mjs utility is well-structured with clear separation of concerns.


🔴 Critical Issues

1. Missing executable permissions on bin scripts ❗

The new bash scripts in bin/ are not executable. All other bin/* scripts in the repo have 755 permissions. This will cause execution failures when users try to run these scripts.

Fix required:

chmod +x bin/compare-bundle-sizes bin/skip-bundle-size-check
git add bin/compare-bundle-sizes bin/skip-bundle-size-check

2. Incomplete PR description ❗

The PR description is still using the template placeholders. According to CLAUDE.md guidelines, you should:

  • Provide a summary of what this PR adds
  • Complete the checklist items or mark them as not applicable
  • CRITICAL: Update the CHANGELOG.md with an entry for this user-facing feature

This is a user-facing feature that affects CI/CD workflows and needs a changelog entry.


⚠️ Issues to Address

3. Path validation needed

The .size-limit.json file references paths that should be validated. Per CLAUDE.md "Managing File Paths" guidelines, verify the paths actually exist after build and test operations that use them.

Recommendation: Add a comment in the PR showing that you have verified these paths exist after build.

4. Missing size-limit dependency test

According to CLAUDE.md "Testing Build and Package Scripts", before merging verify:

rm -rf node_modules
pnpm install --frozen-lockfile
pnpm run build
pnpm exec size-limit --json

5. Minor: Alphabetical ordering in package.json

The only change to package.json is reordering globals in the devDependencies. This is unrelated to the bundle size feature. Consider mentioning this in the PR description.


📝 Suggestions for Improvement

  1. Consider adding tests for the bundle-size.mjs script
  2. Document the workflow in CLAUDE.md explaining when it runs, how to skip it, and how to investigate regressions
  3. CI caching opportunity: Consider caching pnpm store between steps to speed up CI

🔍 Code Quality Notes

scripts/bundle-size.mjs:

  • ✅ Clean, readable code with good separation of concerns
  • ✅ Helpful error messages with color coding
  • ✅ Good documentation in comments

GitHub Actions workflow:

  • ✅ Good use of job dependencies
  • ✅ Proper permissions scoping
  • ✅ Clear step names and comments

📋 Action Items Before Merging

  1. ❗ Fix executable permissions on bin scripts
  2. ❗ Complete PR description (remove template text)
  3. ❗ Add CHANGELOG.md entry
  4. ⚠️ Verify build artifact paths exist
  5. ⚠️ Test clean install with new dependencies

Overall, this is a well-implemented feature with good attention to detail. The main blockers are the missing executable permissions and incomplete PR metadata. Great work on the dynamic threshold approach!

@claude
Copy link

claude bot commented Nov 30, 2025

Code Review: Add bundle size CI check using size-limit

Executive Summary

This PR introduces automated bundle size monitoring with dynamic thresholds and a skip mechanism. Implementation is solid but has security and design issues to address.

Critical Security Issues

1. Script Injection via github.head_ref - ✅ FIXED

Status: Fixed in commit 178cab7 by moving to environment variable. Good catch!

2. Incomplete Input Validation in Skip Check

Location: .github/workflows/bundle-size.yml:27-28

Problem: tr -d removes ALL whitespace including newlines. Multiple branch names would concatenate.

Fix: Use head -n1 instead and validate line count.

High Priority Issues

3. Missing JSON Validation

scripts/bundle-size.mjs needs to validate JSON structure from size-limit

4. Shell Script Error Handling

bin/compare-bundle-sizes needs set -o pipefail to catch pipe errors

5. Race Condition in Workflow

node_modules from base branch may contaminate PR build. Clean between checkouts.

Medium Priority Issues

  1. Document why 0.5KB threshold was chosen
  2. Workflow triggers on skip file (counterproductive)
  3. Revert unnecessary globals reordering in package.json
  4. Consider adding tests for bundle-size.mjs

What's Done Well ✅

  1. Skip mechanism for intentional increases
  2. Dynamic limits (base + threshold)
  3. Local comparison script
  4. Proper cleanup traps
  5. Security fix in 178cab7
  6. Comprehensive size tracking

Recommendations

Must Fix:

  • Fix input validation (Issue 2)
  • Add JSON validation (Issue 3)
  • Add set -o pipefail (Issue 4)

Should Fix:

  • Clean between checkouts (Issue 5)
  • Revert package.json reordering (Issue 8)
  • Document threshold (Issue 6)

Nice to Have:

  • Tests, CHANGELOG update, complete PR description

Final Verdict

⚠️ CHANGES REQUESTED

Great work! Security fix was spot-on. Please address issues 2-4 and this will be ready to merge.

@claude
Copy link

claude bot commented Nov 30, 2025

Code Review: Bundle Size CI Check

Thank you for this contribution! This is a well-thought-out approach to tracking bundle size. Here's my detailed review:


✅ Strengths

  1. Excellent workflow design - Using dynamic limits (base + threshold) is much better than static limits
  2. Good separation of concerns - scripts/bundle-size.mjs is well-structured with clear command separation
  3. Escape hatch provided - The skip mechanism via .bundle-size-skip-branch is useful for intentional increases
  4. Developer-friendly utilities - bin/compare-bundle-sizes enables local testing before pushing

🚨 Critical Issues

1. Missing executable permissions on scripts

The bash scripts in bin/ are not executable:

-rw-r--r-- bin/compare-bundle-sizes
-rw-r--r-- bin/skip-bundle-size-check

Fix:

chmod +x bin/compare-bundle-sizes bin/skip-bundle-size-check
git add bin/compare-bundle-sizes bin/skip-bundle-size-check

This is critical - without executable permissions, users can't run these scripts directly.

2. Missing CHANGELOG entry

According to CLAUDE.md, user-visible changes require a CHANGELOG entry. This is a new CI workflow and developer tooling, so it should be documented.

Add to CHANGELOG.md:

#### Developer Experience

- [PR 2149](https://github.com/shakacode/react_on_rails/pull/2149) by [AbanoubGhadban](https://github.com/AbanoubGhadban): Add bundle size CI check with dynamic limits and comparison utilities

3. Unrelated package.json change

The PR moves globals from line 37 to line 49 (alphabetical reordering). While this is correct, it's unrelated to bundle size checking and could cause merge conflicts. Consider either:

  • Keeping it in a separate commit with a clear message
  • Explaining why it's needed in the PR description

⚠️ Important Issues

4. Script error handling could be improved

In scripts/bundle-size.mjs:

Line 91: The function calls process.exit(1) but then returns it:

return process.exit(1);  // Line 91

Should be just:

process.exit(1);

The return is unreachable, though it doesn't cause bugs.

5. Workflow doesn't validate artifacts exist

The workflow assumes build outputs exist after pnpm run build, but doesn't verify. If the build succeeds but outputs are in wrong locations, size-limit will fail with unclear errors.

Suggestion: Add a validation step:

- name: Verify build artifacts
  run: |
    for pkg in packages/*/lib/*.js; do
      if [ \! -f "$pkg" ]; then
        echo "Missing: $pkg"
        exit 1
      fi
    done

6. PR description is incomplete

The PR body still contains template placeholders. Please:

  • Remove template instructions
  • Explain what this PR adds (bundle size CI)
  • Mention the 0.5KB threshold choice
  • Link to any related discussions about why this is needed

💡 Best Practices & Suggestions

7. Consider adding tests for bundle-size.mjs

The script has 300+ lines of logic but no tests. Consider adding:

  • Unit tests for formatSize(), formatDiff(), parseArgs()
  • Integration tests for setLimits() and compare() with fixture data

8. Document the 0.5KB threshold choice

Why 512 bytes? This seems arbitrary. Consider:

  • Documenting the rationale in the code or PR description
  • Making it configurable per-package in .size-limit.json
  • Different thresholds for different packages (e.g., main bundle vs utilities)

9. Workflow path triggers might be too broad

paths:
  - 'packages/**'

This triggers on ANY file in packages/, including:

  • Documentation
  • Test files
  • Type definitions

Suggestion: Be more specific:

paths:
  - 'packages/**/src/**'
  - 'packages/**/lib/**'
  - 'package.json'
  - 'pnpm-lock.yaml'

10. Skip mechanism could use better UX

The .bundle-size-skip-branch file requires manual editing and commit. Consider:

  • Making it a workflow input/label instead
  • Or using PR labels like skip-size-check
  • Or allowing multiple branches (one per line)

11. Error messages could be more actionable

When size limit is exceeded, the error should tell users:

  • How to run local comparison (bin/compare-bundle-sizes)
  • How to skip if intentional (bin/skip-bundle-size-check)
  • Why the threshold exists

In workflow (line 93-99):

- name: Check bundle size
  if: failure()
  run: |
    echo "::error::Bundle size exceeded threshold"
    echo "To compare locally: bin/compare-bundle-sizes"
    echo "If intentional: bin/skip-bundle-size-check"

🔒 Security

12. Workflow permissions are correct

permissions:
  contents: read
  pull-requests: write

Good job following least-privilege principle!


📋 Testing Recommendations

Before merging, please verify:

# 1. Test the workflow triggers correctly
# (Create a test PR with a package change)

# 2. Test local comparison script
bin/compare-bundle-sizes master

# 3. Test skip mechanism
bin/skip-bundle-size-check
cat .bundle-size-skip-branch  # Should contain current branch

# 4. Verify size-limit works
pnpm run size
pnpm run size:json

# 5. Test bundle-size.mjs commands
node scripts/bundle-size.mjs --help
pnpm run build
pnpm exec size-limit --json > /tmp/test.json
node scripts/bundle-size.mjs set-limits --base /tmp/test.json
node scripts/bundle-size.mjs compare --base /tmp/test.json --current /tmp/test.json

📝 Checklist

  • Add executable permissions to bash scripts
  • Update CHANGELOG.md
  • Complete PR description (remove template)
  • Fix return process.exit(1) (optional but cleaner)
  • Consider adding artifact validation
  • Test all scripts locally
  • Verify workflow runs on a test PR

Summary

This is solid work with a good architectural approach! The dynamic limit strategy is much better than static limits. The main blockers are:

  1. Missing executable permissions (required)
  2. Missing CHANGELOG entry (required per CLAUDE.md)
  3. Incomplete PR description (required)

Everything else is suggestions for improvement. Looking forward to seeing this merged! 🚀

@claude
Copy link

claude bot commented Nov 30, 2025

Code Review - Bundle Size Monitoring

This is a well-implemented bundle size monitoring system! The PR adds comprehensive size tracking with smart dynamic limits. Here's my detailed feedback:


✅ Strengths

  1. Excellent Architecture

    • Smart dynamic limit strategy (base + 0.5KB) prevents false positives while catching regressions
    • Comprehensive coverage: raw, gzip, and brotli compression for all packages
    • Great developer experience with local comparison script bin/compare-bundle-sizes
  2. Robust Workflow Design

    • Clever config handling: copies PR's .size-limit.json to base branch (handles new configs gracefully)
    • Skip mechanism with .bundle-size-skip-branch is a pragmatic escape hatch
    • Proper permissions and path filtering
  3. Clean Code

    • scripts/bundle-size.mjs is well-structured with clear separation of concerns
    • Good error handling with readJsonFileOrExit
    • Helpful color-coded output and formatting utilities
  4. Scripts Are Executable

    • Both bin/compare-bundle-sizes and bin/skip-bundle-size-check have proper +x permissions

⚠️ Issues to Address

1. PR Description Not Filled Out (REQUIRED)

The PR description still has template placeholders. Please update to:

  • Explain what this PR does and why bundle size monitoring matters
  • Describe the dynamic limit strategy (base + 0.5KB)
  • Mention the local testing tool
  • Check off completed items in the checklist

2. CHANGELOG Not Updated (REQUIRED per CLAUDE.md)

Developer tooling improvements should be documented. Add entry to CHANGELOG.md or use /update-changelog command.

3. Security: Potential Input Validation Issue

Location: scripts/bundle-size.mjs:127

If baseSizes JSON contains malformed data, it could cause unexpected behavior.

Recommendation: Add validation after parsing baseSizes to ensure it's an array with valid name/size properties.

Severity: Low

4. Workflow: Missing Error Handling for Build Failures

Location: .github/workflows/bundle-size.yml:76-80

If base branch build fails, the JSON file might be empty/malformed, causing cryptic errors later.

Recommendation: Add explicit error handling and validation that the JSON file is not empty.

Severity: Medium

5. Cleanup Missing Temp Files

Location: bin/compare-bundle-sizes:27-33

The cleanup function doesn't remove /tmp/base-sizes.json and /tmp/current-sizes.json.

Severity: Low

6. Missing Test Coverage

No tests for scripts/bundle-size.mjs utility functions.

Recommendation: Consider adding Jest tests for formatSize, formatDiff, parseArgs.

Severity: Low (nice-to-have)


🎯 Performance Considerations

✅ Good use of pnpm install --frozen-lockfile
✅ Path filtering prevents unnecessary runs
✅ Skip mechanism avoids blocking development
✅ Proper pnpm store caching


🔒 Security Considerations

✅ Correctly uses pull-requests: write permissions (minimal necessary)
⚠️ Input validation needed (see issue 3)
✅ Good fix for script injection via github.head_ref (commit d6cec1a)


📊 Size Limit Configuration Review

.size-limit.json looks comprehensive:
✅ Tracks all 3 packages (react-on-rails, pro, node-renderer)
✅ Monitors raw, gzip, and brotli compression
✅ Includes bundled imports for client-side code


📝 Code Quality

scripts/bundle-size.mjs:
✅ Clean ES modules syntax
✅ Good separation: setLimits vs compare commands
✅ Helpful CLI output with colors
⚠️ Missing JSDoc for some functions (minor)

Bash Scripts:
✅ Proper error handling with set -e
✅ Cleanup trap on EXIT
✅ Color-coded output for better UX
✅ Helpful usage documentation


✅ Pre-Commit Checklist per CLAUDE.md

Before merging:

  • Run bundle exec rubocop and fix all violations
  • Update PR description (remove template text)
  • Update CHANGELOG.md (required)
  • Verify all files end with newlines
  • Test locally: Run bin/compare-bundle-sizes

🚀 Recommendations Summary

Must Fix Before Merge:

  1. Fill out PR description properly
  2. Add CHANGELOG entry
  3. Add error handling to workflow build steps

Should Fix:
4. Add input validation in bundle-size.mjs
5. Clean up temp files in compare script

Nice to Have:
6. Add unit tests for utility functions


🎉 Overall Assessment

This is excellent work! The implementation is thoughtful, well-structured, and adds real value to the development workflow. The dynamic limit strategy is particularly clever—it prevents size regressions without creating maintenance burden from hardcoded limits.

With the required fixes above (PR description, CHANGELOG, error handling), this will be ready to merge.

Great job on the comprehensive coverage and developer experience! 🙌

@claude
Copy link

claude bot commented Nov 30, 2025

Pull Request Review: Bundle Size CI Check

Thank you for implementing bundle size monitoring! This is a valuable addition to prevent performance regressions. I have reviewed the changes and have feedback organized by category.


🔴 Critical Issues

1. Missing Dependency in package.json

The workflow uses size-limit but I do not see it added to package.json devDependencies. The only change to package.json is reordering globals.

Required fix:

"devDependencies": {
  "size-limit": "^11.0.0",
  "@size-limit/file": "^11.0.0",
  "@size-limit/webpack": "^11.0.0"
}

2. Build Artifact Path Verification

The workflow verifies build artifacts exist at packages/*/lib/*.js, but according to CLAUDE.md testing guidelines, you should test the build scripts locally first.

Required before merge:

# From CLAUDE.md: "Mandatory Testing After ANY Changes"
rm -rf node_modules
pnpm install --frozen-lockfile
pnpm run build
pnpm run prepack
ls -la packages/react-on-rails/lib/*.js
ls -la packages/react-on-rails-pro/lib/*.js
ls -la packages/react-on-rails-pro-node-renderer/lib/*.js

3. Incomplete PR Checklist

Per CLAUDE.md requirements, the PR description shows:

  • ❌ Add/update test - No tests for the bundle-size script
  • ❌ Update documentation - No docs on when/how to use skip mechanism
  • ❌ Update CHANGELOG - User-facing feature, should be documented

🟡 Code Quality & Best Practices

4. CI Job Failure Needs Investigation

The PR shows size: FAILURE and build: FAILURE in status checks. Before this can be merged, you must:

  1. Investigate why the workflow is failing
  2. Fix the failures locally first (per CLAUDE.md: "NEVER claim a test is fixed without running it locally first")
  3. Push verified fixes

Per CLAUDE.md guidelines:

If working in isolated environment, clearly state: "Cannot test locally in isolated workspace"
Use "This SHOULD fix..." for untested changes, not "This fixes..."

5. Bash Script Robustness

bin/compare-bundle-sizes:
The script has trap cleanup EXIT which is good, but consider handling signals:

trap cleanup EXIT INT TERM

6. Unused Environment Variable

In .github/workflows/bundle-size.yml:

env:
  CI_JOB_NUMBER: 1

Question: This is not referenced anywhere in the workflow. If unused, remove it.


🟢 Performance Considerations

7. Workflow Efficiency

The workflow:

  1. ✅ Only runs on relevant file changes (good path filtering)
  2. ✅ Reuses actions/checkout@v4 efficiently
  3. ✅ Uses --frozen-lockfile (prevents dependency drift)
  4. ⚠️ Builds twice (base + PR) - unavoidable but documented

Suggestion: Consider caching pnpm store for faster installs (see pnpm/action-setup@v4 documentation).


🔒 Security Concerns

8. Permissions

permissions:
  contents: read
  pull-requests: write

Good practice! Following principle of least privilege. ✅


📝 Documentation & User Experience

9. Missing CHANGELOG Entry

Per CLAUDE.md:

Update CHANGELOG.md for user-visible changes only (features, bug fixes, breaking changes)

This is a user-facing feature (developers will see bundle size checks in PRs).

Add to CHANGELOG.md:

#### Developer Experience

[PR 2149](https://github.com/shakacode/react_on_rails/pull/2149) by [AbanoubGhadban](https://github.com/AbanoubGhadban): Add bundle size CI check using size-limit. PRs that increase bundle size by more than 0.5KB will now fail CI with a detailed report. Use `bin/skip-bundle-size-check` for intentional size increases.

10. User-Facing Documentation Needed

Users need to know:

  • What the bundle size check does
  • What the 0.5KB threshold means
  • When to use bin/skip-bundle-size-check
  • How to interpret failures

Consider adding documentation explaining the feature.


🧪 Test Coverage

11. No Automated Tests

The scripts/bundle-size.mjs has complex logic but no tests:

  • Argument parsing
  • Size formatting
  • Threshold comparison
  • File I/O error handling

Recommendation: Consider adding Jest tests for the utility functions.


🎯 Specific Implementation Notes

12. Magic Number Documentation

const DEFAULT_THRESHOLD = 512;

Consider adding a comment explaining why 512 bytes:

// Default threshold: 0.5 KB (512 bytes)
// This represents a ~2% increase for typical bundle sizes (20-30KB gzipped)
const DEFAULT_THRESHOLD = 512;

13. Handling New Config Entries

The workflow copies the PR config to the base branch. This is clever, but what happens when:

  • The PR adds new entries to .size-limit.json
  • The base branch has no measurements for those entries

Consider how set-limits handles entries without base sizes.


✅ What is Done Well

  1. Dynamic threshold calculation - Smart approach to avoid hardcoded limits
  2. Skip mechanism - Good escape hatch for intentional increases
  3. Comprehensive metrics - Tracking raw, gzip, and brotli sizes
  4. Local testing scripts - bin/compare-bundle-sizes is very useful
  5. Clean separation - Script logic separate from CI workflow
  6. Detailed output - The comparison table is very readable

📋 Action Items Before Merge

Must Fix:

  • Investigate and fix CI failures (size: FAILURE, build: FAILURE)
  • Add size-limit dependencies to package.json (if needed)
  • Test build scripts locally per CLAUDE.md guidelines
  • Add CHANGELOG entry
  • Complete PR checklist in description

Should Fix:

  • Add user documentation (README or dedicated doc)
  • Handle new config entries without base size
  • Remove unused CI_JOB_NUMBER env var if not needed

Nice to Have:

  • Add tests for bundle-size.mjs
  • Add pnpm caching to workflow
  • Document the 512-byte threshold rationale

Summary

This is a valuable addition that will help prevent bundle size regressions. The implementation is generally solid with good separation of concerns and useful developer tools.

Critical items to address:

  1. Fix failing CI checks
  2. Verify local testing per CLAUDE.md requirements
  3. Add documentation for users
  4. Complete CHANGELOG entry

Recommendation: Request changes for the critical issues, then approve after fixes.


Generated by Claude Code PR Review

AbanoubGhadban added a commit that referenced this pull request Nov 30, 2025
Add .size-limit.json with configuration for measuring bundle sizes of:
- react-on-rails (raw, gzip, brotli)
- react-on-rails-pro (raw, gzip, brotli)
- react-on-rails-pro-node-renderer (raw, gzip, brotli)
- Client bundled sizes for webpack imports

This is a prerequisite for the bundle size CI workflow in PR #2149.

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

Co-Authored-By: Claude <noreply@anthropic.com>
AbanoubGhadban added a commit that referenced this pull request Nov 30, 2025
## Summary
- Add `.size-limit.json` with configuration for measuring bundle sizes
of all packages
- Includes raw, gzip, and brotli measurements
- Includes webpack bundled sizes for client imports

This is a prerequisite for the bundle size CI workflow in PR #2149.

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

Co-authored-by: Claude <noreply@anthropic.com>
AbanoubGhadban and others added 11 commits November 30, 2025 21:14
- Install size-limit and @size-limit/file packages
- Add .size-limit.json configuration tracking all package outputs
- Create GitHub Actions workflow for PR comments with size comparison
- Add npm scripts: `pnpm run size` and `pnpm run size:json`

Bundle size limits:
- react-on-rails (full): 20 kB gzipped
- react-on-rails (client): 1 kB gzipped
- react-on-rails-pro (full): 45 kB gzipped
- react-on-rails-pro (client): 2 kB gzipped
- react-on-rails-pro-node-renderer: 15 kB gzipped

The CI will post comparison comments on PRs showing size changes.

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

Co-Authored-By: Claude <noreply@anthropic.com>
The size-limit tool only measures files, it doesn't build them.
Update the size scripts to run build before measuring.

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

Co-Authored-By: Claude <noreply@anthropic.com>
Compare all three compression levels for each package:
- Raw (uncompressed) - actual file size on disk
- Gzip - most common server compression
- Brotli - best compression, newer standard

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove static limits from .size-limit.json
- Workflow now fetches base branch sizes first
- Dynamically calculates limits as base_size + 512 bytes
- Supports any PR base branch, not just master
- Simplified to track only gzip sizes

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

Co-Authored-By: Claude <noreply@anthropic.com>
npx doesn't find pnpm-installed packages, causing CI failure.

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

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
AbanoubGhadban and others added 9 commits November 30, 2025 21:14
Add @size-limit/webpack to measure realistic bundle sizes when users
import from the packages:
- react-on-rails/client
- react-on-rails-pro/client
- react-on-rails-pro/registerServerComponent/client
- react-on-rails-pro/wrapServerComponentRenderer/client

Use "webpack": false for glob-based entries to prevent bundling server
files that have Node.js dependencies.

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

Co-Authored-By: Claude <noreply@anthropic.com>
Move github.head_ref from inline script interpolation to an environment
variable to prevent potential command injection attacks from malicious
branch names containing shell metacharacters.

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

Co-Authored-By: Claude <noreply@anthropic.com>
The base branch (master) may not have .size-limit.json config file.
Copy it from the PR branch before checking out and measuring the
base branch sizes.

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

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add verification step to check build artifacts exist before measuring
- Remove unreachable return statement before process.exit(1)

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

Co-Authored-By: Claude <noreply@anthropic.com>
The function calls process.exit(1) which never returns, making ESLint's
consistent-return rule a false positive. Added disable comment.

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

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

claude bot commented Nov 30, 2025

Code Review: Bundle Size CI Check

Overview

This PR adds automated bundle size checking to CI, building on the size-limit packages added in #2150. The implementation is well-thought-out with dynamic threshold-based checking and skip mechanisms.


✅ Strengths

  1. Smart Design Decisions

    • Dynamic limits (base + 0.5KB) instead of hardcoded values prevents false positives as bundles naturally grow
    • Skip mechanism via .bundle-size-skip-branch provides escape hatch for intentional size increases
    • Comprehensive measurement: raw, gzip, and brotli for all packages
    • Two-step workflow (check-skip → size) optimizes CI resource usage
  2. Good Developer Experience

    • bin/compare-bundle-sizes script enables local verification before pushing
    • Clear terminal output with colors and formatting
    • Helpful error messages and usage documentation
  3. Robust Implementation

    • Artifact verification step catches build failures early
    • Proper stashing/cleanup in bash scripts with trap handlers
    • JSON output mode for programmatic use

⚠️ Issues & Recommendations

1. Critical: Missing CHANGELOG Entry

Per CLAUDE.md requirements:

  • Required: Add entry to CHANGELOG.md (this is a user-visible improvement)
  • Format: PR 2149 by AbanoubGhadban
  • Category: Infrastructure/Developer Experience

2. PR Description Incomplete

The PR body still contains template placeholders. Please update with summary, how it works, and testing performed.

3. Code Issues in scripts/bundle-size.mjs

a) Missing Validation in formatSize():
The function does not validate for null/undefined/negative values. Add defensive checks.

b) Error Handling in readJsonFileOrExit():
Improve error messages by distinguishing between file-not-found, invalid JSON, and other errors.

4. Workflow Issues in .github/workflows/bundle-size.yml

a) Hardcoded Node Version:
Line 48 has node-version: 22 hardcoded. Consider using .nvmrc with node-version-file parameter.

b) Missing Error Handling:
The set-limits step could fail silently. Add explicit error handling.

c) Cache Opportunity:
Consider caching base branch node_modules to speed up CI (2-3 min savings).

5. Bash Script Issues

a) bin/compare-bundle-sizes - Error Suppression:
Lines 53-54 use || true which prevents failure detection. If build fails, script continues with invalid results. This is the most critical bug to fix.

b) Missing Branch Validation:
Add error handling if base branch does not exist.

6. Testing Gaps

Critical: Did you test the actual CI workflow on this PR branch? Recommended local tests:

  • bin/compare-bundle-sizes master
  • pnpm run build && pnpm exec size-limit --json > /tmp/test.json
  • node scripts/bundle-size.mjs set-limits --base /tmp/test.json

7. Documentation Needs

Consider adding docs/contributor-info/bundle-size-checks.md explaining how the CI check works and when to use the skip mechanism.


🔒 Security Considerations

✅ No major security issues identified.

Minor notes:

  1. .bundle-size-skip-branch file should be cleared before merge
  2. GitHub token permissions are appropriate

📋 Pre-Merge Checklist

Before merging:

  • Add CHANGELOG.md entry (REQUIRED per CLAUDE.md)
  • Update PR description (remove template placeholders)
  • Clear .bundle-size-skip-branch (should be empty on master)
  • Test CI workflow (critical - verify it actually works)
  • Fix error handling in bash scripts (the || true issue)
  • Run linting: bundle exec rubocop and pnpm run lint

Critical blockers:
❗ CHANGELOG entry (MANDATORY)
❗ Test the actual CI workflow
❗ Fix bash error suppression (|| true on lines 53-54)


Summary

This is solid infrastructure work that will help prevent bundle bloat! The main blockers are the missing CHANGELOG entry, testing the workflow, and fixing error suppression in the bash script.

The code quality is good overall. With the suggested improvements for error handling and documentation, this will be a valuable addition to the project.

Great work on the dynamic threshold approach - much better than hardcoded limits! 🎉


Generated with Claude Code

@claude
Copy link

claude bot commented Nov 30, 2025

Code Review: Bundle Size CI Check

Excellent work on implementing bundle size tracking! This is a valuable addition to the CI pipeline. Here's my detailed review:


✅ Strengths

1. Well-architected solution

  • Smart approach copying config from PR branch to base branch (addresses the "config does not exist on master" problem)
  • Dynamic limits (base + 0.5KB threshold) are much better than hardcoded limits
  • Two-job workflow design (check-skip → size) is clean and efficient
  • Great local development tooling (bin/compare-bundle-sizes)

2. Security conscious

  • Fixed the github.head_ref security warning by using environment variables (commit 58e158c)
  • Proper permissions set in workflow (contents: read, pull-requests: write)

3. Good error handling

  • Build artifact verification step (lines 78-90 in workflow)
  • Comprehensive error messages in bundle-size.mjs
  • Proper cleanup in bash scripts with trap handlers

4. Code quality

  • ESLint disable comment properly justified (process.exit(1) never returns)
  • Comprehensive JSDoc comments
  • Consistent ANSI color usage
  • Good separation of concerns (set-limits vs compare commands)

🔍 Issues & Suggestions

1. CRITICAL: PR Description is Empty ⚠️

The PR body still contains template boilerplate. Per CLAUDE.md: Update CHANGELOG.md for user-visible changes only (features, bug fixes, breaking changes...)

Action required:

  • Fill in the Summary section explaining what this PR does
  • Complete the Pull Request checklist
  • Update CHANGELOG.md (this is a user-facing feature!)

Suggested CHANGELOG entry:

#### Added
- Bundle size CI monitoring using size-limit. [PR 2149](https://github.com/shakacode/react_on_rails/pull/2149) by [AbanoubGhadban](https://github.com/AbanoubGhadban)
  - Tracks bundle sizes for all packages (raw, gzip, brotli)
  - CI fails if size increases by more than 0.5KB compared to base branch
  - Local comparison tool: bin/compare-bundle-sizes [base-branch]
  - Skip mechanism: bin/skip-bundle-size-check for intentional increases

2. Missing Test Coverage

There are no tests for the new functionality. Consider adding:

  • Unit tests for scripts/bundle-size.mjs functions
  • Integration test to verify the skip mechanism works
  • Test that bin/compare-bundle-sizes handles edge cases

3. Potential Race Condition in Cleanup

In bin/compare-bundle-sizes:27-33, if CURRENT_BRANCH is empty (detached HEAD state), the cleanup could fail silently. Add validation before git checkout.

4. Potential Issue: Base Branch May Not Have Dependencies

The workflow assumes the base branch has the same build dependencies. What if base branch does not have size-limit in package.json? Would likely fail during pnpm install --frozen-lockfile. Consider adding error handling or documenting this limitation.

5. Minor: Hardcoded Package Names

In workflow lines 81-85, package names are hardcoded. Consider extracting them dynamically from the config file.

6. Documentation: Usage Examples

The PR would benefit from:

  • README updates explaining the new CI check
  • Examples of what developers should do when the check fails
  • Explanation of when to use bin/skip-bundle-size-check

🔒 Security Considerations

Properly addressed:

  • Fixed github.head_ref injection risk (commit 58e158c)
  • No eval or unsafe string interpolation
  • Proper quoting in bash scripts

🚀 Performance Considerations

CI time impact: This adds a full build + measure cycle for both base and PR branches (~2-5 minutes). Mitigated by good path filtering, so overall acceptable for the value provided.


📋 Pre-merge Checklist

Per CLAUDE.md requirements:

  • Run bundle exec rubocop - Ensure all violations are fixed
  • Ensure files end with newlines - Check all new files
  • Update PR description - Fill in the template
  • Update CHANGELOG.md - Add entry for this feature
  • Add tests - At least basic smoke tests

🎯 Recommendation

Conditional approval - This is solid work, but please address:

  1. MUST FIX: Fill in PR description and checklist
  2. MUST FIX: Add CHANGELOG.md entry
  3. SHOULD FIX: Add basic tests
  4. NICE TO HAVE: Address the edge cases mentioned above

Once these are addressed, this will be a great addition to the project!


💡 Future Enhancements

Consider for follow-up PRs:

  • Historical size tracking over time
  • Per-commit size trends visualization
  • Different size budgets per package
  • Integration with bundle analyzer for detailed breakdown

Great job overall! The core implementation is solid and well-thought-out. 🎉

@claude
Copy link

claude bot commented Nov 30, 2025

Code Review: Bundle Size CI Check

Thank you for this comprehensive PR! This adds valuable CI infrastructure. Here's my detailed review:

✅ Strengths

Architecture & Design

  • Dynamic threshold approach: The base + 0.5KB threshold is smart - allows growth while preventing bloat
  • Separation of concerns: Clean split between workflow, utilities, and helper scripts
  • Skip mechanism: The .bundle-size-skip-branch approach is pragmatic for intentional size increases
  • Local testing tools: bin/compare-bundle-sizes enables developers to verify changes before pushing

Code Quality

  • Well-structured JavaScript: Good use of functions, clear variable names, proper error handling
  • Bash best practices: Proper use of set -e, cleanup traps, and color-coded output
  • Comprehensive coverage: Tests all 3 packages with multiple compression formats

⚠️ Issues to Address

1. CRITICAL: Incomplete PR Description

The PR body is still the template text. Per CLAUDE.md guidelines, you need to:

  • Explain why bundle size monitoring is needed
  • Justify the 0.5KB threshold choice
  • Provide testing evidence
  • Update CHANGELOG.md

2. CRITICAL: Missing CHANGELOG Entry

Per CLAUDE.md, user-visible changes need CHANGELOG entries. This is a developer tooling improvement that affects PR workflows.

Suggested entry:

#### Developer Experience
- [PR 2149](https://github.com/shakacode/react_on_rails/pull/2149) by [AbanoubGhadban](https://github.com/AbanoubGhadban): Add bundle size CI check with 0.5KB threshold. Use bin/compare-bundle-sizes to test locally or bin/skip-bundle-size-check to bypass for intentional increases.

3. CRITICAL: Security - Path Injection in Bash Scripts

In bin/compare-bundle-sizes line 51, branch names are used directly in git commands without validation. Add input validation to prevent command injection.

4. JavaScript: Magic Numbers

Line 21: DEFAULT_THRESHOLD = 512 needs a comment explaining why 0.5KB was chosen.

5. JavaScript: Inconsistent Return Pattern

Line 86: eslint-disable for consistent-return might be unnecessary since process.exit() terminates execution.

6. Missing Requirements Documentation

Add to bin script headers what's required (pnpm, size-limit, clean working directory).

🔍 Testing Concerns

Per CLAUDE.md CRITICAL REQUIREMENTS: "NEVER claim a test is fixed without running it locally first"

Please address in PR description:

  1. Have you manually triggered this workflow on a test PR?
  2. Have you tested the skip mechanism end-to-end?
  3. Have you tested bin/compare-bundle-sizes with edge cases?

🎯 Before Merging Checklist

  • Fill out PR description completely
  • Add CHANGELOG.md entry
  • Add input validation to bash scripts (security)
  • Document threshold choice in code comments
  • Add requirements documentation to script headers
  • Provide evidence of manual testing
  • Run bundle exec rubocop (mandatory per CLAUDE.md)
  • Confirm all files end with newline character

📊 Overall Assessment

Code Quality: 8/10 - Well-structured, clear intent, good patterns
Security: 6/10 - Path injection risks need addressing
Documentation: 4/10 - Missing PR description, CHANGELOG
Testing: Unknown - No evidence provided

Recommendation: Request changes for CRITICAL issues before merge. The implementation is solid, but needs process compliance and security hardening.

Great work on the implementation! The architecture is sound. 🚀

AbanoubGhadban and others added 2 commits November 30, 2025 21:22
- Add eslint-disable for consistent-return false positive (process.exit never returns)
- Add Bundle Size Checks section to CONTRIBUTING.md documenting:
  - How to run size checks locally
  - How to use bin/compare-bundle-sizes script
  - How to bypass the check for intentional increases
  - What packages get measured

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Add CHANGELOG entry for bundle size CI monitoring feature
- Document DEFAULT_THRESHOLD explaining it's intentionally strict

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

Co-Authored-By: Claude <noreply@anthropic.com>
@AbanoubGhadban AbanoubGhadban marked this pull request as ready for review November 30, 2025 19:31
@claude
Copy link

claude bot commented Nov 30, 2025

Code Review: Bundle Size CI Check

Thanks for this PR! This is a great addition to prevent unexpected bundle size regressions. I've reviewed the implementation and have some feedback organized by category:


Strengths

  1. Well-documented: Excellent documentation in CONTRIBUTING.md with clear usage examples
  2. Smart workflow design: Copying the PR's size-limit config to the base branch ensures consistency
  3. User-friendly tools: The bin/compare-bundle-sizes and bin/skip-bundle-size-check scripts are well-thought-out
  4. Good defaults: 0.5KB threshold is reasonable and strict enough to catch regressions
  5. Proper cleanup: The comparison script has proper trap handling for cleanup

🔍 Potential Issues

1. Critical: Build Artifact Verification Timing

The build artifact verification happens BEFORE measuring sizes, but it should also verify artifacts exist for the PR branch before running size-limit. Without this, size-limit might measure empty directories or fail cryptically.

2. Security: Shell Injection in skip-check script

The branch name is used directly without sanitization. While git branch names have restrictions, this could be hardened with regex validation.

3. Race Condition: Concurrent base branch changes

If the base branch is updated between checking out base and PR, the comparison might be against outdated sizes. Consider using github.event.pull_request.base.sha instead of github.base_ref to use the specific commit SHA.

4. Error Handling: Silent failures in compare script

The readJsonFileOrExit function exits silently on parse errors. Consider adding more context about what went wrong.


🎯 Minor Improvements

  1. Package.json: The globals package was moved (alphabetization). Not mentioned in PR description but appears intentional.

  2. Workflow: Consider adding pnpm caching to speed up CI (could save 30-60 seconds per run)

  3. Script: Missing JSDoc for public functions (setLimits, compare)

  4. Workflow: The skip notice only appears in workflow logs. Consider posting a PR comment to make it more visible to reviewers.


📝 Testing Recommendations

Before merging, please verify:

  1. Test the workflow with an actual size increase > 0.5KB to ensure it fails correctly
  2. Test the skip mechanism end-to-end
  3. Test bin/compare-bundle-sizes with uncommitted changes to verify stash/unstash works
  4. Verify build artifacts are in expected locations after the build step

🎓 Adherence to CLAUDE.md

  • ✅ Documentation added to CONTRIBUTING.md as required
  • ✅ CHANGELOG.md updated with proper PR link format
  • ⚠️ No mention of running bundle exec rubocop - please verify no Ruby linting issues
  • ⚠️ No mention of testing locally - per CLAUDE.md, you should document what testing was done
  • ✅ Scripts are executable
  • ✅ Files end with newlines

🚀 Recommendation

This is a solid PR with good architecture. The issues above are mostly minor, with issue #1 (PR build verification) being the most critical to address.

Must fix: Add build artifact verification for PR branch
Should fix: Use specific base commit SHA
Nice to have: Add pnpm caching, improve error messages

Overall: Approve with minor changes 👍

Copy link
Contributor

@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: 3

🧹 Nitpick comments (5)
bin/compare-bundle-sizes (1)

53-54: Suppressing errors may hide real build failures.

Using || true after pnpm install and pnpm run build will suppress genuine errors. If the build fails, the script will continue and produce misleading size comparisons.

Consider letting critical commands fail:

-pnpm install --frozen-lockfile 2>&1 | grep -v "^$" | head -5 || true
-pnpm run build 2>&1 | grep -v "^$" | tail -3 || true
+pnpm install --frozen-lockfile 2>&1 | grep -v "^$" | head -5
+pnpm run build 2>&1 | grep -v "^$" | tail -3

Or add explicit error handling to report which step failed.

scripts/bundle-size.mjs (2)

180-184: Consider handling new entries more explicitly.

When a current entry has no matching base entry (new package), it defaults to { size: 0 }, making any size appear as 100% increase. This is likely intentional (flag new large bundles), but consider logging a notice for clarity.

-    const base = baseSizes.find((b) => b.name === current.name) || { size: 0 };
+    const baseEntry = baseSizes.find((b) => b.name === current.name);
+    const base = baseEntry || { size: 0 };
+    const isNew = !baseEntry;

Then optionally mark new entries in the output.


240-240: Threshold display text is slightly confusing.

The text "Threshold: ${formatSize(threshold)} (base + ${formatSize(threshold)})" reads oddly since the second part just repeats the threshold value. Consider simplifying:

-    console.log(`Threshold: ${formatSize(threshold)} (base + ${formatSize(threshold)})`);
+    console.log(`Threshold: ${formatSize(threshold)} allowed increase per package`);
bin/skip-bundle-size-check (1)

1-34: Ensure skip file is always written at repo root

Right now SKIP_FILE=".bundle-size-skip-branch" is relative to the current working directory, so running bin/skip-bundle-size-check from a subdirectory will create the skip file in the wrong place and CI won’t see it. Consider resolving and cd‑ing to the Git repo root before writing:

-set -e
-
-SKIP_FILE=".bundle-size-skip-branch"
-BRANCH=$(git branch --show-current)
+set -e
+
+REPO_ROOT=$(git rev-parse --show-toplevel)
+cd "$REPO_ROOT"
+
+SKIP_FILE=".bundle-size-skip-branch"
+BRANCH=$(git branch --show-current)

Optionally, you could also harden the script with set -euo pipefail for better failure behavior. Also, please ensure this file ends with a trailing newline per the coding guidelines.

.github/workflows/bundle-size.yml (1)

22-34: Clarify .bundle-size-skip-branch format and parsing assumptions

The skip logic strips comments/blank lines and then removes all whitespace:

SKIP_BRANCH=$(grep -v '^[[:space:]]*#' "$SKIP_FILE" 2>/dev/null | grep -v '^[[:space:]]*$' | tr -d '[:space:]' || echo "")

This effectively assumes a single, whitespace‑free branch name in the file. If someone later adds multiple branch lines or extra text, they’ll get concatenated into one string, and matching may silently stop working.

Since the intended contract is “one branch per file,” consider:

  • documenting that explicitly in .bundle-size-skip-branch, and/or
  • guarding against multiple non‑comment lines (e.g., take only the first) to avoid surprising behavior.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b726df0 and 40fd2fc.

📒 Files selected for processing (8)
  • .bundle-size-skip-branch (1 hunks)
  • .github/workflows/bundle-size.yml (1 hunks)
  • CHANGELOG.md (1 hunks)
  • CONTRIBUTING.md (1 hunks)
  • bin/compare-bundle-sizes (1 hunks)
  • bin/skip-bundle-size-check (1 hunks)
  • package.json (1 hunks)
  • scripts/bundle-size.mjs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

ALWAYS ensure files end with a newline character before committing/pushing

Files:

  • bin/skip-bundle-size-check
  • scripts/bundle-size.mjs
  • bin/compare-bundle-sizes
  • CONTRIBUTING.md
  • package.json
  • CHANGELOG.md
🧠 Learnings (10)
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: The `react_on_rails_pro/` directory has its own Prettier/ESLint configuration and must be linted separately

Applied to files:

  • CONTRIBUTING.md
  • package.json
📚 Learning: 2025-02-12T16:38:06.537Z
Learnt from: Romex91
Repo: shakacode/react_on_rails PR: 1697
File: package-scripts.yml:28-28
Timestamp: 2025-02-12T16:38:06.537Z
Learning: The file `node_package/lib/ReactOnRails.full.js` is autogenerated during the build process and should not be present in the repository.

Applied to files:

  • CONTRIBUTING.md
📚 Learning: 2025-09-16T08:01:11.146Z
Learnt from: justin808
Repo: shakacode/react_on_rails PR: 1770
File: lib/generators/react_on_rails/templates/base/base/app/javascript/src/HelloWorld/ror_components/HelloWorld.client.jsx:2-2
Timestamp: 2025-09-16T08:01:11.146Z
Learning: React on Rails uses webpack CSS Modules configuration with namedExports: true, which requires the import syntax `import * as style from './file.module.css'` rather than the default export pattern. This configuration enables better tree shaking and bundle size optimization for CSS modules.

Applied to files:

  • CONTRIBUTING.md
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Applies to **/*.{rb,rake} : ALWAYS run `bundle exec rubocop` and fix ALL violations before every commit/push

Applied to files:

  • CONTRIBUTING.md
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Applies to lib/react_on_rails/*.rb : Create RBS signature files for new Ruby files in `lib/react_on_rails/` by adding corresponding `.rbs` file in `sig/react_on_rails/`, adding to Steepfile, and validating before committing

Applied to files:

  • CONTRIBUTING.md
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Applies to /CHANGELOG.md : Update `/CHANGELOG.md` for user-visible changes (features, bug fixes, breaking changes, deprecations, performance improvements) to the open-source React on Rails gem and npm package

Applied to files:

  • CONTRIBUTING.md
  • CHANGELOG.md
📚 Learning: 2025-04-26T21:55:55.874Z
Learnt from: alexeyr-ci2
Repo: shakacode/react_on_rails PR: 1732
File: spec/dummy/client/app-react16/startup/ReduxSharedStoreApp.client.jsx:40-44
Timestamp: 2025-04-26T21:55:55.874Z
Learning: In the react_on_rails project, files under `app-react16` directories are copied/moved to corresponding `/app` directories during the conversion process (removing the `-react16` suffix), which affects their relative import paths at runtime.

Applied to files:

  • CONTRIBUTING.md
📚 Learning: 2025-10-23T17:22:01.074Z
Learnt from: AbanoubGhadban
Repo: shakacode/react_on_rails PR: 1875
File: lib/react_on_rails/utils.rb:112-124
Timestamp: 2025-10-23T17:22:01.074Z
Learning: In React on Rails, when Pro is installed but not licensed, the intended behavior is to raise an error on boot. The `react_on_rails_pro?` method validates licenses and should raise errors early (including during path resolution in methods like `server_bundle?`) to enforce licensing requirements rather than failing later with obscure errors.

Applied to files:

  • CONTRIBUTING.md
📚 Learning: 2025-01-23T18:20:45.824Z
Learnt from: alexeyr-ci
Repo: shakacode/react_on_rails PR: 1687
File: spec/dummy/package.json:0-0
Timestamp: 2025-01-23T18:20:45.824Z
Learning: When adding or updating dependencies in spec/dummy/package.json, maintain version consistency with other package.json files in the codebase to avoid potential version conflicts.

Applied to files:

  • package.json
📚 Learning: 2025-11-25T08:05:17.804Z
Learnt from: CR
Repo: shakacode/react_on_rails PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T08:05:17.804Z
Learning: Applies to /CHANGELOG*.md : Use changelog format: `[PR 1818](https://github.com/shakacode/react_on_rails/pull/1818) by [username](https://github.com/username)` (no hash in PR number)

Applied to files:

  • CHANGELOG.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: package-js-tests
  • GitHub Check: rspec-dummy-app-node-renderer
  • GitHub Check: dummy-app-node-renderer-e2e-tests
  • GitHub Check: dummy-app-integration-tests (3.4, 22, latest)
  • GitHub Check: rspec-package-tests (3.4, latest)
  • GitHub Check: examples (3.4, latest)
  • GitHub Check: build
🔇 Additional comments (8)
.bundle-size-skip-branch (1)

1-6: LGTM!

Clear documentation for the bundle size skip mechanism. The file properly explains its purpose, usage, and when to use it.

CHANGELOG.md (1)

28-29: LGTM!

The changelog entry follows the correct format (no hash in PR number) and accurately describes the bundle size monitoring feature with all key capabilities.

CONTRIBUTING.md (1)

308-370: Documentation is comprehensive and well-structured.

Clear instructions for local testing, bypassing checks, and understanding what's measured. The guidance to document intentional size increases in PR descriptions is a good practice.

bin/compare-bundle-sizes (1)

27-35: Good cleanup trap implementation.

The cleanup function properly restores the working tree state and pops the stash when needed. Using 2>/dev/null || true for cleanup commands is appropriate since cleanup should be best-effort.

package.json (1)

49-49: No functional change - dependency reordering.

The globals entry appears to have been reordered alphabetically within devDependencies. No version or functional changes.

scripts/bundle-size.mjs (3)

38-43: LGTM - formatSize utility.

Clean implementation. For bundle size monitoring, KB granularity is appropriate.


102-132: setLimits command implementation is correct.

Properly reads base sizes, computes dynamic limits (base + threshold), and writes back to config. Good logging for debugging.


293-314: Main command dispatch is well-structured.

Clean switch statement with help fallback. Exits appropriately for unknown commands.

Comment on lines +56 to +77
# 1. Get PR's size-limit config first (base branch may not have it)
- name: Checkout PR branch for config
uses: actions/checkout@v4

- name: Save size-limit config
run: cp .size-limit.json /tmp/size-limit-config.json

# 2. Get base branch sizes
- name: Checkout base branch
uses: actions/checkout@v4
with:
ref: ${{ github.base_ref }}

- name: Copy size-limit config to base branch
run: cp /tmp/size-limit-config.json .size-limit.json

- name: Install base dependencies
run: pnpm install --frozen-lockfile

- name: Build base branch
run: pnpm run build

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check if the workflow file ends with a trailing newline
tail -c 1 .github/workflows/bundle-size.yml | od -An -tx1

Repository: shakacode/react_on_rails

Length of output: 110


🏁 Script executed:

# Get the file size and last few lines to understand the ending
wc -l .github/workflows/bundle-size.yml
tail -5 .github/workflows/bundle-size.yml | cat -A

Repository: shakacode/react_on_rails

Length of output: 267


🌐 Web query:

size-limit behavior missing target files npm package

💡 Result:

Likely cause

  • Size Limit reports "missing target files" when the config "path" (or glob) doesn't match any files — e.g., you run size-limit before your build produces the bundle, the glob is wrong, or you asked Size Limit to use webpack but your project already has no bundle to inspect. (npmjs.com)

Quick fixes to try

  1. Make sure you build before running size-limit (add "npm run build && size-limit" or run your build step in CI). (npmjs.com)
  2. Verify the config "path" matches actual files (try the glob on the shell or point to the exact file). If using patterns, ensure they expand in the CI environment. (npmjs.com)
  3. If your project is an application with its own bundler, set "webpack": false in the size-limit section so Size Limit checks the produced bundle instead of trying to build one. If you want Size Limit to create a bundle for a library, leave webpack enabled or use the @size-limit/webpack plugin. (npmjs.com)
  4. Add an explicit entry array (entry) or use the @size-limit/file plugin for checking specific files if needed. (npmjs.com)

If that doesn't help

  • Run size-limit locally with verbose/--why to get more details and confirm which path(s) are failing, and paste the exact error + your .size-limit / package.json config if you want me to inspect it. (npmjs.com)

Sources

  • size-limit README and config docs (npm / GitHub). (npmjs.com)

Citations:


🏁 Script executed:

# Search the codebase for how size-limit is configured and used
rg "size-limit" --type yaml --type json -A 2 -B 2

Repository: shakacode/react_on_rails

Length of output: 3685


🏁 Script executed:

# Check if there are any test cases or scripts that show size-limit error handling
rg "size-limit.*error\|missing.*target" -i

Repository: shakacode/react_on_rails

Length of output: 50


🏁 Script executed:

# Check the .size-limit.json file to understand its structure
cat .size-limit.json

Repository: shakacode/react_on_rails

Length of output: 3062


🏁 Script executed:

# Check the bundle-size.mjs script to see how it handles size-limit execution
cat scripts/bundle-size.mjs

Repository: shakacode/react_on_rails

Length of output: 9246


🏁 Script executed:

# View the full workflow file to understand the complete logic and error handling
cat .github/workflows/bundle-size.yml

Repository: shakacode/react_on_rails

Length of output: 3402


🏁 Script executed:

# Check if the "Verify build artifacts" step is part of the reviewed code (lines 56-77)
# The snippet shows lines 56-77, let's count and see where verify step falls
sed -n '56,77p' .github/workflows/bundle-size.yml

Repository: shakacode/react_on_rails

Length of output: 734


🏁 Script executed:

# Get line numbers of key steps to understand the code review scope
grep -n "Measure base branch sizes\|Verify build artifacts" .github/workflows/bundle-size.yml

Repository: shakacode/react_on_rails

Length of output: 150


Size-limit may fail when PR adds new bundle entries not present on base

You copy the PR's .size-limit.json to the base branch and measure sizes without checking whether all configured paths exist. If a PR introduces new bundle entries pointing to files that don't exist on the base branch, size-limit will error before producing base-sizes.json, breaking the job.

While the workflow includes a "Verify build artifacts" step (line 78), it only checks the three existing packages and doesn't validate all entries in the .size-limit.json config. Consider either:

  • Extending the verify step to check all configured paths, or
  • Falling back to the base branch's own .size-limit.json for measurement if the PR's config is incompatible.
🤖 Prompt for AI Agents
In .github/workflows/bundle-size.yml around lines 56 to 77, the workflow blindly
copies the PR's .size-limit.json onto the checked-out base branch which will
cause size-limit to fail if the PR added new bundle entry paths that don't exist
on the base; add a validation step after "Copy size-limit config to base branch"
that parses /tmp/size-limit-config.json and verifies every configured path/file
exists in the checked-out base branch, and if any are missing restore the base
branch's own .size-limit.json (or skip overwriting) so size measurements run
against a compatible config; alternatively (or additionally) extend the later
"Verify build artifacts" step to iterate over all entries from the active
.size-limit.json and fail early with a clear message if any paths are absent
before invoking size-limit.

set -e

BASE_BRANCH="${1:-master}"
CURRENT_BRANCH=$(git branch --show-current)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Detached HEAD state may cause issues in CI environments.

git branch --show-current returns an empty string in detached HEAD state, which is common in CI. This would cause the cleanup function and the checkout back to the current branch to fail silently or behave unexpectedly.

Consider adding a fallback to use the commit SHA:

-CURRENT_BRANCH=$(git branch --show-current)
+CURRENT_BRANCH=$(git branch --show-current)
+if [ -z "$CURRENT_BRANCH" ]; then
+  # Fallback to commit SHA for detached HEAD (common in CI)
+  CURRENT_BRANCH=$(git rev-parse HEAD)
+fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
CURRENT_BRANCH=$(git branch --show-current)
CURRENT_BRANCH=$(git branch --show-current)
if [ -z "$CURRENT_BRANCH" ]; then
# Fallback to commit SHA for detached HEAD (common in CI)
CURRENT_BRANCH=$(git rev-parse HEAD)
fi
🤖 Prompt for AI Agents
In bin/compare-bundle-sizes around line 19, CURRENT_BRANCH is set using git
branch --show-current which yields an empty string in detached HEAD CI runs;
change the logic to record a safe fallback (use git rev-parse --short HEAD or
git rev-parse --verify HEAD) if the branch name is empty, store that ref in
CURRENT_BRANCH, and update any cleanup/checkout code to handle restoring either
a branch name or the commit SHA accordingly (i.e., if CURRENT_BRANCH is
empty-string fallback then checkout the saved commit SHA). Ensure the script
treats the saved ref consistently everywhere it currently uses CURRENT_BRANCH.

Comment on lines +343 to +344
bin/compare-bundle-sizes --hierarchical # Group results by package
```
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

The --hierarchical flag is documented but not implemented.

The bin/compare-bundle-sizes script doesn't pass the --hierarchical flag to the underlying scripts/bundle-size.mjs, and the Node script doesn't have this option implemented. Either remove this from the documentation or implement the feature.

 Options:
 
 ```sh
 bin/compare-bundle-sizes main        # Compare against 'main' instead of 'master'
-bin/compare-bundle-sizes --hierarchical  # Group results by package

<details>
<summary>🤖 Prompt for AI Agents</summary>

In CONTRIBUTING.md around lines 343-344 the docs mention a --hierarchical flag
that is not implemented; either remove the example or implement it. To
implement: update bin/compare-bundle-sizes to forward the --hierarchical flag
(and any value) to scripts/bundle-size.mjs when spawning/execing the Node
script, and modify scripts/bundle-size.mjs to accept and parse a --hierarchical
boolean option from process.argv (or the existing arg parser) and implement the
grouping logic (or toggle an existing code path) so that when --hierarchical is
present results are grouped by package; alternatively, if you prefer not to
implement, remove the --hierarchical example line from CONTRIBUTING.md so docs
reflect current behavior.


</details>

<!-- fingerprinting:phantom:medusa:ocelot -->

<!-- This is an auto-generated comment by CodeRabbit -->

@claude
Copy link

claude bot commented Dec 1, 2025

Code Review: Bundle Size CI Check

Overall Assessment

Excellent PR! This is a well-implemented feature that adds automated bundle size monitoring to the CI pipeline. The implementation is clean, well-documented, and follows best practices.

Strengths

  1. Smart Two-Stage Workflow Design

    • Separate check-skip job allows early exit, saving CI resources when a branch is marked to skip
    • Clean dependency management with needs: check-skip
  2. Robust Configuration Handling

    • Clever approach: copies .size-limit.json from PR branch to base branch
    • Handles scenario where base branch may not have the config file yet
    • Uses dynamic limits (base + 0.5KB) rather than static thresholds
  3. Comprehensive Tooling

    • bin/compare-bundle-sizes: Local comparison tool with proper cleanup
    • bin/skip-bundle-size-check: Easy bypass mechanism for intentional increases
    • scripts/bundle-size.mjs: Well-structured CLI with multiple commands
  4. Excellent Documentation

    • Clear CONTRIBUTING.md section with usage examples
    • Changelog entry follows project conventions
    • Inline comments in scripts are helpful
  5. Code Quality

    • Good error handling (e.g., readJsonFileOrExit)
    • Proper use of ANSI colors for output formatting
    • Clean bash script with proper cleanup traps

Minor Issues and Suggestions

1. Missing Build Artifact Verification

In .github/workflows/bundle-size.yml:86-95, you verify build artifacts exist for the base branch. Consider adding the same verification after building the PR branch (around line 102) for symmetry and to catch issues on both branches.

2. Hardcoded Threshold (Design Choice)

scripts/bundle-size.mjs:22 defines a 0.5KB threshold for all packages. Consider whether this is appropriate for all package sizes - it might be too strict for small utilities or too lenient for large bundles. This could be a future enhancement to make configurable per-package.

3. Grep Pattern Fragility

.github/workflows/bundle-size.yml:28 uses tr -d [:space:] which removes ALL whitespace, including within branch names. Consider using xargs instead to trim only leading/trailing whitespace while preserving internal spaces.

4. Package.json Change

The only change in package.json is alphabetically sorting globals. This is fine but unrelated to the PR main purpose - consider mentioning this in the PR description.

5. Error Handling in bin/compare-bundle-sizes

Line 51: If neither checkout succeeds, the script continues silently. The second git checkout should exit on failure with a clear error message.

6. CI Path Filters

Consider adding scripts/bundle-size.mjs to the workflow path filters, so changes to the size comparison logic trigger the workflow for validation.

Security Considerations

No security concerns identified

  • No credential handling
  • No external API calls
  • Proper use of GitHub Actions permissions

Performance Considerations

Well optimized

  • Early exit via check-skip job saves resources
  • Uses --frozen-lockfile for reproducible installs

Potential improvement: Consider caching pnpm store to speed up installs by 30-60 seconds.

Test Coverage

Adequate for infrastructure PR

  • The workflow itself serves as the test
  • Local tooling is verifiable manually
  • CI is passing

Compliance with CLAUDE.md

Follows all guidelines

  • Changelog updated correctly
  • Documentation added to CONTRIBUTING.md
  • No linting issues
  • Proper bash scripting conventions

Final Recommendation

APPROVED ✅ with minor suggestions for future improvement.

This PR is production-ready. The issues mentioned above are minor and can be addressed in follow-up PRs if desired. The core functionality is solid, well-tested, and well-documented.


Questions for the author:

  1. Have you tested the bypass mechanism in a real PR?
  2. Have you tested what happens when base branch is missing build artifacts?
  3. What was the rationale for choosing 0.5KB as the threshold?

Great work, @AbanoubGhadban! This will be valuable for preventing bundle size regressions. 🎉

@claude
Copy link

claude bot commented Dec 1, 2025

Code Review: Bundle Size CI Check

Thanks for this excellent addition! This is a valuable feature for preventing bundle size regressions.


✅ Strengths

Architecture & Design

  • Smart dynamic threshold approach: Using base + 0.5KB instead of hardcoded limits
  • Good separation of concerns: CLI scripts, GitHub workflow, and comparison logic are well-separated
  • Bypass mechanism: The .bundle-size-skip-branch approach is clean and well-documented
  • Local testing support: bin/compare-bundle-sizes mirrors CI behavior perfectly

Code Quality

  • Excellent error handling: Scripts handle missing files, detached HEAD, and edge cases gracefully
  • User-friendly output: Color-coded tables, clear status messages, and helpful error messages
  • Proper cleanup: The compare-bundle-sizes script uses trap for cleanup on exit
  • Good documentation: CONTRIBUTING.md additions are thorough and include examples

🔍 Potential Issues & Suggestions

1. Missing Newline Requirement Violation ⚠️

Files: bin/compare-bundle-sizes, bin/skip-bundle-size-check, scripts/bundle-size.mjs

Per CLAUDE.md: "ALWAYS ensure files end with a newline character"

All three scripts are missing trailing newlines. This will cause linting failures.

Fix: Add newlines to end of these files.

2. Stash Safety in compare-bundle-sizes ⚠️

File: bin/compare-bundle-sizes:44-46

If stashing fails (e.g., untracked files that conflict), the script continues without setting STASHED=true, but the cleanup trap will attempt to pop a non-existent stash.

Recommendation: Check stash success and handle failures gracefully.

3. Globals Package Reordering 🤔

File: package.json

The diff shows globals was moved from line 37 to line 46. This appears unrelated to the bundle size feature.

Question: Was this an accidental alphabetization? If intentional, should be mentioned in the PR description.

4. Workflow Triggers May Be Too Broad 🤔

File: .github/workflows/bundle-size.yml:5-10

This triggers on ANY change to packages/**, including Ruby gem files, test files, and documentation.

Recommendation: Narrow to only JS/TS build inputs to avoid unnecessary CI runs.

5. Threshold Consistency 📝

The threshold is hardcoded as 512 bytes in multiple places. Consider making it configurable via environment variable for easier adjustments.


🧪 Test Coverage

Status: N/A (CI workflow)

This is infrastructure code, so traditional unit tests don't apply. The scripts/bundle-size.mjs could potentially have unit tests for the comparison logic.


🔒 Security Considerations

✅ No issues identified

  • Scripts properly handle user input
  • No arbitrary code execution risks
  • GitHub token permissions are appropriately scoped

⚡ Performance Considerations

The workflow is well-optimized with skip checks. Potential improvement: cache base build artifacts between runs since the workflow builds twice (base + PR).


📚 Documentation

✅ Excellent documentation in CONTRIBUTING.md

Minor suggestion: Add a troubleshooting section for common issues.


🎯 Required Changes

Before merging:

  1. Add trailing newlines to all three scripts
  2. Fix stash error handling in bin/compare-bundle-sizes
  3. Run bundle exec rubocop to verify no linting issues

💡 Recommended Enhancements (Optional)

  1. Make threshold configurable via environment variable
  2. Narrow workflow triggers to only JS/TS source files
  3. Add more specific build artifact verification

Overall Assessment

Rating: ⭐⭐⭐⭐ (Excellent with minor fixes needed)

This is a valuable addition that will help prevent bundle size regressions. The implementation is well-thought-out, user-friendly, and follows React on Rails conventions. The required fixes are minor formatting issues.

Great work! 🎉

@AbanoubGhadban AbanoubGhadban merged commit 3253096 into master Dec 2, 2025
33 checks passed
@AbanoubGhadban AbanoubGhadban deleted the feature/bundle-size-ci branch December 2, 2025 09:15
justin808 pushed a commit that referenced this pull request Dec 5, 2025
## Summary
- Add size-limit and its plugins (@size-limit/file, @size-limit/webpack)
to enable bundle size measurement
- Add `size` and `size:json` npm scripts for local bundle size checking

This is a prerequisite for the bundle size CI workflow in PR #2149.

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

Co-authored-by: Claude <noreply@anthropic.com>
justin808 pushed a commit that referenced this pull request Dec 5, 2025
## Summary
- Add `.size-limit.json` with configuration for measuring bundle sizes
of all packages
- Includes raw, gzip, and brotli measurements
- Includes webpack bundled sizes for client imports

This is a prerequisite for the bundle size CI workflow in PR #2149.

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

Co-authored-by: Claude <noreply@anthropic.com>
justin808 pushed a commit that referenced this pull request Dec 5, 2025
## Summary

Add automated bundle size monitoring to CI using
[size-limit](https://github.com/ai/size-limit). This helps prevent
unexpected bundle size regressions by comparing PR bundle sizes against
the base branch.

### How It Works

1. CI checks out the base branch and measures bundle sizes
2. CI checks out the PR branch and measures bundle sizes
3. Compares sizes - fails if any package increases by more than 0.5KB
4. Posts a size report comment on the PR

### What Gets Measured

- **react-on-rails**: Raw, gzip, and brotli compressed sizes
- **react-on-rails-pro**: Raw, gzip, and brotli compressed sizes  
- **react-on-rails-pro-node-renderer**: Raw, gzip, and brotli compressed
sizes
- **Webpack bundled imports**: Client-side bundle sizes when importing
via webpack

### Local Testing

```sh
# Check current bundle sizes
pnpm run size

# Compare your branch against master
bin/compare-bundle-sizes
```

### Bypassing the Check

For intentional size increases (e.g., adding new features):

```sh
bin/skip-bundle-size-check
git add .bundle-size-skip-branch
git commit -m "Skip bundle size check for intentional size increase"
git push
```

## Pull Request checklist
- [x] Add/update test to cover these changes - N/A (CI workflow)
- [x] Update documentation - Added to CONTRIBUTING.md
- [x] Update CHANGELOG file

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Automated bundle size CI monitoring compares PR bundle sizes against
the base branch and fails if any package exceeds a 0.5KB growth
threshold.
  * Added bypass mechanism for intentional bundle size increases.

* **Documentation**
  * Bundle size checking and comparison commands documented.
* Local tooling available to measure and compare package sizes against a
base branch.

* **Chores**
  * Bundle size monitoring workflow set up for CI.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants