From 2b7f60062d401af28705d6f146c692d2ecd9d6d8 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Wed, 21 Sep 2022 17:29:02 -0700 Subject: [PATCH 01/21] Pre-register view_to_component URLs --- CHANGELOG.md | 9 ++++++++- src/django_idom/__init__.py | 2 +- src/django_idom/components.py | 35 +++++++++++++++++------------------ 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 894a1390..c57df31a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,12 @@ Using the following categories, list your changes in this order: - Nothing (Yet) +## [1.2.1] - 2022-09-21 + +### Fixed + +- URLs are now pre-registered when using `view_to_component` with `compatibility=True`. + ## [1.2.0] - 2022-09-19 ### Added @@ -130,7 +136,8 @@ Using the following categories, list your changes in this order: - Support for IDOM within the Django -[unreleased]: https://github.com/idom-team/django-idom/compare/1.2.0...HEAD +[unreleased]: https://github.com/idom-team/django-idom/compare/1.2.1...HEAD +[1.2.0]: https://github.com/idom-team/django-idom/compare/1.2.0...1.2.1 [1.2.0]: https://github.com/idom-team/django-idom/compare/1.1.0...1.2.0 [1.1.0]: https://github.com/idom-team/django-idom/compare/1.0.0...1.1.0 [1.0.0]: https://github.com/idom-team/django-idom/compare/0.0.5...1.0.0 diff --git a/src/django_idom/__init__.py b/src/django_idom/__init__.py index 998ab5a6..2a4fa2f4 100644 --- a/src/django_idom/__init__.py +++ b/src/django_idom/__init__.py @@ -3,7 +3,7 @@ from django_idom.websocket.paths import IDOM_WEBSOCKET_PATH -__version__ = "1.2.0" +__version__ = "1.2.1" __all__ = [ "IDOM_WEBSOCKET_PATH", "IdomWebsocket", diff --git a/src/django_idom/components.py b/src/django_idom/components.py index 34ce359c..081e2e59 100644 --- a/src/django_idom/components.py +++ b/src/django_idom/components.py @@ -47,11 +47,17 @@ def view_to_component( kwargs: The keyword arguments to pass to the view. """ kwargs = kwargs or {} - rendered_view, set_rendered_view = hooks.use_state(None) + converted_view, set_converted_view = hooks.use_state(None) request_obj = request if not request: request_obj = HttpRequest() request_obj.method = "GET" + if compatibility: + dotted_path = f"{view.__module__}.{view.__name__}" + dotted_path = dotted_path.replace("<", "").replace(">", "") + IDOM_VIEW_COMPONENT_IFRAMES[dotted_path] = ViewComponentIframe( + view, args, kwargs + ) # Render the view render within a hook @hooks.use_effect( @@ -64,14 +70,7 @@ async def async_renderer(): """Render the view in an async hook to avoid blocking the main thread.""" # Render Check 1: Compatibility mode if compatibility: - dotted_path = f"{view.__module__}.{view.__name__}" - dotted_path = dotted_path.replace("<", "").replace(">", "") - IDOM_VIEW_COMPONENT_IFRAMES[dotted_path] = ViewComponentIframe( - view, args, kwargs - ) - - # Signal that the view has been rendered - set_rendered_view( + set_converted_view( html.iframe( { "src": reverse("idom:view_to_component", args=[dotted_path]), @@ -83,40 +82,40 @@ async def async_renderer(): # Render Check 2: Async function view elif iscoroutinefunction(view): - render = await view(request_obj, *args, **kwargs) + view_html = await view(request_obj, *args, **kwargs) # Render Check 3: Async class view elif getattr(view, "view_is_async", False): view_or_template_view = await view.as_view()(request_obj, *args, **kwargs) if getattr(view_or_template_view, "render", None): # TemplateView - render = await view_or_template_view.render() + view_html = await view_or_template_view.render() else: # View - render = view_or_template_view + view_html = view_or_template_view # Render Check 4: Sync class view elif getattr(view, "as_view", None): async_cbv = database_sync_to_async(view.as_view()) view_or_template_view = await async_cbv(request_obj, *args, **kwargs) if getattr(view_or_template_view, "render", None): # TemplateView - render = await database_sync_to_async(view_or_template_view.render)() + view_html = await database_sync_to_async(view_or_template_view.render)() else: # View - render = view_or_template_view + view_html = view_or_template_view # Render Check 5: Sync function view else: - render = await database_sync_to_async(view)(request_obj, *args, **kwargs) + view_html = await database_sync_to_async(view)(request_obj, *args, **kwargs) # Signal that the view has been rendered - set_rendered_view( + set_converted_view( utils.html_to_vdom( - render.content.decode("utf-8").strip(), + view_html.content.decode("utf-8").strip(), *transforms, strict=strict_parsing, ) ) # Return the view if it's been rendered via the `async_renderer` hook - return rendered_view + return converted_view @component From 3d1779d5683d477aec3939823145500137d978ec Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Wed, 21 Sep 2022 18:02:55 -0700 Subject: [PATCH 02/21] top level `view_to_component` is now a regular function --- CHANGELOG.md | 1 + src/django_idom/components.py | 148 +++++++++++++++++++++------------- 2 files changed, 91 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c57df31a..d32214f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ Using the following categories, list your changes in this order: ### Fixed - URLs are now pre-registered when using `view_to_component` with `compatibility=True`. +- `view_to_component` type hints will now display like normal utility functions. ## [1.2.0] - 2022-09-19 diff --git a/src/django_idom/components.py b/src/django_idom/components.py index 081e2e59..14f836ab 100644 --- a/src/django_idom/components.py +++ b/src/django_idom/components.py @@ -19,7 +19,6 @@ # TODO: Might want to intercept href clicks and form submit events. # Form events will probably be accomplished through the upcoming DjangoForm. -@component def view_to_component( view: Callable | View, compatibility: bool = False, @@ -47,75 +46,104 @@ def view_to_component( kwargs: The keyword arguments to pass to the view. """ kwargs = kwargs or {} - converted_view, set_converted_view = hooks.use_state(None) request_obj = request if not request: request_obj = HttpRequest() request_obj.method = "GET" if compatibility: - dotted_path = f"{view.__module__}.{view.__name__}" + dotted_path = _generate_obj_name(view, raises=True) dotted_path = dotted_path.replace("<", "").replace(">", "") IDOM_VIEW_COMPONENT_IFRAMES[dotted_path] = ViewComponentIframe( view, args, kwargs ) - # Render the view render within a hook - @hooks.use_effect( - dependencies=[ - json.dumps(vars(request_obj), default=lambda x: _generate_obj_name(x)), - json.dumps([args, kwargs], default=lambda x: _generate_obj_name(x)), - ] - ) - async def async_renderer(): - """Render the view in an async hook to avoid blocking the main thread.""" - # Render Check 1: Compatibility mode - if compatibility: + @component + def new_component( + view: Callable | View, + compatibility: bool = False, + transforms: Iterable[Callable[[VdomDict], Any]] = (), + strict_parsing: bool = True, + request: HttpRequest | None = None, + args: Iterable = (), + kwargs: Dict | None = None, + ): + converted_view, set_converted_view = hooks.use_state(None) + + # Render the view render within a hook + @hooks.use_effect( + dependencies=[ + json.dumps(vars(request_obj), default=lambda x: _generate_obj_name(x)), + json.dumps([args, kwargs], default=lambda x: _generate_obj_name(x)), + ] + ) + async def async_renderer(): + """Render the view in an async hook to avoid blocking the main thread.""" + # Render Check 1: Compatibility mode + if compatibility: + set_converted_view( + html.iframe( + { + "src": reverse( + "idom:view_to_component", args=[dotted_path] + ), + "loading": "lazy", + } + ) + ) + return + + # Render Check 2: Async function view + elif iscoroutinefunction(view): + view_html = await view(request_obj, *args, **kwargs) + + # Render Check 3: Async class view + elif getattr(view, "view_is_async", False): + view_or_template_view = await view.as_view()( + request_obj, *args, **kwargs + ) + if getattr(view_or_template_view, "render", None): # TemplateView + view_html = await view_or_template_view.render() + else: # View + view_html = view_or_template_view + + # Render Check 4: Sync class view + elif getattr(view, "as_view", None): + async_cbv = database_sync_to_async(view.as_view()) + view_or_template_view = await async_cbv(request_obj, *args, **kwargs) + if getattr(view_or_template_view, "render", None): # TemplateView + view_html = await database_sync_to_async( + view_or_template_view.render + )() + else: # View + view_html = view_or_template_view + + # Render Check 5: Sync function view + else: + view_html = await database_sync_to_async(view)( + request_obj, *args, **kwargs + ) + + # Signal that the view has been rendered set_converted_view( - html.iframe( - { - "src": reverse("idom:view_to_component", args=[dotted_path]), - "loading": "lazy", - } + utils.html_to_vdom( + view_html.content.decode("utf-8").strip(), + *transforms, + strict=strict_parsing, ) ) - return - - # Render Check 2: Async function view - elif iscoroutinefunction(view): - view_html = await view(request_obj, *args, **kwargs) - - # Render Check 3: Async class view - elif getattr(view, "view_is_async", False): - view_or_template_view = await view.as_view()(request_obj, *args, **kwargs) - if getattr(view_or_template_view, "render", None): # TemplateView - view_html = await view_or_template_view.render() - else: # View - view_html = view_or_template_view - - # Render Check 4: Sync class view - elif getattr(view, "as_view", None): - async_cbv = database_sync_to_async(view.as_view()) - view_or_template_view = await async_cbv(request_obj, *args, **kwargs) - if getattr(view_or_template_view, "render", None): # TemplateView - view_html = await database_sync_to_async(view_or_template_view.render)() - else: # View - view_html = view_or_template_view - - # Render Check 5: Sync function view - else: - view_html = await database_sync_to_async(view)(request_obj, *args, **kwargs) - - # Signal that the view has been rendered - set_converted_view( - utils.html_to_vdom( - view_html.content.decode("utf-8").strip(), - *transforms, - strict=strict_parsing, - ) - ) - # Return the view if it's been rendered via the `async_renderer` hook - return converted_view + # Return the view if it's been rendered via the `async_renderer` hook + return converted_view + + return new_component( + view=view, + compatibility=compatibility, + transforms=transforms, + strict_parsing=strict_parsing, + request=request, + args=args, + kwargs=kwargs, + ) @component @@ -164,7 +192,7 @@ def _cached_static_contents(static_path: str): return file_contents -def _generate_obj_name(object: Any) -> str | None: +def _generate_obj_name(object: Any, raises: bool = False) -> str | None: """Makes a best effort to create a name for an object. Useful for JSON serialization of Python objects.""" if hasattr(object, "__module__"): @@ -172,4 +200,8 @@ def _generate_obj_name(object: Any) -> str | None: return f"{object.__module__}.{object.__name__}" if hasattr(object, "__class__"): return f"{object.__module__}.{object.__class__.__name__}" - return None + + if not raises: + return None + + raise (TypeError(f"Could not generate name for object {object}")) From cc39d942d671cc41d3bed8b96a50b3e7e5ad625a Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Wed, 21 Sep 2022 18:08:17 -0700 Subject: [PATCH 03/21] mypy --- src/django_idom/components.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/django_idom/components.py b/src/django_idom/components.py index 14f836ab..8aff424d 100644 --- a/src/django_idom/components.py +++ b/src/django_idom/components.py @@ -51,7 +51,7 @@ def view_to_component( request_obj = HttpRequest() request_obj.method = "GET" if compatibility: - dotted_path = _generate_obj_name(view, raises=True) + dotted_path = f"{view.__module__}.{view.__name__}" # type: ignore[union-attr] dotted_path = dotted_path.replace("<", "").replace(">", "") IDOM_VIEW_COMPONENT_IFRAMES[dotted_path] = ViewComponentIframe( view, args, kwargs @@ -192,7 +192,7 @@ def _cached_static_contents(static_path: str): return file_contents -def _generate_obj_name(object: Any, raises: bool = False) -> str | None: +def _generate_obj_name(object: Any) -> str | None: """Makes a best effort to create a name for an object. Useful for JSON serialization of Python objects.""" if hasattr(object, "__module__"): @@ -201,7 +201,4 @@ def _generate_obj_name(object: Any, raises: bool = False) -> str | None: if hasattr(object, "__class__"): return f"{object.__module__}.{object.__class__.__name__}" - if not raises: - return None - - raise (TypeError(f"Could not generate name for object {object}")) + return None From bea145bb055347b50f6e6eccb591d1555f5bc026 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Wed, 21 Sep 2022 18:40:03 -0700 Subject: [PATCH 04/21] mypy again --- src/django_idom/components.py | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/src/django_idom/components.py b/src/django_idom/components.py index 8aff424d..b1b71ce8 100644 --- a/src/django_idom/components.py +++ b/src/django_idom/components.py @@ -11,6 +11,7 @@ from django.urls import reverse from django.views import View from idom import component, hooks, html, utils +from idom.core.component import Component from idom.types import VdomDict from django_idom.config import IDOM_CACHE, IDOM_VIEW_COMPONENT_IFRAMES @@ -27,7 +28,7 @@ def view_to_component( request: HttpRequest | None = None, args: Iterable = (), kwargs: Dict | None = None, -) -> VdomDict | None: +) -> Component: """Converts a Django view to an IDOM component. Args: @@ -58,15 +59,7 @@ def view_to_component( ) @component - def new_component( - view: Callable | View, - compatibility: bool = False, - transforms: Iterable[Callable[[VdomDict], Any]] = (), - strict_parsing: bool = True, - request: HttpRequest | None = None, - args: Iterable = (), - kwargs: Dict | None = None, - ): + def new_component(): converted_view, set_converted_view = hooks.use_state(None) # Render the view render within a hook @@ -135,15 +128,7 @@ async def async_renderer(): # Return the view if it's been rendered via the `async_renderer` hook return converted_view - return new_component( - view=view, - compatibility=compatibility, - transforms=transforms, - strict_parsing=strict_parsing, - request=request, - args=args, - kwargs=kwargs, - ) + return new_component() @component From ba71dd46e415ac2d13bb3855d280965d93e470a9 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Wed, 21 Sep 2022 19:00:21 -0700 Subject: [PATCH 05/21] add tests --- tests/test_app/tests/test_components.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_app/tests/test_components.py b/tests/test_app/tests/test_components.py index cf6b153e..75f8350a 100644 --- a/tests/test_app/tests/test_components.py +++ b/tests/test_app/tests/test_components.py @@ -5,6 +5,9 @@ from channels.testing import ChannelsLiveServerTestCase from playwright.sync_api import TimeoutError, sync_playwright +from django_idom.components import view_to_component +from django_idom.config import IDOM_VIEW_COMPONENT_IFRAMES + class TestIdomCapabilities(ChannelsLiveServerTestCase): @classmethod @@ -176,3 +179,9 @@ def test_view_to_component_template_view_class_compatibility(self): ).locator( "#ViewToComponentTemplateViewClassCompatibility[data-success=true]" ).wait_for() + + def test_view_to_component_iframe_registration(self): + view_to_component(lambda x: None, compatibility=True) + self.assertIn( + "test_app.tests.test_components.lambda", IDOM_VIEW_COMPONENT_IFRAMES + ) From 253652ac58c99eeb41cef74f37b5e505e83eb966 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Wed, 21 Sep 2022 19:01:27 -0700 Subject: [PATCH 06/21] fix changelog version --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d32214f6..158c2c54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -138,7 +138,7 @@ Using the following categories, list your changes in this order: - Support for IDOM within the Django [unreleased]: https://github.com/idom-team/django-idom/compare/1.2.1...HEAD -[1.2.0]: https://github.com/idom-team/django-idom/compare/1.2.0...1.2.1 +[1.2.1]: https://github.com/idom-team/django-idom/compare/1.2.0...1.2.1 [1.2.0]: https://github.com/idom-team/django-idom/compare/1.1.0...1.2.0 [1.1.0]: https://github.com/idom-team/django-idom/compare/1.0.0...1.1.0 [1.0.0]: https://github.com/idom-team/django-idom/compare/0.0.5...1.0.0 From 37372e425b56f66286f5b3e9ae55beac07a40303 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Fri, 23 Sep 2022 02:03:24 -0700 Subject: [PATCH 07/21] fix spacing --- src/django_idom/components.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/django_idom/components.py b/src/django_idom/components.py index b1b71ce8..8658a1b4 100644 --- a/src/django_idom/components.py +++ b/src/django_idom/components.py @@ -185,5 +185,4 @@ def _generate_obj_name(object: Any) -> str | None: return f"{object.__module__}.{object.__name__}" if hasattr(object, "__class__"): return f"{object.__module__}.{object.__class__.__name__}" - return None From 293dc018a8b63fa2967cfd59680c8f62dbdea5ca Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Fri, 23 Sep 2022 02:04:02 -0700 Subject: [PATCH 08/21] clean up changelog verbiage --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 158c2c54..f39aef1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,7 @@ Using the following categories, list your changes in this order: ### Fixed - URLs are now pre-registered when using `view_to_component` with `compatibility=True`. -- `view_to_component` type hints will now display like normal utility functions. +- `view_to_component` type hints will now display like normal functions. ## [1.2.0] - 2022-09-19 From 78372d276b3b3ce3ec5b20133ed94bb9cda985a4 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Fri, 23 Sep 2022 02:06:52 -0700 Subject: [PATCH 09/21] fix type hints for django_css and django_js --- CHANGELOG.md | 2 +- src/django_idom/components.py | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f39aef1a..29ae61c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,7 @@ Using the following categories, list your changes in this order: ### Fixed - URLs are now pre-registered when using `view_to_component` with `compatibility=True`. -- `view_to_component` type hints will now display like normal functions. +- `view_to_component`, `django_css`, and `django_js` type hints will now display like normal functions. ## [1.2.0] - 2022-09-19 diff --git a/src/django_idom/components.py b/src/django_idom/components.py index 8658a1b4..d1ce0380 100644 --- a/src/django_idom/components.py +++ b/src/django_idom/components.py @@ -131,7 +131,6 @@ async def async_renderer(): return new_component() -@component def django_css(static_path: str): """Fetches a CSS static file for use within IDOM. This allows for deferred CSS loading. @@ -139,10 +138,14 @@ def django_css(static_path: str): static_path: The path to the static file. This path is identical to what you would use on a `static` template tag. """ - return html.style(_cached_static_contents(static_path)) + + @component + def new_component(): + return html.style(_cached_static_contents(static_path)) + + return new_component() -@component def django_js(static_path: str): """Fetches a JS static file for use within IDOM. This allows for deferred JS loading. @@ -150,7 +153,12 @@ def django_js(static_path: str): static_path: The path to the static file. This path is identical to what you would use on a `static` template tag. """ - return html.script(_cached_static_contents(static_path)) + + @component + def new_component(): + return html.script(_cached_static_contents(static_path)) + + return new_component() def _cached_static_contents(static_path: str): From 655a6153a8c7b2df7e554e7243abc8d81e594e0d Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Fri, 30 Sep 2022 14:55:01 -0700 Subject: [PATCH 10/21] consistent component identity --- src/django_idom/components.py | 173 ++++++++++++++++++---------------- 1 file changed, 94 insertions(+), 79 deletions(-) diff --git a/src/django_idom/components.py b/src/django_idom/components.py index d1ce0380..e63e34f7 100644 --- a/src/django_idom/components.py +++ b/src/django_idom/components.py @@ -18,6 +18,78 @@ from django_idom.types import ViewComponentIframe +@component +def _view_to_component( + view: Callable | View, + compatibility: bool = False, + transforms: Iterable[Callable[[VdomDict], Any]] = (), + strict_parsing: bool = True, + request: HttpRequest | None = None, + args: Iterable = (), + kwargs: Dict | None = None, + dotted_path: str | None = None, +): + converted_view, set_converted_view = hooks.use_state(None) + + # Render the view render within a hook + @hooks.use_effect( + dependencies=[ + json.dumps(vars(request), default=lambda x: _generate_obj_name(x)), + json.dumps([args, kwargs], default=lambda x: _generate_obj_name(x)), + ] + ) + async def async_renderer(): + """Render the view in an async hook to avoid blocking the main thread.""" + # Render Check 1: Compatibility mode + if compatibility: + set_converted_view( + html.iframe( + { + "src": reverse("idom:view_to_component", args=[dotted_path]), + "loading": "lazy", + } + ) + ) + return + + # Render Check 2: Async function view + elif iscoroutinefunction(view): + view_html = await view(request, *args, **kwargs) + + # Render Check 3: Async class view + elif getattr(view, "view_is_async", False): + view_or_template_view = await view.as_view()(request, *args, **kwargs) + if getattr(view_or_template_view, "render", None): # TemplateView + view_html = await view_or_template_view.render() + else: # View + view_html = view_or_template_view + + # Render Check 4: Sync class view + elif getattr(view, "as_view", None): + async_cbv = database_sync_to_async(view.as_view()) + view_or_template_view = await async_cbv(request, *args, **kwargs) + if getattr(view_or_template_view, "render", None): # TemplateView + view_html = await database_sync_to_async(view_or_template_view.render)() + else: # View + view_html = view_or_template_view + + # Render Check 5: Sync function view + else: + view_html = await database_sync_to_async(view)(request, *args, **kwargs) + + # Signal that the view has been rendered + set_converted_view( + utils.html_to_vdom( + view_html.content.decode("utf-8").strip(), + *transforms, + strict=strict_parsing, + ) + ) + + # Return the view if it's been rendered via the `async_renderer` hook + return converted_view + + # TODO: Might want to intercept href clicks and form submit events. # Form events will probably be accomplished through the upcoming DjangoForm. def view_to_component( @@ -48,7 +120,7 @@ def view_to_component( """ kwargs = kwargs or {} request_obj = request - if not request: + if not request_obj: request_obj = HttpRequest() request_obj.method = "GET" if compatibility: @@ -57,78 +129,24 @@ def view_to_component( IDOM_VIEW_COMPONENT_IFRAMES[dotted_path] = ViewComponentIframe( view, args, kwargs ) + else: + dotted_path = None - @component - def new_component(): - converted_view, set_converted_view = hooks.use_state(None) - - # Render the view render within a hook - @hooks.use_effect( - dependencies=[ - json.dumps(vars(request_obj), default=lambda x: _generate_obj_name(x)), - json.dumps([args, kwargs], default=lambda x: _generate_obj_name(x)), - ] - ) - async def async_renderer(): - """Render the view in an async hook to avoid blocking the main thread.""" - # Render Check 1: Compatibility mode - if compatibility: - set_converted_view( - html.iframe( - { - "src": reverse( - "idom:view_to_component", args=[dotted_path] - ), - "loading": "lazy", - } - ) - ) - return - - # Render Check 2: Async function view - elif iscoroutinefunction(view): - view_html = await view(request_obj, *args, **kwargs) - - # Render Check 3: Async class view - elif getattr(view, "view_is_async", False): - view_or_template_view = await view.as_view()( - request_obj, *args, **kwargs - ) - if getattr(view_or_template_view, "render", None): # TemplateView - view_html = await view_or_template_view.render() - else: # View - view_html = view_or_template_view - - # Render Check 4: Sync class view - elif getattr(view, "as_view", None): - async_cbv = database_sync_to_async(view.as_view()) - view_or_template_view = await async_cbv(request_obj, *args, **kwargs) - if getattr(view_or_template_view, "render", None): # TemplateView - view_html = await database_sync_to_async( - view_or_template_view.render - )() - else: # View - view_html = view_or_template_view - - # Render Check 5: Sync function view - else: - view_html = await database_sync_to_async(view)( - request_obj, *args, **kwargs - ) - - # Signal that the view has been rendered - set_converted_view( - utils.html_to_vdom( - view_html.content.decode("utf-8").strip(), - *transforms, - strict=strict_parsing, - ) - ) + return _view_to_component( + view=view, + compatibility=compatibility, + transforms=transforms, + strict_parsing=strict_parsing, + request=request_obj, + args=args, + kwargs=kwargs, + dotted_path=dotted_path, + ) - # Return the view if it's been rendered via the `async_renderer` hook - return converted_view - return new_component() +@component +def _django_css(static_path: str): + return html.style(_cached_static_contents(static_path)) def django_css(static_path: str): @@ -139,11 +157,12 @@ def django_css(static_path: str): use on a `static` template tag. """ - @component - def new_component(): - return html.style(_cached_static_contents(static_path)) + return _django_css(static_path=static_path) + - return new_component() +@component +def _django_js(static_path: str): + return html.script(_cached_static_contents(static_path)) def django_js(static_path: str): @@ -154,11 +173,7 @@ def django_js(static_path: str): use on a `static` template tag. """ - @component - def new_component(): - return html.script(_cached_static_contents(static_path)) - - return new_component() + return _django_js(static_path=static_path) def _cached_static_contents(static_path: str): From 8719dd9d19fcb909281f1c2975c927dccafcbff5 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 2 Oct 2022 17:02:21 -0700 Subject: [PATCH 11/21] async_renderer -> async_render --- src/django_idom/components.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/django_idom/components.py b/src/django_idom/components.py index e63e34f7..53d96659 100644 --- a/src/django_idom/components.py +++ b/src/django_idom/components.py @@ -38,7 +38,7 @@ def _view_to_component( json.dumps([args, kwargs], default=lambda x: _generate_obj_name(x)), ] ) - async def async_renderer(): + async def async_render(): """Render the view in an async hook to avoid blocking the main thread.""" # Render Check 1: Compatibility mode if compatibility: @@ -86,7 +86,7 @@ async def async_renderer(): ) ) - # Return the view if it's been rendered via the `async_renderer` hook + # Return the view if it's been rendered via the `async_render` hook return converted_view From 89f4033c342a1a489a98c67834fc44ca30b7a71c Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Sun, 2 Oct 2022 18:09:47 -0700 Subject: [PATCH 12/21] add vtc limitations --- docs/src/features/components.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/src/features/components.md b/docs/src/features/components.md index 8d95c062..91e5241a 100644 --- a/docs/src/features/components.md +++ b/docs/src/features/components.md @@ -181,6 +181,16 @@ Convert any Django view into a IDOM component by usng this decorator. Compatible return HttpResponse("