Skip to content

fix: add privateOutputPath computed property to JS config#891

Merged
justin808 merged 5 commits intomainfrom
ihabadham/fix/add-private-output-path-js-config
Feb 15, 2026
Merged

fix: add privateOutputPath computed property to JS config#891
justin808 merged 5 commits intomainfrom
ihabadham/fix/add-private-output-path-js-config

Conversation

@ihabadham
Copy link
Copy Markdown
Contributor

@ihabadham ihabadham commented Feb 14, 2026

Summary

Fixes #890 — The private_output_path feature (PR #592 / #604) added the Ruby-side Shakapacker::Configuration#private_output_path method but not the corresponding JS-side computed property. This caused config.privateOutputPath to always be undefined, breaking config sync for consumers like React on Rails.

Changes

  • package/config.ts — Compute config.privateOutputPath as an absolute path from config.private_output_path, following the same pattern as config.outputPath
  • package/types.ts — Add privateOutputPath?: string to the Config interface
  • test/package/config.test.js — Add test verifying privateOutputPath resolves to an absolute path

How it was found

React on Rails' generated serverWebpackConfig.js (PR #2028) uses config.privateOutputPath for the server bundle output path. Since the property was always undefined:

  1. A false warning fires on every build: "Shakapacker 9.0+ detected but private_output_path not configured"
  2. Changing private_output_path in shakapacker.yml has no effect on webpack output — always falls back to hardcoded path

User report: shakacode/react_on_rails#2289 (comment)

Test plan

  • yarn jest test/package/config.test.js — 13/13 passing
  • yarn jest — 347/347 passing
  • yarn build — TypeScript compiles clean
  • Verified in a real Rails + React on Rails test app: warning gone, config.privateOutputPath returns correct absolute path

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Optional private output path support added; when provided it is exposed and resolved to an absolute path for more predictable builds.
  • Tests

    • Added tests confirming the private output path resolves to an absolute path when configured and remains unset when not provided.

