From 28d6d7be955cb43784bc5f39fd8d114fa65f75c3 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Thu, 11 Sep 2025 16:36:08 -0700 Subject: [PATCH 1/2] use async helmet --- pyi_hashes.json | 4 ++-- reflex/app.py | 4 +++- reflex/components/core/__init__.py | 2 +- reflex/components/core/helmet.py | 11 ++++++++++- reflex/constants/installer.py | 2 +- tests/units/test_app.py | 6 ++++-- 6 files changed, 21 insertions(+), 8 deletions(-) diff --git a/pyi_hashes.json b/pyi_hashes.json index 601177c96b4..c24e7c73829 100644 --- a/pyi_hashes.json +++ b/pyi_hashes.json @@ -11,12 +11,12 @@ "reflex/components/base/meta.pyi": "d9ab3f671c0689bf477ddc823fc567f6", "reflex/components/base/script.pyi": "b103b2188e1d9761d27c387e7daecf9d", "reflex/components/base/strict_mode.pyi": "6b72e16caadf7158ab744a0ab751b010", - "reflex/components/core/__init__.pyi": "007170b97e58bdf28b2aee381d91c0c7", + "reflex/components/core/__init__.pyi": "a469d9e61421eeb9a377d26ba7a20436", "reflex/components/core/auto_scroll.pyi": "10c4cf71d0d0c1d46a8e1205bd119c11", "reflex/components/core/banner.pyi": "3c07547afc4f215aefd5e5afa409aa25", "reflex/components/core/clipboard.pyi": "a844eb927d9bc2a43f5e88161b258539", "reflex/components/core/debounce.pyi": "055da7aa890f44fb4d48bd5978f1a874", - "reflex/components/core/helmet.pyi": "43f8497c8fafe51e29dca1dd535d143a", + "reflex/components/core/helmet.pyi": "3ae693d1cc100ed26b987a563b699514", "reflex/components/core/html.pyi": "ea5919db8c8172913185977df900f36b", "reflex/components/core/sticky.pyi": "a9b4492e423f1dd4ccbf270c8ea90157", "reflex/components/core/upload.pyi": "c11465a3a88e3a374251dd1a16582938", diff --git a/reflex/app.py b/reflex/app.py index 740aefa226d..4f3f0912a12 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -68,6 +68,7 @@ connection_toaster, ) from reflex.components.core.breakpoints import set_breakpoints +from reflex.components.core.helmet import HelmetProvider from reflex.components.core.sticky import sticky from reflex.components.core.upload import Upload, get_upload_dir from reflex.components.radix import themes @@ -1158,7 +1159,8 @@ def get_compilation_time() -> str: # Add the app wrappers. app_wrappers: dict[tuple[int, str], Component] = { # Default app wrap component renders {children} - (0, "AppWrap"): AppWrap.create() + (0, "AppWrap"): AppWrap.create(), + (199, "HelmetProvider"): HelmetProvider.create(), } if self.theme is not None: diff --git a/reflex/components/core/__init__.py b/reflex/components/core/__init__.py index c9babf294a1..c722bcdfacf 100644 --- a/reflex/components/core/__init__.py +++ b/reflex/components/core/__init__.py @@ -28,7 +28,7 @@ "Foreach", ], "html": ["html", "Html"], - "helmet": ["Helmet"], + "helmet": ["Helmet", "helmet", "HelmetProvider", "helmet_provider"], "match": [ "match", "Match", diff --git a/reflex/components/core/helmet.py b/reflex/components/core/helmet.py index e4d1730759e..efc225cce51 100644 --- a/reflex/components/core/helmet.py +++ b/reflex/components/core/helmet.py @@ -6,9 +6,18 @@ class Helmet(Component): """A helmet component.""" - library = "react-helmet@6.1.0" + library = "react-helmet-async@2.0.5" tag = "Helmet" +class HelmetProvider(Component): + """A helmet provider component.""" + + library = "react-helmet-async@2.0.5" + + tag = "HelmetProvider" + + helmet = Helmet.create +helmet_provider = HelmetProvider.create diff --git a/reflex/constants/installer.py b/reflex/constants/installer.py index 125199f33f1..aa59388bf5f 100644 --- a/reflex/constants/installer.py +++ b/reflex/constants/installer.py @@ -129,7 +129,7 @@ def DEPENDENCIES(cls) -> dict[str, str]: "@react-router/node": cls._react_router_version, "sirv-cli": "3.0.1", "react": cls._react_version, - "react-helmet": "6.1.0", + "react-helmet-async": "2.0.5", "react-dom": cls._react_version, "isbot": "5.1.30", "socket.io-client": "4.8.1", diff --git a/tests/units/test_app.py b/tests/units/test_app.py index 699a89722fa..363daadbbc3 100644 --- a/tests/units/test_app.py +++ b/tests/units/test_app.py @@ -1372,6 +1372,7 @@ def test_app_wrap_compile_theme( "const [addEvents, connectErrors] = useContext(EventLoopContext);\n\n\n\n" "return (" + ("jsx(StrictMode,{}," if react_strict_mode else "") + + "jsx(HelmetProvider,{}," + "jsx(ErrorBoundary,{" """fallbackRender:((event_args) => (jsx("div", ({css:({ ["height"] : "100%", ["width"] : "100%", ["position"] : "absolute", ["backgroundColor"] : "#fff", ["color"] : "#000", ["display"] : "flex", ["alignItems"] : "center", ["justifyContent"] : "center" })}), (jsx("div", ({css:({ ["display"] : "flex", ["flexDirection"] : "column", ["gap"] : "1rem" })}), (jsx("div", ({css:({ ["display"] : "flex", ["flexDirection"] : "column", ["gap"] : "1rem", ["maxWidth"] : "50ch", ["border"] : "1px solid #888888", ["borderRadius"] : "0.25rem", ["padding"] : "1rem" })}), (jsx("h2", ({css:({ ["fontSize"] : "1.25rem", ["fontWeight"] : "bold" })}), "An error occurred while rendering this page.")), (jsx("p", ({css:({ ["opacity"] : "0.75" })}), "This is an error with the application itself.")), (jsx("details", ({}), (jsx("summary", ({css:({ ["padding"] : "0.5rem" })}), "Error message")), (jsx("div", ({css:({ ["width"] : "100%", ["maxHeight"] : "50vh", ["overflow"] : "auto", ["background"] : "#000", ["color"] : "#fff", ["borderRadius"] : "0.25rem" })}), (jsx("div", ({css:({ ["padding"] : "0.5rem", ["width"] : "fit-content" })}), (jsx("pre", ({}), event_args.error.name + \': \' + event_args.error.message + \'\\n\' + event_args.error.stack)))))), (jsx("button", ({css:({ ["padding"] : "0.35rem 0.75rem", ["margin"] : "0.5rem", ["background"] : "#fff", ["color"] : "#000", ["border"] : "1px solid #000", ["borderRadius"] : "0.25rem", ["fontWeight"] : "bold" }),onClick:((_e) => (addEvents([(ReflexEvent("_call_function", ({ ["function"] : (() => (navigator["clipboard"]["writeText"](event_args.error.name + \': \' + event_args.error.message + \'\\n\' + event_args.error.stack))), ["callback"] : null }), ({ })))], [_e], ({ }))))}), "Copy")))))), (jsx("hr", ({css:({ ["borderColor"] : "currentColor", ["opacity"] : "0.25" })}))), (jsx(ReactRouterLink, ({to:"https://reflex.dev"}), (jsx("div", ({css:({ ["display"] : "flex", ["alignItems"] : "baseline", ["justifyContent"] : "center", ["fontFamily"] : "monospace", ["--default-font-family"] : "monospace", ["gap"] : "0.5rem" })}), "Built with ", (jsx("svg", ({"aria-label":"Reflex",css:({ ["fill"] : "currentColor" }),height:"12",role:"img",width:"56",xmlns:"http://www.w3.org/2000/svg"}), (jsx("path", ({d:"M0 11.5999V0.399902H8.96V4.8799H6.72V2.6399H2.24V4.8799H6.72V7.1199H2.24V11.5999H0ZM6.72 11.5999V7.1199H8.96V11.5999H6.72Z"}))), (jsx("path", ({d:"M11.2 11.5999V0.399902H17.92V2.6399H13.44V4.8799H17.92V7.1199H13.44V9.3599H17.92V11.5999H11.2Z"}))), (jsx("path", ({d:"M20.16 11.5999V0.399902H26.88V2.6399H22.4V4.8799H26.88V7.1199H22.4V11.5999H20.16Z"}))), (jsx("path", ({d:"M29.12 11.5999V0.399902H31.36V9.3599H35.84V11.5999H29.12Z"}))), (jsx("path", ({d:"M38.08 11.5999V0.399902H44.8V2.6399H40.32V4.8799H44.8V7.1199H40.32V9.3599H44.8V11.5999H38.08Z"}))), (jsx("path", ({d:"M47.04 4.8799V0.399902H49.28V4.8799H47.04ZM53.76 4.8799V0.399902H56V4.8799H53.76ZM49.28 7.1199V4.8799H53.76V7.1199H49.28ZM47.04 11.5999V7.1199H49.28V11.5999H47.04ZM53.76 11.5999V7.1199H56V11.5999H53.76Z"}))), (jsx("title", ({}), "Reflex"))))))))))))),""" """onError:((_error, _info) => (addEvents([(ReflexEvent("reflex___state____state.reflex___state____frontend_event_exception_state.handle_frontend_exception", ({ ["info"] : ((((_error["name"]+": ")+_error["message"])+"\\n")+_error["stack"]), ["component_stack"] : _info["componentStack"] }), ({ })))], [_error, _info], ({ }))))""" @@ -1384,7 +1385,7 @@ def test_app_wrap_compile_theme( "jsx(MemoizedToastProvider,{},)," "jsx(Fragment,{}," "children" - "))))))" + (")" if react_strict_mode else "") + ")" + ")))))))" + (")" if react_strict_mode else "") + ")" "\n}" ) assert expected.split(",") == function_app_definition.split(",") @@ -1445,6 +1446,7 @@ def page(): "const [addEvents, connectErrors] = useContext(EventLoopContext);\n\n\n\n" "return (" + ("jsx(StrictMode,{}," if react_strict_mode else "") + + "jsx(HelmetProvider,{}," + "jsx(RadixThemesBox,{}," "jsx(ErrorBoundary,{" """fallbackRender:((event_args) => (jsx("div", ({css:({ ["height"] : "100%", ["width"] : "100%", ["position"] : "absolute", ["backgroundColor"] : "#fff", ["color"] : "#000", ["display"] : "flex", ["alignItems"] : "center", ["justifyContent"] : "center" })}), (jsx("div", ({css:({ ["display"] : "flex", ["flexDirection"] : "column", ["gap"] : "1rem" })}), (jsx("div", ({css:({ ["display"] : "flex", ["flexDirection"] : "column", ["gap"] : "1rem", ["maxWidth"] : "50ch", ["border"] : "1px solid #888888", ["borderRadius"] : "0.25rem", ["padding"] : "1rem" })}), (jsx("h2", ({css:({ ["fontSize"] : "1.25rem", ["fontWeight"] : "bold" })}), "An error occurred while rendering this page.")), (jsx("p", ({css:({ ["opacity"] : "0.75" })}), "This is an error with the application itself.")), (jsx("details", ({}), (jsx("summary", ({css:({ ["padding"] : "0.5rem" })}), "Error message")), (jsx("div", ({css:({ ["width"] : "100%", ["maxHeight"] : "50vh", ["overflow"] : "auto", ["background"] : "#000", ["color"] : "#fff", ["borderRadius"] : "0.25rem" })}), (jsx("div", ({css:({ ["padding"] : "0.5rem", ["width"] : "fit-content" })}), (jsx("pre", ({}), event_args.error.name + \': \' + event_args.error.message + \'\\n\' + event_args.error.stack)))))), (jsx("button", ({css:({ ["padding"] : "0.35rem 0.75rem", ["margin"] : "0.5rem", ["background"] : "#fff", ["color"] : "#000", ["border"] : "1px solid #000", ["borderRadius"] : "0.25rem", ["fontWeight"] : "bold" }),onClick:((_e) => (addEvents([(ReflexEvent("_call_function", ({ ["function"] : (() => (navigator["clipboard"]["writeText"](event_args.error.name + \': \' + event_args.error.message + \'\\n\' + event_args.error.stack))), ["callback"] : null }), ({ })))], [_e], ({ }))))}), "Copy")))))), (jsx("hr", ({css:({ ["borderColor"] : "currentColor", ["opacity"] : "0.25" })}))), (jsx(ReactRouterLink, ({to:"https://reflex.dev"}), (jsx("div", ({css:({ ["display"] : "flex", ["alignItems"] : "baseline", ["justifyContent"] : "center", ["fontFamily"] : "monospace", ["--default-font-family"] : "monospace", ["gap"] : "0.5rem" })}), "Built with ", (jsx("svg", ({"aria-label":"Reflex",css:({ ["fill"] : "currentColor" }),height:"12",role:"img",width:"56",xmlns:"http://www.w3.org/2000/svg"}), (jsx("path", ({d:"M0 11.5999V0.399902H8.96V4.8799H6.72V2.6399H2.24V4.8799H6.72V7.1199H2.24V11.5999H0ZM6.72 11.5999V7.1199H8.96V11.5999H6.72Z"}))), (jsx("path", ({d:"M11.2 11.5999V0.399902H17.92V2.6399H13.44V4.8799H17.92V7.1199H13.44V9.3599H17.92V11.5999H11.2Z"}))), (jsx("path", ({d:"M20.16 11.5999V0.399902H26.88V2.6399H22.4V4.8799H26.88V7.1199H22.4V11.5999H20.16Z"}))), (jsx("path", ({d:"M29.12 11.5999V0.399902H31.36V9.3599H35.84V11.5999H29.12Z"}))), (jsx("path", ({d:"M38.08 11.5999V0.399902H44.8V2.6399H40.32V4.8799H44.8V7.1199H40.32V9.3599H44.8V11.5999H38.08Z"}))), (jsx("path", ({d:"M47.04 4.8799V0.399902H49.28V4.8799H47.04ZM53.76 4.8799V0.399902H56V4.8799H53.76ZM49.28 7.1199V4.8799H53.76V7.1199H49.28ZM47.04 11.5999V7.1199H49.28V11.5999H47.04ZM53.76 11.5999V7.1199H56V11.5999H53.76Z"}))), (jsx("title", ({}), "Reflex"))))))))))))),""" @@ -1459,7 +1461,7 @@ def page(): "jsx(MemoizedToastProvider,{},)," "jsx(Fragment,{}," "children" - ")))))))" + (")" if react_strict_mode else "") + "))\n}" + "))))))))" + (")" if react_strict_mode else "") + "))\n}" ) assert expected.split(",") == function_app_definition.split(",") From 64bd4196ad71dce0be471286fb45741266ea8100 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Thu, 11 Sep 2025 16:41:26 -0700 Subject: [PATCH 2/2] maybe? --- reflex/components/core/helmet.py | 4 ++-- reflex/constants/installer.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/reflex/components/core/helmet.py b/reflex/components/core/helmet.py index efc225cce51..6ddcc314f2d 100644 --- a/reflex/components/core/helmet.py +++ b/reflex/components/core/helmet.py @@ -6,7 +6,7 @@ class Helmet(Component): """A helmet component.""" - library = "react-helmet-async@2.0.5" + library = "@dr.pogodin/react-helmet@3.0.4" tag = "Helmet" @@ -14,7 +14,7 @@ class Helmet(Component): class HelmetProvider(Component): """A helmet provider component.""" - library = "react-helmet-async@2.0.5" + library = "@dr.pogodin/react-helmet@3.0.4" tag = "HelmetProvider" diff --git a/reflex/constants/installer.py b/reflex/constants/installer.py index aa59388bf5f..12037df2efc 100644 --- a/reflex/constants/installer.py +++ b/reflex/constants/installer.py @@ -129,7 +129,7 @@ def DEPENDENCIES(cls) -> dict[str, str]: "@react-router/node": cls._react_router_version, "sirv-cli": "3.0.1", "react": cls._react_version, - "react-helmet-async": "2.0.5", + "@dr.pogodin/react-helmet": "3.0.4", "react-dom": cls._react_version, "isbot": "5.1.30", "socket.io-client": "4.8.1",