Skip to content

Add offline rendering support #213

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
## Description

A summary of the changes.
<!-- A summary of the changes. -->

## Checklist:
## Checklist

Please update this checklist as you complete each item:

Expand All @@ -11,4 +11,4 @@ Please update this checklist as you complete each item:
- [ ] Documentation has been updated, if necessary.
- [ ] GitHub Issues closed by this PR have been linked.

<sub>By submitting this pull request you agree that all contributions comply with this project's open source license(s).</sub>
<sub>By submitting this pull request I agree that all contributions comply with this project's open source license(s).</sub>
13 changes: 10 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ Using the following categories, list your changes in this order:

## [Unreleased]

- Nothing (yet)!
### Added

- An "offline component" can now be displayed when the client disconnects from the server.

## [3.6.0] - 2024-01-10

Expand Down Expand Up @@ -103,9 +105,14 @@ Using the following categories, list your changes in this order:
- Prettier WebSocket URLs for components that do not have sessions.
- Template tag will now only validate `args`/`kwargs` if `settings.py:DEBUG` is enabled.
- Bumped the minimum `@reactpy/client` version to `0.3.1`
- Bumped the minimum Django version to `4.2`.
- Use TypeScript instead of JavaScript for this repository.
- Note: ReactPy-Django will continue bumping minimum Django requirements to versions that increase async support. This "latest-only" trend will continue until Django has all async features that ReactPy benefits from. After this point, ReactPy-Django will begin supporting all maintained Django versions.
- Bumped the minimum Django version to `4.2`.

???+ note "Django 4.2+ is required"

ReactPy-Django will continue bumping minimum Django requirements to versions that increase async support.

This "latest-only" trend will continue until Django has all async features that ReactPy benefits from. After this point, ReactPy-Django will begin supporting all maintained Django versions.

