Write package.json in bun's layout

Merged
MA
2d ago
+182-21

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Description

Found in the reflex 0.11.0a1 pre-release testing (FINDING-029).

Reflex wrote .web/package.json as compact one-line JSON, and reflex.lock/package.json is a byte copy of that file. Whenever bun add changes the file, bun rewrites it 2-space indented. The persisted file therefore flipped between the two layouts and produced VCS diffs with no content change.

Every package.json writer now produces bun's layout:

  • reflex_base.compiler.templates.package_json_template, which initialize_package_json and sync_root_package_json_to_web use
  • frontend_skeleton.update_package_json_overrides

The layout is json.dumps(..., indent=2, ensure_ascii=False) + "\n", written as UTF-8 with newline="\n", so Windows writes LF like bun does. bun writes non-ASCII characters as raw UTF-8 rather than \uXXXX escapes. For that reason every package.json reader now uses encoding="utf-8": _read_package_json_object, js_runtimes._existing_web_package_sections and exec.get_package_json_and_hash. A file that is not valid UTF-8 is treated as unusable, the same as invalid JSON. The persisted copy is made with path_ops.cp, so it gets the same layout.

Checked against bun 1.4.4, the version reflex pins:

  • bun add on a reflex-rendered file changes only the entries it adds. Its output equals json.dumps(json.loads(out), indent=2, ensure_ascii=False) + "\n".
  • bun keeps whatever trailing newline the file already has. An indented file goes through bun add and bun remove byte-identical.
  • bun keeps arrays expanded when they start expanded, which is how reflex writes them.

Changes To Core Features:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you successfully ran tests with your changes locally?

Every test below fails on main and passes with this change. Most of them run under a new windows_text_io fixture in tests/units/conftest.py. When no encoding or newline is given, the fixture makes text-mode file access decode as ASCII and translate LF to CRLF on writes.

  • tests/units/utils/test_frontend_skeleton.py:
    • test_rendered_package_json_matches_bun_format and test_update_package_json_overrides_matches_bun_format: layout, UTF-8, and no \r in the file.
    • test_sync_root_package_json_repairs_unusable_file[\xff{}]: a non-UTF-8 file is repaired instead of raising.
  • tests/units/utils/test_exec.py::test_get_package_json_and_hash_reads_utf8
  • tests/units/utils/test_js_runtimes.py::test_existing_web_package_sections_reads_utf8

test_frontend_skeleton.py, test_exec.py, test_js_runtimes.py, test_prerequisites.py and tests/units/compiler pass, and ruff, ruff format, pyright and pre-commit are clean on the changed files.

šŸ¤– Generated with Claude Code

https://claude.ai/code/session_01Dxjadq3qkhKnqZR2b9WBFi