Skip to content

fix(app): normalize subpath imports to install base npm package#6380

Open
BABTUNA wants to merge 2 commits intoreflex-dev:mainfrom
BABTUNA:fix-6234-library-subpath
Open

fix(app): normalize subpath imports to install base npm package#6380
BABTUNA wants to merge 2 commits intoreflex-dev:mainfrom
BABTUNA:fix-6234-library-subpath

Conversation

@BABTUNA
Copy link
Copy Markdown

@BABTUNA BABTUNA commented Apr 24, 2026

All Submissions:

  • Have you followed the guidelines stated in CONTRIBUTING.md file?
  • Have you checked to ensure there aren't any other open Pull Requests for the desired changed?

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

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?

Description

Fixes frontend package installation when component import keys include package subpaths.

Before this change, _get_frontend_packages attempted to install subpath keys directly (for example
eact-map-gl/maplibre), which is not an installable npm package name.

This patch adds package-name normalization in App._get_frontend_packages:

  • Converts unscoped subpaths like
    eact-map-gl/maplibre to
    eact-map-gl.
  • Converts scoped subpaths like @scope/pkg/subpath to @scope/pkg.
  • Preserves pinned version info when present.

Tests

Added regression test:

  • est_get_frontend_packages_maps_subpath_imports_to_installable_package_names

Validation run:

  • uv run pytest tests/units/test_app.py -k "maps_subpath_imports_to_installable_package_names" -q
  • uv run ruff check reflex/app.py tests/units/test_app.py

Closes #6234

@BABTUNA BABTUNA requested a review from a team as a code owner April 24, 2026 04:05
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 24, 2026

Greptile Summary

This PR fixes frontend package installation for components that use npm subpath imports (e.g. react-map-gl/maplibre) by extracting a _get_frontend_package_name helper that normalises both unscoped and scoped subpaths down to their installable base package name.

  • P1 regression: URL-based import keys (CDN-style imports starting with https) are not excluded early; format_library_name returns them unchanged but the subsequent .split("/", maxsplit=1)[0] reduces them to "https:", which is passed to install_frontend_packages instead of the original URL.
  • P2 edge case: imports combining a version pin and a subpath (e.g. react-map-gl@1.0.0/maplibre) hit the if package_name == library_name: return import_name short-circuit because format_library_name already strips @1.0.0/maplibre, so the full subpath string is returned unchanged.

Confidence Score: 3/5

Not safe to merge as-is — introduces a regression for https:// URL imports that was absent before this change.

The P1 finding is a concrete behavioural regression: any component whose import key starts with https:// will now attempt to install a package named 'https:' instead of the original URL. This replaces working behaviour with a silent mis-install. The P2 versioned-subpath edge case is lower risk but also untested.

reflex/app.py — _get_frontend_package_name needs an early-return for https:// URL imports and a fix for the versioned+subpath case.

Important Files Changed

Filename Overview
reflex/app.py Adds _get_frontend_package_name static method for subpath normalization; regression for https:// URL imports and edge-case bug with versioned+subpath imports.
tests/units/test_app.py New regression test covers the primary unscoped and scoped subpath cases; missing coverage for versioned+subpath and https:// URL imports.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["import_name"] --> B{"empty or starts\nwith /, $/, .?"}
    B -- yes --> C["return None"]
    B -- no --> D["format_library_name(import_name)\n→ strips @version suffix"]
    D --> E{"starts with '@'?\n(scoped package)"}
    E -- yes --> F["Extract @scope/pkg\nfrom @scope/pkg/subpath"]
    E -- no --> G["Split on first '/'\n→ base package name"]
    F --> H{"package_name\n== library_name?"}
    G --> H
    H -- yes --> I["return import_name\n⚠️ BUG if versioned+subpath\n⚠️ BUG if https:// URL"]
    H -- no --> J{"import_name has\npinned version?"}
    J -- yes --> K["return package_name@version"]
    J -- no --> L["return package_name"]
Loading

Reviews (1): Last reviewed commit: "fix(app): install base npm package for s..." | Re-trigger Greptile

Comment thread reflex/app.py
Comment on lines +1059 to +1062
package_name = library_name.split("/", maxsplit=1)[0]

if package_name == library_name:
return import_name
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 https:// URL imports mangled to "https:"

format_library_name short-circuits for https://… URLs and returns the full URL unchanged. That URL then falls through to the unscoped branch where .split("/", maxsplit=1)[0] produces "https:", which is returned as the package name and later passed to install_frontend_packages.

The original code passed such URL imports through intact; this PR introduces a regression for any component whose import key starts with https:// (e.g. Skypack CDN imports). An early-return for https:// in _get_frontend_package_name would restore the previous behaviour:

if import_name == "" or any(
    import_name.startswith(prefix) for prefix in ("/", "$/", ".", "https://")
):
    return None

Comment thread reflex/app.py
Comment on lines +1061 to +1062
if package_name == library_name:
return import_name
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Versioned + subpath imports returned unchanged

When an import carries both a version pin and a subpath, e.g. react-map-gl@1.0.0/maplibre, format.format_library_name strips @1.0.0/maplibre entirely via rpartition("@"), yielding library_name = "react-map-gl". At that point package_name (also "react-map-gl") equals library_name, so the guard if package_name == library_name: return import_name fires and returns "react-map-gl@1.0.0/maplibre" — the original subpath-containing string — defeating the fix.

The condition is meant to short-circuit when there is no subpath to strip, but it does not account for format_library_name having already consumed the subpath as part of the version segment. Checking whether the original import_name contains a / after the version separator would close the gap.

@BABTUNA
Copy link
Copy Markdown
Author

BABTUNA commented Apr 24, 2026

Addressed both review points in 7516516:

  • Fixed URL import regression: _get_frontend_package_name now preserves https:///http:// imports instead of mangling to https:.
  • Fixed versioned+subpath normalization: imports like react-map-gl@1.0.0/maplibre and @scope/pkg@2.0.0/subpath now normalize to react-map-gl@1.0.0 and @scope/pkg@2.0.0.

Added regression tests:

  • test_get_frontend_packages_keeps_https_imports_unchanged
  • test_get_frontend_packages_maps_versioned_subpath_imports_to_pinned_base

Validation:

  • uv run pytest tests/units/test_app.py -k "maps_subpath_imports_to_installable_package_names or keeps_https_imports_unchanged or maps_versioned_subpath_imports_to_pinned_base" -q
  • uv run ruff check reflex/app.py tests/units/test_app.py

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.

Cannot specify package subpaths in library attribute - auto-generates invalid bare imports

1 participant