The private_output_path feature (PR #592) added the Ruby-side method but
not the JS-side computed property. This caused consumers like React on
Rails to always get undefined for config.privateOutputPath, breaking
config sync and producing false warnings on every build.

Follows the same pattern as config.outputPath: resolves the raw YAML
string to an absolute path.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 14, 2026

Warning

Rate limit exceeded

@justin808 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 9 minutes and 56 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

Walkthrough

Adds an optional camelCase privateOutputPath to the exported Config, computed as resolve(config.private_output_path) when private_output_path is present; includes tests verifying presence and absence of this field.

Changes

Cohort / File(s) Summary
Config implementation & types
package/config.ts, package/types.ts
Add conditional assignment to populate config.privateOutputPath = resolve(config.private_output_path) when provided; add privateOutputPath?: string to Config interface.
Tests
test/package/config.test.js
Add tests asserting privateOutputPath is an absolute path when configured and undefined when not configured.
Formatting ignore
.prettierignore
Add GitHub workflow files .github/workflows/claude.yml and .github/workflows/claude-code-review.yml to prettier ignore list.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

Poem

🐰 I hopped through configs, found a hidden key,
snake_case whispered, "Turn me camel, please."
I resolved the path, tied it neat and fast,
Now private outputs have a home at last. 🎋

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: adding a computed property called privateOutputPath to the JS config, fixing a missing feature that existed on the Ruby side.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ihabadham/fix/add-private-output-path-js-config

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.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Feb 14, 2026

Greptile Summary

Adds missing config.privateOutputPath computed property to sync with Ruby-side private_output_path configuration, fixing React on Rails integration where the property was always undefined.

Changes:

  • Computes privateOutputPath as an absolute path from private_output_path YAML config (following same pattern as outputPath)
  • Adds TypeScript type definition for the new property
  • Includes comprehensive test coverage for both configured and unconfigured scenarios

Confidence Score: 5/5

  • This PR is safe to merge with no risks
  • Simple, well-tested addition that fills a missing gap in the JavaScript config. The implementation correctly mirrors the existing outputPath pattern, includes proper type definitions, and has comprehensive test coverage verifying both configured and unconfigured scenarios. All tests pass (347/347).
  • No files require special attention

Important Files Changed

Filename Overview
package/config.ts Added privateOutputPath computed property that resolves to absolute path when configured
package/types.ts Added privateOutputPath?: string to Config interface for type safety
test/package/config.test.js Added two test cases: one for configured privateOutputPath, one for undefined when not configured

Flowchart

flowchart TD
    A[Load shakapacker.yml config] --> B{private_output_path set?}
    B -->|Yes| C[config.private_output_path = 'ssr-generated']
    B -->|No| D[config.private_output_path = undefined]
    C --> E[resolve private_output_path to absolute path]
    E --> F[config.privateOutputPath = /absolute/path/to/ssr-generated]
    D --> G[config.privateOutputPath remains undefined]
    F --> H[Available for webpack config]
    G --> H
    H --> I[React on Rails uses config.privateOutputPath]
Loading

Last reviewed commit: 016394c

ihabadham and others added 2 commits February 15, 2026 00:05
Verifies privateOutputPath is undefined when private_output_path is
absent from shakapacker.yml, using the same SHAKAPACKER_CONFIG override
pattern as the manifestPath tests.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@justin808
Copy link
Copy Markdown
Member

Superseded by #896, which combines this fix with the workflow Prettier updates needed for CI to pass cleanly.

@justin808
Copy link
Copy Markdown
Member

Closing as superseded by #896.

@justin808 justin808 closed this Feb 15, 2026
@justin808 justin808 reopened this Feb 15, 2026
@justin808
Copy link
Copy Markdown
Member

Added one clean follow-up commit on this original PR branch to address the workflow-file Prettier lint blocker:

  • commit 016394c adds .prettierignore entries for claude workflow files (wording fixed)

Validation run:

  • yarn test test/package/config.test.js (pass)

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
.prettierignore (1)

5-7: Consider tracking the "temporary" ignore with a TODO or issue reference.

The comment mentions temporarily ignoring these workflow files, but without a TODO, issue link, or timeline, temporary ignores can easily become permanent. Since this PR is superseded by #896, that PR may already address this concern.

📋 Suggested improvement
-# Temporarily ignore workflow files that cannot be modified in PRs due to claude-review validation
+# TODO(`#issue-number`): Temporarily ignore workflow files that cannot be modified in PRs due to claude-review validation
 .github/workflows/claude.yml
 .github/workflows/claude-code-review.yml

- Add privateOutputPath computed property to JS config (package/config.ts),
  resolving private_output_path to an absolute path when configured
- Add privateOutputPath?: string to the Config TypeScript interface
- Add JS tests: positive case resolves to absolute path, negative case
  returns undefined when not configured
- Fix Ruby Configuration#private_output_path to use blank? instead of
  nil check, so empty strings don't silently resolve to the Rails root
- Add Ruby spec covering the empty string edge case

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@justin808
Copy link
Copy Markdown
Member

@claude review this PR.

@justin808 justin808 merged commit 179856f into main Feb 15, 2026
56 checks passed
@justin808 justin808 deleted the ihabadham/fix/add-private-output-path-js-config branch February 15, 2026 22:14
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Feb 15, 2026

Claude finished @justin808's task in 3m 3s —— View job


PR Review ✅

I've completed a thorough review of PR #891. This PR successfully addresses issue #890 by adding the missing privateOutputPath computed property to the JavaScript config.


Summary

Verdict: ✅ Excellent implementation - Clean, well-tested, follows existing patterns perfectly

This PR fixes a bug where config.privateOutputPath was always undefined in JavaScript, even though the Ruby-side private_output_path configuration existed. This broke React on Rails integration, causing false warnings and preventing users from configuring their private output path.


Code Review

package/config.ts - Implementation (Lines 112-115)

config.outputPath = resolve(config.public_root_path, config.public_output_path)

if (config.private_output_path) {
  config.privateOutputPath = resolve(config.private_output_path)
}

Strengths:

  • ✅ Follows the exact same pattern as outputPath
  • ✅ Properly conditional - only sets when private_output_path is configured
  • ✅ Uses resolve() to create absolute paths
  • ✅ Positioned logically right after outputPath computation
  • ✅ Clean and readable

Analysis: The implementation correctly mirrors the outputPath pattern. The conditional check ensures privateOutputPath remains undefined when not configured, which is the correct behavior for optional paths.


package/types.ts - Type Definition (Line 34)

export interface Config {
  // ...
  outputPath: string
  privateOutputPath?: string  // ← Added
  publicPath: string
  // ...
}

Strengths:

  • ✅ Correctly typed as optional (?:) since it's only set when configured
  • ✅ Positioned logically next to outputPath
  • ✅ Consistent with TypeScript best practices

Analysis: Perfect type definition. The optional nature matches the conditional assignment in config.ts.


test/package/config.test.js - Test Coverage (Lines 57-67)

test("should return privateOutputPath as absolute path", () => {
  const config = require("../../package/config")
  expect(config.privateOutputPath).toStrictEqual(resolve("ssr-generated"))
})

test("should not set privateOutputPath when not configured", () => {
  process.env.SHAKAPACKER_CONFIG = "config/shakapacker_manifest_path.yml"
  const config = require("../../package/config")
  expect(config.privateOutputPath).toBeUndefined()
})

Strengths:

  • ✅ Tests both configured and unconfigured scenarios
  • ✅ Verifies absolute path resolution
  • ✅ Verifies undefined when not configured
  • ✅ Uses toStrictEqual for exact matching
  • ✅ Follows existing test patterns in the file

Analysis: Comprehensive test coverage. The tests verify both the happy path and the edge case of missing configuration.


lib/shakapacker/configuration.rb - Ruby Side Already Strong

The Ruby implementation (lines 184-195) was already excellent:

  • Proper validation of conflicting paths
  • Returns nil when not configured
  • Clear error messages
  • Well-documented

spec/shakapacker/configuration_spec.rb - Excellent Ruby Tests

The Ruby tests (lines 80-176) are exemplary:

  • Tests absolute path resolution
  • Tests path conflict validation
  • Tests relative path normalization with ..
  • Tests validation caching to prevent redundant checks
  • Tests different valid configurations

⚠️ .prettierignore - Minor Documentation Opportunity

# Temporarily ignore workflow files that cannot be modified in PRs due to claude-review validation
.github/workflows/claude.yml
.github/workflows/claude-code-review.yml

Observation: The comment explains the temporary nature but doesn't include a TODO or reference. Per CodeRabbit's review, consider adding an issue reference. However, this is minor and doesn't block merging.


Pattern Consistency Analysis

The implementation perfectly follows the established pattern:

Property Snake Case (YAML) Camel Case (Computed) Resolution
Public output public_output_path outputPath resolve(public_root_path, public_output_path)
Private output private_output_path privateOutputPath resolve(private_output_path)
Manifest manifest_path manifestPath resolve(manifest_path)

Key Pattern:

  • YAML config uses snake_case
  • Computed JS properties use camelCase
  • All use resolve() for absolute paths ✅
  • Optional configs are conditionally set ✅

Testing Verification

From the PR description, all tests passed:

  • yarn jest test/package/config.test.js — 13/13 passing
  • yarn jest — 347/347 passing
  • yarn build — TypeScript compiles clean
  • ✅ Verified in real Rails + React on Rails app

The implementation was also validated in a real-world scenario, which confirms it solves the actual user problem reported in react_on_rails#2289.


Code Quality Assessment

Aspect Rating Notes
Correctness ⭐⭐⭐⭐⭐ Correctly implements the feature
Pattern Consistency ⭐⭐⭐⭐⭐ Perfectly follows existing patterns
Type Safety ⭐⭐⭐⭐⭐ Proper TypeScript types
Test Coverage ⭐⭐⭐⭐⭐ Tests both positive and negative cases
Documentation ⭐⭐⭐⭐ Clear PR description, code is self-documenting
Impact ⭐⭐⭐⭐⭐ Fixes real user issue, enables React on Rails SSR

Overall: ⭐⭐⭐⭐⭐ (5/5)


Impact Assessment

Problem Solved:

  • ❌ Before: config.privateOutputPath always undefined
  • ✅ After: config.privateOutputPath returns correct absolute path when configured

User Impact:

  • Fixes false warnings in React on Rails builds
  • Enables users to configure private output path from shakapacker.yml
  • Maintains backward compatibility (undefined when not configured)

Risk Level: 🟢 Low

  • Additive change (no breaking changes)
  • Well-tested
  • Follows established patterns
  • Already merged and in use

Recommendations

Since this PR is already merged, these are observations for future reference:

  1. ✅ No action needed - The implementation is solid as-is

  2. Consider for future - The .prettierignore comment could reference why workflow files need special handling, but this is cosmetic

  3. Documentation - Consider adding privateOutputPath to any user-facing configuration documentation (if it exists)


Final Verdict

This PR is production-ready and correctly implemented.

The code quality is excellent, testing is comprehensive, and it solves a real user problem. The implementation follows Shakapacker's established patterns perfectly and maintains full backward compatibility.

Great work by @ihabadham! This is exactly the kind of focused, well-tested PR that makes maintenance easy.


| Branch: claude/pr-891-20260215-2214

justin808 added a commit that referenced this pull request Mar 5, 2026
Added two user-visible changelog entries:
- PR #901: Changed default file rule type from asset/resource to asset
- PR #891: Fixed privateOutputPath not being computed in JavaScript config
justin808 added a commit that referenced this pull request Mar 5, 2026
Added two user-visible changelog entries:
- PR #901: Changed default file rule type from asset/resource to asset
- PR #891: Fixed privateOutputPath not being computed in JavaScript config
justin808 added a commit that referenced this pull request Mar 5, 2026
### Summary

Added two missing user-visible changelog entries to the Unreleased
section:
- PR #891: Fixed privateOutputPath not being computed in JavaScript
config
- PR #901: Changed default file rule type from asset/resource to asset
for static assets

### Pull Request checklist

- [x] ~Add/update test to cover these changes~
- [x] ~Update documentation~
- [x] Update CHANGELOG file

### Other Information

Both entries were missing from the changelog despite being user-visible
changes that affect developers upgrading to the next version.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Documentation-only change to the changelog with no code or runtime
behavior modifications.
> 
> **Overview**
> Updates `CHANGELOG.md` *Unreleased* notes to include two previously
missing user-visible entries: the default static asset module rule
changing from `asset/resource` to `asset` (enabling automatic inlining
of small assets), and the fix ensuring `privateOutputPath` is correctly
computed/exposed in the JavaScript config.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
734096d. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

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

## Summary by CodeRabbit

* **Documentation**
* Updated changelog to document static asset inlining via data URIs
functionality.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
justin808 added a commit that referenced this pull request Mar 8, 2026
### Summary

Added two missing user-visible changelog entries to the Unreleased
section:
- PR #891: Fixed privateOutputPath not being computed in JavaScript
config
- PR #901: Changed default file rule type from asset/resource to asset
for static assets

### Pull Request checklist

- [x] ~Add/update test to cover these changes~
- [x] ~Update documentation~
- [x] Update CHANGELOG file

### Other Information

Both entries were missing from the changelog despite being user-visible
changes that affect developers upgrading to the next version.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Documentation-only change to the changelog with no code or runtime
behavior modifications.
> 
> **Overview**
> Updates `CHANGELOG.md` *Unreleased* notes to include two previously
missing user-visible entries: the default static asset module rule
changing from `asset/resource` to `asset` (enabling automatic inlining
of small assets), and the fix ensuring `privateOutputPath` is correctly
computed/exposed in the JavaScript config.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
734096d. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

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

## Summary by CodeRabbit

* **Documentation**
* Updated changelog to document static asset inlining via data URIs
functionality.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing privateOutputPath computed property in JS config (private_output_path feature incomplete on JS side)

2 participants