Skip to content

fix: include frontend_path in sirv prod command for correct 404.html fallback#6154

Open
masenf wants to merge 2 commits intomainfrom
claude/condescending-bartik
Open

fix: include frontend_path in sirv prod command for correct 404.html fallback#6154
masenf wants to merge 2 commits intomainfrom
claude/condescending-bartik

Conversation

@masenf
Copy link
Collaborator

@masenf masenf commented Mar 5, 2026

When frontend_path is set, the build moves all static files (including 404.html) into a subdirectory, but the sirv --single flag was hardcoded to look for 404.html at the root. This broke dynamic routes in prod.

Closes #5812

…fallback

When frontend_path is set, the build moves all static files (including
404.html) into a subdirectory, but the sirv --single flag was hardcoded
to look for 404.html at the root. This broke dynamic routes in prod.

Closes #5812

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@codspeed-hq
Copy link

codspeed-hq bot commented Mar 5, 2026

Merging this PR will degrade performance by 3.03%

❌ 1 regressed benchmark
✅ 7 untouched benchmarks

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
test_compile_stateful[_stateful_page] 150.8 µs 155.5 µs -3.03%

Comparing claude/condescending-bartik (b808e06) with main (e7c3742)

Open in CodSpeed

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 5, 2026

Greptile Summary

This PR fixes a bug where dynamic routes in production break when frontend_path is set. The sirv --single fallback was hardcoded to look for 404.html at the root, but when frontend_path is set, the build places all static files in a subdirectory.

Key changes:

  • Adds PackageJson.Commands.get_prod_command(frontend_path) in installer.py that dynamically computes the correct --single <path>/404.html argument by stripping leading/trailing slashes from frontend_path.
  • Updates _compile_package_json() in frontend_skeleton.py to call get_config() and pass config.frontend_path to the new method, ensuring the generated package.json always references the correct 404.html path.
  • Adds comprehensive parameterized tests covering all edge cases: empty path, bare /, paths with/without leading slashes, and deeply nested paths.

One remaining issue: the old PROD class attribute at line 109 remains as unused dead code. It should be removed to avoid future confusion.

Confidence Score: 4/5

  • Safe to merge once the unused PROD constant is removed from installer.py. The fix itself is correct, well-tested, and tightly scoped.
  • The core fix is correct: get_prod_command() properly handles all edge cases for frontend_path, and _compile_package_json() correctly invokes it with the config. Tests comprehensively cover empty paths, bare slashes, leading/trailing slashes, and nested paths. The only concern is that the old PROD constant at line 109 is dead code left behind and should be removed before merge to maintain code clarity.
  • reflex/constants/installer.py — the unused PROD constant should be removed (line 109).

Important Files Changed

Filename Overview
reflex/constants/installer.py Adds get_prod_command static method to dynamically build the correct sirv --single argument based on frontend_path. The method correctly strips leading/trailing slashes and constructs relative paths. The old PROD constant at line 109 remains as unused dead code and should be removed before merge.
reflex/utils/frontend_skeleton.py Updates _compile_package_json() to call get_config() and pass config.frontend_path to get_prod_command(), ensuring the generated package.json prod script always uses the correct 404.html fallback path relative to the deployment root.
tests/units/test_prerequisites.py Adds comprehensive parameterized tests for both get_prod_command() edge cases (empty string, /, paths with/without leading slashes, nested paths) and end-to-end _compile_package_json() via monkeypatching get_config(). All cases are explicitly covered and assertions are correct.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["_compile_package_json()"] --> B["get_config()"]
    B --> C{{"config.frontend_path"}}
    C -->|empty string or '/'| D["fallback = '404.html'"]
    C -->|e.g. '/app'| E["stripped = 'app'<br/>fallback = 'app/404.html'"]
    C -->|e.g. '/deep/nested'| F["stripped = 'deep/nested'<br/>fallback = 'deep/nested/404.html'"]
    D --> G["sirv ./build/client --single 404.html --host"]
    E --> H["sirv ./build/client --single app/404.html --host"]
    F --> I["sirv ./build/client --single deep/nested/404.html --host"]
    G --> J["Written to package.json 'prod' script"]
    H --> J
    I --> J
Loading

Last reviewed commit: 0ef95c4

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
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.

Setting the frontend_path breaks static 404 page generation, which breaks dynamic routes for prod builds.

1 participant