Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
34f5412
Add bundle size CI check using size-limit
AbanoubGhadban Nov 30, 2025
a422fe6
Ensure size scripts build packages first
AbanoubGhadban Nov 30, 2025
fd56f7a
Track raw, gzip, and brotli bundle sizes
AbanoubGhadban Nov 30, 2025
f727385
Use dynamic bundle size limits (base branch + 0.5KB)
AbanoubGhadban Nov 30, 2025
7cf319d
Trigger CI with new base branch
AbanoubGhadban Nov 30, 2025
d26de94
Fix: Use pnpm exec instead of npx for size-limit
AbanoubGhadban Nov 30, 2025
25f3766
Test: Add bloat data to verify bundle size CI fails on increases
AbanoubGhadban Nov 30, 2025
451924c
Revert "Test: Add bloat data to verify bundle size CI fails on increa…
AbanoubGhadban Nov 30, 2025
dbb3907
Track raw, gzip, and brotli bundle sizes
AbanoubGhadban Nov 30, 2025
4ba4dff
Reapply "Test: Add bloat data to verify bundle size CI fails on incre…
AbanoubGhadban Nov 30, 2025
a122bb9
Revert "Reapply "Test: Add bloat data to verify bundle size CI fails …
AbanoubGhadban Nov 30, 2025
8d48b13
Add local bundle size comparison script
AbanoubGhadban Nov 30, 2025
527b8fb
Add bundle-size.mjs utility script
AbanoubGhadban Nov 30, 2025
afcbf70
Refactor: Use bundle-size.mjs script in workflow and local script
AbanoubGhadban Nov 30, 2025
b1c46b8
Add skip-bundle-size-check script for bypassing size check
AbanoubGhadban Nov 30, 2025
0b5fea6
Skip bundle size check for feature/bundle-size-ci
AbanoubGhadban Nov 30, 2025
fc592d6
Revert "Skip bundle size check for feature/bundle-size-ci"
AbanoubGhadban Nov 30, 2025
277fea8
Add webpack bundled size checks for client imports
AbanoubGhadban Nov 30, 2025
89fc846
Empty commit
AbanoubGhadban Nov 30, 2025
cc0c564
Test: Add bloat data to verify bundle size CI fails on increases
AbanoubGhadban Nov 30, 2025
8374d77
Revert "Test: Add bloat data to verify bundle size CI fails on increa…
AbanoubGhadban Nov 30, 2025
58e158c
Fix security warning for github.head_ref in bundle-size workflow
AbanoubGhadban Nov 30, 2025
818a710
Fix bundle-size CI: copy config from PR branch before measuring base
AbanoubGhadban Nov 30, 2025
90b84c7
Make bundle size scripts executable
AbanoubGhadban Nov 30, 2025
fe55a99
Add build artifact verification and fix script error handling
AbanoubGhadban Nov 30, 2025
7468b45
Fix ESLint consistent-return warning in bundle-size script
AbanoubGhadban Nov 30, 2025
4bcadfc
Fix ESLint warning and add bundle size documentation
AbanoubGhadban Nov 30, 2025
40fd2fc
Add CHANGELOG entry and document threshold value
AbanoubGhadban Nov 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .bundle-size-skip-branch
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This file allows skipping the bundle size CI check for a specific branch.
# When a branch name in this file matches the PR branch, the size check is skipped.
#
# Usage: Run `bin/skip-bundle-size-check` to set the current branch, then commit and push.
#
# This is useful when you have an intentional size increase that exceeds the 0.5KB threshold.
115 changes: 115 additions & 0 deletions .github/workflows/bundle-size.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
name: Bundle Size

on:
pull_request:
paths:
- 'packages/**'
- 'package.json'
- 'pnpm-lock.yaml'
- '.size-limit.json'
- '.github/workflows/bundle-size.yml'
- '.bundle-size-skip-branch'

jobs:
check-skip:
runs-on: ubuntu-22.04
outputs:
skip: ${{ steps.skip-check.outputs.skip }}
steps:
- name: Checkout PR branch
uses: actions/checkout@v4