### Removed

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
- [Distributed computing](https://reactive-python.github.io/reactpy-django/latest/reference/settings/#reactpy_default_hosts)
- [Performance enhancements](https://reactive-python.github.io/reactpy-django/latest/reference/settings/#performance-settings)
- [Customizable reconnection behavior](https://reactive-python.github.io/reactpy-django/latest/reference/settings/#stability-settings)
- [Customizable disconnection behavior](https://reactive-python.github.io/reactpy-django/latest/reference/template-tag)
- [Multiple root components](https://reactive-python.github.io/reactpy-django/latest/reference/template-tag/)
- [Django view to ReactPy component conversion](https://reactive-python.github.io/reactpy-django/latest/reference/components/#view-to-component)
- [Django static file access](https://reactive-python.github.io/reactpy-django/latest/reference/components/#django-css)
Expand Down
2 changes: 1 addition & 1 deletion docs/src/learn/add-reactpy-to-a-django-project.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ The [next step](./your-first-component.md) will show you how to create your firs

Prefer a quick summary? Read the **At a Glance** section below.

!!! info "At a Glance: Your First Component"
!!! info "At a Glance"

<font size="5">**`my_app/components.py`**</font>

Expand Down
10 changes: 6 additions & 4 deletions docs/src/reference/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,11 @@ Multiprocessing-safe database used by ReactPy, typically for session data.

If configuring this value, it is mandatory to enable our database router like such:

```python linenums="0"
DATABASE_ROUTERS = ["reactpy_django.database.Router", ...]
```
=== "settings.py"

```python linenums="0"
DATABASE_ROUTERS = ["reactpy_django.database.Router", ...]
```

---

Expand Down Expand Up @@ -145,7 +147,7 @@ Configures whether to pre-render your components via HTTP, which enables SEO com
During pre-rendering, there are some key differences in behavior:

1. Only the component's first render is pre-rendered.
2. All `#!python connection` related hooks use HTTP.
2. All [`connection` hooks](https://reactive-python.github.io/reactpy-django/latest/reference/hooks/#connection-hooks) will provide HTTP variants.
3. The component will be non-interactive until a WebSocket connection is formed.

<!-- TODO: The comment below will become true when ReactPy no longer strips scripts from the DOM -->
Expand Down
72 changes: 49 additions & 23 deletions docs/src/reference/template-tag.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ This template tag can be used to insert any number of ReactPy components onto yo
| `#!python class` | `#!python str | None` | The HTML class to apply to the top-level component div. | `#!python None` |
| `#!python key` | `#!python Any` | Force the component's root node to use a [specific key value](https://reactpy.dev/docs/guides/creating-interfaces/rendering-data/index.html#organizing-items-with-keys). Using `#!python key` within a template tag is effectively useless. | `#!python None` |
| `#!python host` | `#!python str | None` | The host to use for the ReactPy connections. If unset, the host will be automatically configured.<br/>Example values include: `localhost:8000`, `example.com`, `example.com/subdir` | `#!python None` |
| `#!python prerender` | `#!python str` | If `#!python "True"`, the component will pre-rendered, which enables SEO compatibility and reduces perceived latency. | `#!python "False"` |
| `#!python prerender` | `#!python str` | If `#!python "true"`, the component will pre-rendered, which enables SEO compatibility and reduces perceived latency. | `#!python "false"` |
| `#!python offline` | `#!python str` | The dotted path to a component that will be displayed if your root component loses connection to the server. Keep in mind, this `offline` component will be non-interactive (hooks won't operate). | `#!python ""` |
| `#!python **kwargs` | `#!python Any` | The keyword arguments to provide to the component. | N/A |

<font size="4">**Returns**</font>
Expand Down Expand Up @@ -62,27 +63,9 @@ This template tag can be used to insert any number of ReactPy components onto yo
{% include "../../python/template-tag-bad-view.py" %}
```

<!--context-end-->

??? question "Can I render components on a different server (distributed computing)?"

Yes! By using the `#!python host` keyword argument, you can render components from a completely separate ASGI server.
_Note: If you decide to not follow this warning, you will need to use the [`register_component`](../reference/utils.md#register-component) function to manually register your components._

=== "my-template.html"

```jinja
...
{% component "example_project.my_app.components.do_something" host="127.0.0.1:8001" %}
...
```

This configuration most commonly involves you deploying multiple instances of your project. But, you can also create dedicated Django project(s) that only render specific ReactPy components if you wish.

Here's a couple of things to keep in mind:

1. If your host address are completely separate ( `origin1.com != origin2.com` ) you will need to [configure CORS headers](https://pypi.org/project/django-cors-headers/) on your main application during deployment.
2. You will not need to register ReactPy WebSocket or HTTP paths on any applications that do not perform any component rendering.
3. Your component will only be able to access your template tag's `#!python *args`/`#!python **kwargs` if your applications share a common database.
<!--context-end-->

<!--multiple-components-start-->

Expand All @@ -109,7 +92,6 @@ This template tag can be used to insert any number of ReactPy components onto yo
Additionally, in scenarios where you are trying to create a Single Page Application (SPA) within Django, you will only have one component within your `#!html <body>` tag.

<!--multiple-components-end-->
<!--args-kwargs-start-->

??? question "Can I use positional arguments instead of keyword arguments?"

Expand All @@ -127,4 +109,48 @@ This template tag can be used to insert any number of ReactPy components onto yo
{% include "../../python/template-tag-args-kwargs.py" %}
```

<!--args-kwargs-end-->
??? question "Can I render components on a different server (distributed computing)?"

Yes! This is most commonly done through [`settings.py:REACTPY_HOSTS`](../reference/settings.md#reactpy_default_hosts). However, you can use the `#!python host` keyword to render components on a specific ASGI server.

=== "my-template.html"

```jinja
...
{% component "example_project.my_app.components.do_something" host="127.0.0.1:8001" %}
...
```

This configuration most commonly involves you deploying multiple instances of your project. But, you can also create dedicated Django project(s) that only render specific ReactPy components if you wish.

Here's a couple of things to keep in mind:

1. If your host address are completely separate ( `origin1.com != origin2.com` ) you will need to [configure CORS headers](https://pypi.org/project/django-cors-headers/) on your main application during deployment.
2. You will not need to register ReactPy WebSocket or HTTP paths on any applications that do not perform any component rendering.
3. Your component will only be able to access your template tag's `#!python *args`/`#!python **kwargs` if your applications share a common database.

??? question "How do I pre-render components for SEO compatibility?"

This is most commonly done through [`settings.py:REACTPY_PRERENDER`](../reference/settings.md#reactpy_prerender). However, you can use the `#!python prerender` keyword to pre-render a specific component.

=== "my-template.html"

```jinja
...
{% component "example_project.my_app.components.do_something" prerender="true" %}
...
```

??? question "How do I show something when the client disconnects?"

You can use the `#!python offline` keyword to display a specific component when the client disconnects from the server.

=== "my-template.html"

```jinja
...
{% component "example_project.my_app.components.do_something" offline="example_project.my_app.components.offline" %}
...
```

_Note: The `#!python offline` component will be non-interactive (hooks won't operate)._
Loading