diff --git a/reflex/.templates/web/vite.config.js b/reflex/.templates/web/vite.config.js index 20bb8b676e3..1327ea9b222 100644 --- a/reflex/.templates/web/vite.config.js +++ b/reflex/.templates/web/vite.config.js @@ -11,6 +11,12 @@ export default defineConfig((config) => ({ }, server: { port: process.env.PORT, + watch: { + ignored: [ + "**/.web/backend/**", + "**/.web/reflex.install_frontend_packages.cached", + ], + }, }, resolve: { mainFields: ["browser", "module", "jsnext"], diff --git a/reflex/app.py b/reflex/app.py index 3dbd9d3f055..bcd3b9eff43 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -77,6 +77,7 @@ EventType, IndividualEventType, get_hydrate_event, + noop, ) from reflex.model import Model, get_db_status from reflex.page import DECORATED_PAGES @@ -213,17 +214,21 @@ def default_overlay_components(): return Fragment.create(memo(default_overlay_components)()) -def default_error_boundary(*children: Component) -> Component: +def default_error_boundary(*children: Component, **props) -> Component: """Default error_boundary attribute for App. Args: *children: The children to render in the error boundary. + **props: The props to pass to the error boundary. Returns: The default error_boundary, which is an ErrorBoundary. """ - return ErrorBoundary.create(*children) + return ErrorBoundary.create( + *children, + **props, + ) class OverlayFragment(Fragment): @@ -345,7 +350,9 @@ class App(MiddlewareMixin, LifespanMixin): dataclasses.field( default_factory=lambda: { (55, "ErrorBoundary"): ( - lambda stateful: default_error_boundary() if stateful else None + lambda stateful: default_error_boundary( + **({"on_error": noop()} if not stateful else {}) + ) ), (5, "Overlay"): ( lambda stateful: default_overlay_component() if stateful else None diff --git a/tests/integration/test_call_script.py b/tests/integration/test_call_script.py index 24f04bef132..f7643202f35 100644 --- a/tests/integration/test_call_script.py +++ b/tests/integration/test_call_script.py @@ -406,6 +406,9 @@ def assert_token(driver: WebDriver) -> str: """ ss = SessionStorage(driver) assert AppHarness._poll_for(lambda: ss.get("token") is not None), "token not found" + assert AppHarness._poll_for( + lambda: driver.execute_script("return typeof external4 !== 'undefined'") + ), "scripts not loaded" return ss.get("token") diff --git a/tests/units/test_app.py b/tests/units/test_app.py index e2359fa90bc..fec3c758dce 100644 --- a/tests/units/test_app.py +++ b/tests/units/test_app.py @@ -1370,9 +1370,11 @@ def test_app_wrap_compile_theme( lines = "".join(app_js_lines) expected = ( "function AppWrap({children}) {" + "const [addEvents, connectErrors] = useContext(EventLoopContext);" "return (" + ("jsx(StrictMode,{}," if react_strict_mode else "") - + "jsx(RadixThemesColorModeProvider,{}," + + """jsx(ErrorBoundary,{fallbackRender:((event_args) => (jsx("div", ({css:({ ["height"] : "100%", ["width"] : "100%", ["position"] : "absolute", ["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" })}), (jsx(Fragment, ({}), "An error occurred while rendering this page.")))), (jsx("p", ({css:({ ["opacity"] : "0.75" })}), (jsx(Fragment, ({}), "This is an error with the application itself.")))), (jsx("details", ({}), (jsx("summary", ({css:({ ["padding"] : "0.5rem" })}), (jsx(Fragment, ({}), "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", ({}), (jsx(Fragment, ({}), 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([(Event("_call_function", ({ ["function"] : (() => (navigator["clipboard"]["writeText"](event_args.error.stack))), ["callback"] : null }), ({ })))], [_e], ({ }))))}), (jsx(Fragment, ({}), "Copy")))))))), (jsx("hr", ({css:({ ["borderColor"] : "currentColor", ["opacity"] : "0.25" })}))), (jsx("a", ({href:"https://reflex.dev"}), (jsx("div", ({css:({ ["display"] : "flex", ["alignItems"] : "baseline", ["justifyContent"] : "center", ["fontFamily"] : "monospace", ["--default-font-family"] : "monospace", ["gap"] : "0.5rem" })}), (jsx(Fragment, ({}), "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", ({}), (jsx(Fragment, ({}), "Reflex"))))))))))))))),onError:((_error, _info) => (addEvents([(Event("_call_function", ({ ["function"] : (() => null), ["callback"] : null }), ({ })))], [_error, _info], ({ }))))},""" + "jsx(RadixThemesColorModeProvider,{}," "jsx(RadixThemesTheme,{accentColor:\"plum\",css:{...theme.styles.global[':root'], ...theme.styles.global.body}}," "jsx(Fragment,{}," "jsx(MemoizedToastProvider,{},)," @@ -1381,6 +1383,7 @@ def test_app_wrap_compile_theme( ")," ")," ")," + ")," ")" + (",)" if react_strict_mode else "") + ")" "}" ) @@ -1438,9 +1441,11 @@ def page(): lines = "".join(app_js_lines) expected = ( "function AppWrap({children}) {" + "const [addEvents, connectErrors] = useContext(EventLoopContext);" "return (" + ("jsx(StrictMode,{}," if react_strict_mode else "") + "jsx(RadixThemesBox,{}," + """jsx(ErrorBoundary,{fallbackRender:((event_args) => (jsx("div", ({css:({ ["height"] : "100%", ["width"] : "100%", ["position"] : "absolute", ["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" })}), (jsx(Fragment, ({}), "An error occurred while rendering this page.")))), (jsx("p", ({css:({ ["opacity"] : "0.75" })}), (jsx(Fragment, ({}), "This is an error with the application itself.")))), (jsx("details", ({}), (jsx("summary", ({css:({ ["padding"] : "0.5rem" })}), (jsx(Fragment, ({}), "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", ({}), (jsx(Fragment, ({}), 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([(Event("_call_function", ({ ["function"] : (() => (navigator["clipboard"]["writeText"](event_args.error.stack))), ["callback"] : null }), ({ })))], [_e], ({ }))))}), (jsx(Fragment, ({}), "Copy")))))))), (jsx("hr", ({css:({ ["borderColor"] : "currentColor", ["opacity"] : "0.25" })}))), (jsx("a", ({href:"https://reflex.dev"}), (jsx("div", ({css:({ ["display"] : "flex", ["alignItems"] : "baseline", ["justifyContent"] : "center", ["fontFamily"] : "monospace", ["--default-font-family"] : "monospace", ["gap"] : "0.5rem" })}), (jsx(Fragment, ({}), "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", ({}), (jsx(Fragment, ({}), "Reflex"))))))))))))))),onError:((_error, _info) => (addEvents([(Event("_call_function", ({ ["function"] : (() => null), ["callback"] : null }), ({ })))], [_error, _info], ({ }))))},""" 'jsx(RadixThemesText,{as:"p"},' "jsx(RadixThemesColorModeProvider,{}," "jsx(Fragment2,{}," @@ -1448,7 +1453,7 @@ def page(): "jsx(MemoizedToastProvider,{},)," "jsx(Fragment,{}," "children" - ",),),),),)" + (",)" if react_strict_mode else "") + ",),),),),),)" + (",)" if react_strict_mode else "") ) assert expected in lines