- name: Check if branch should skip size check
id: skip-check
env:
BRANCH: ${{ github.head_ref }}
run: |
SKIP_FILE=".bundle-size-skip-branch"
SKIP_BRANCH=$(grep -v '^[[:space:]]*#' "$SKIP_FILE" 2>/dev/null | grep -v '^[[:space:]]*$' | tr -d '[:space:]' || echo "")
if [ "$SKIP_BRANCH" = "$BRANCH" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "::notice::Branch '$BRANCH' is set to skip size check"
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
size:
needs: check-skip
if: needs.check-skip.outputs.skip != 'true'
runs-on: ubuntu-22.04
permissions:
contents: read
pull-requests: write
env:
CI_JOB_NUMBER: 1
steps:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22'

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9

# 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

Comment on lines +56 to +77
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.

- name: Verify build artifacts
run: |
missing=0
for pkg in react-on-rails react-on-rails-pro react-on-rails-pro-node-renderer; do
if ! ls packages/$pkg/lib/*.js >/dev/null 2>&1; then
echo "::error::Missing build artifacts in packages/$pkg/lib/"
missing=1
fi
done
if [ $missing -eq 1 ]; then
exit 1
fi
echo "All build artifacts verified"
- name: Measure base branch sizes
run: |
pnpm exec size-limit --json > /tmp/base-sizes.json
echo "Base branch sizes:"
cat /tmp/base-sizes.json
# 3. Checkout PR and set dynamic limits
- name: Checkout PR branch
uses: actions/checkout@v4

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

- name: Set dynamic limits (base + 0.5KB)
run: node scripts/bundle-size.mjs set-limits --base /tmp/base-sizes.json

# 4. Run the action with dynamic limits
- name: Check bundle size
uses: andresz1/size-limit-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
package_manager: pnpm
build_script: build
skip_step: install
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Changes since the last non-beta release.

#### Added

- **Bundle Size CI Monitoring**: Added automated bundle size tracking to CI using size-limit. Compares PR bundle sizes against the base branch and fails if any package increases by more than 0.5KB. Includes local comparison tool (`bin/compare-bundle-sizes`) and bypass mechanism (`bin/skip-bundle-size-check`) for intentional size increases. [PR 2149](https://github.com/shakacode/react_on_rails/pull/2149) by [AbanoubGhadban](https://github.com/AbanoubGhadban).

- **Service Dependency Checking for bin/dev**: Added optional `.dev-services.yml` configuration to validate required external services (Redis, PostgreSQL, Elasticsearch, etc.) are running before `bin/dev` starts the development server. Provides clear error messages with start commands and install hints when services are missing. Zero impact if not configured - backwards compatible with all existing installations. [PR 2098](https://github.com/shakacode/react_on_rails/pull/2098) by [justin808](https://github.com/justin808).

#### Changed
Expand Down
63 changes: 63 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,69 @@ Run only ESLint:
pnpm run lint
```

### Bundle Size Checks

React on Rails monitors bundle sizes in CI to prevent unexpected size increases. The CI compares your PR's bundle sizes against the base branch and fails if any package increases by more than 0.5KB.

#### Running Locally

Check current bundle sizes:

```sh
pnpm run size
```

Get JSON output for programmatic use:

```sh
pnpm run size:json
```

Compare your branch against the base branch:

```sh
bin/compare-bundle-sizes
```

This script automatically:

1. Stashes any uncommitted changes
2. Checks out and builds the base branch (default: `master`)
3. Checks out and builds your current branch
4. Compares the sizes and shows a detailed report

Options:

```sh
bin/compare-bundle-sizes main # Compare against 'main' instead of 'master'
bin/compare-bundle-sizes --hierarchical # Group results by package
```
Comment on lines +343 to +344
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 -->


#### Bypassing the Check

If your PR intentionally increases bundle size (e.g., adding a new feature), you can skip the bundle size check:

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

This sets your branch to skip the size check. The skip only applies to the specific branch name written to `.bundle-size-skip-branch`.

**Important**: Only skip the check when the size increase is justified. Document why the increase is acceptable in your PR description.

#### What Gets Measured

The CI measures sizes for:

- **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

### Starting the Dummy App

To run the dummy app, it's **CRITICAL** to not just run `rails s`. You have to run `foreman start` with one of the Procfiles. If you don't do this, then `webpack` will not generate a new bundle, and you will be seriously confused when you change JavaScript and the app does not change. If you change the Webpack configs, then you need to restart Foreman. If you change the JS code for react-on-rails, you need to run `pnpm run build` in the project root.
Expand Down
69 changes: 69 additions & 0 deletions bin/compare-bundle-sizes
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env bash
#
# Compare bundle sizes between current branch and a base branch
#
# Usage:
# bin/compare-bundle-sizes [base-branch]
#
# Arguments:
# base-branch The branch to compare against (default: master)
#
# Examples:
# bin/compare-bundle-sizes # Compare against master
# bin/compare-bundle-sizes develop # Compare against develop
# bin/compare-bundle-sizes feature/some-branch

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.

STASHED=false

# Colors for output
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

cleanup() {
echo -e "\n${BLUE}Cleaning up...${NC}"
git checkout "$CURRENT_BRANCH" --quiet 2>/dev/null || true
if [ "$STASHED" = true ]; then
git stash pop --quiet 2>/dev/null || true
fi
}

trap cleanup EXIT

echo -e "${BLUE}📦 Bundle Size Comparison${NC}"
echo -e " Current branch: ${YELLOW}$CURRENT_BRANCH${NC}"
echo -e " Base branch: ${YELLOW}$BASE_BRANCH${NC}"
echo ""

# Check for uncommitted changes
if ! git diff --quiet || ! git diff --cached --quiet; then
echo -e "${YELLOW}Stashing uncommitted changes...${NC}"
git stash push -m "compare-bundle-sizes temp stash" --quiet
STASHED=true
fi

# Get base branch sizes
echo -e "${BLUE}Building base branch ($BASE_BRANCH)...${NC}"
git fetch origin "$BASE_BRANCH" --quiet 2>/dev/null || true
git checkout "$BASE_BRANCH" --quiet 2>/dev/null || git checkout "origin/$BASE_BRANCH" --quiet
pnpm install --frozen-lockfile 2>&1 | grep -v "^$" | head -5 || true
pnpm run build 2>&1 | grep -v "^$" | tail -3 || true

echo -e "${BLUE}Measuring base branch sizes...${NC}"
pnpm exec size-limit --json > /tmp/base-sizes.json

# Get current branch sizes
echo -e "${BLUE}Building current branch ($CURRENT_BRANCH)...${NC}"
git checkout "$CURRENT_BRANCH" --quiet
pnpm install --frozen-lockfile 2>&1 | grep -v "^$" | head -5 || true
pnpm run build 2>&1 | grep -v "^$" | tail -3 || true

echo -e "${BLUE}Measuring current branch sizes...${NC}"
pnpm exec size-limit --json > /tmp/current-sizes.json

# Compare sizes using the bundle-size script
node scripts/bundle-size.mjs compare --base /tmp/base-sizes.json --current /tmp/current-sizes.json
34 changes: 34 additions & 0 deletions bin/skip-bundle-size-check
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/env bash
#
# Skip bundle size check for current branch
#
# Usage:
# bin/skip-bundle-size-check
#

set -e

SKIP_FILE=".bundle-size-skip-branch"
BRANCH=$(git branch --show-current)

if [ -z "$BRANCH" ]; then
echo "Error: Not on a branch (detached HEAD?)"
exit 1
fi

# Write comment header and branch name
cat > "$SKIP_FILE" << EOF
# This file allows skipping the bundle size CI check for a specific branch.
# When a branch name in this file matches the PR branch, the size check is skipped.
#
# Usage: Run \`bin/skip-bundle-size-check\` to set the current branch, then commit and push.
#
# This is useful when you have an intentional size increase that exceeds the 0.5KB threshold.
$BRANCH
EOF
echo "Set '$BRANCH' as the branch to skip bundle size check"
echo ""
echo "Next steps:"
echo " git add $SKIP_FILE"
echo " git commit -m 'Skip bundle size check for $BRANCH'"
echo " git push"
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
"@types/react-dom": "^18.3.5",
"@types/turbolinks": "^5.2.2",
"create-react-class": "^15.7.0",
"globals": "^16.2.0",
"eslint": "^9.24.0",
"eslint-config-prettier": "^10.1.1",
"eslint-config-shakacode": "^19.0.0",
Expand All @@ -47,6 +46,7 @@
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-testing-library": "^7.1.1",
"globals": "^16.2.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-fetch-mock": "^3.0.3",
Expand Down
Loading
Loading