Skip to content
Draft
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
10 changes: 10 additions & 0 deletions cms/src/apps/example_app/templates/example_app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,17 @@
<link rel="stylesheet" type="text/css" href="{% static 'example_app/css/example_app.css' %}">
{% endaddtoblock %}

{% addtoblock "js" %}
{# Optional: create this file in your project to load your React build. #}
{# Example: it can include <script type="module" src="/static/.../assets/..."></script> #}
{% include "example_app/react-imports.html" ignore missing %}
{% endaddtoblock %}

<h1>Example App</h1>
<p>Example application content.</p>

<section aria-label="React mount example">
<div id="example-react-mount"></div>
</section>

{% endblock %}
1 change: 1 addition & 0 deletions docs/configure-project.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ To know what settings are typically customized, see [TACC/Core-CMS:`/…/setting

- Update `custom_app_settings.py` with pertinent content from [TACC/Core-CMS:`/taccsite_cms/custom_app_settings.example.py`](https://github.com/TACC/Core-CMS/blob/1d88c35/taccsite_cms/custom_app_settings.example.py).
- Update `urls_custom.py` with pertinent content from [TACC/Core-CMS:`/taccsite_cms/urls_custom.example.py`](https://github.com/TACC/Core-CMS/blob/1d88c35/taccsite_cms/urls_custom.example.py).
- If your custom app needs to host React UI, see [`docs/react-custom-app.md`](react-custom-app.md).


<!-- Link Aliases -->
Expand Down
76 changes: 76 additions & 0 deletions docs/react-custom-app.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# React Custom App (Docs-Only Integration)

This template repo does **not** ship a React build system. Instead, it documents a convention for hosting a React build inside Core-CMS via a custom Django app.

The recommended developer experience matches `tup-cms-react` “widget mounts”: the React entrypoint looks for a DOM element by ID and **only mounts if it exists**. That keeps the Django/CMS side in control of where (and whether) the React UI appears.

## Concepts

- **Mount-by-ID (recommended)**: Your React entrypoint does something like `document.getElementById('cms-sysmon')` and renders only when found. This supports one widget or multiple widgets on a page.
- **Full-page app (also supported)**: Same idea, but you mount a single React root (e.g. `id="root"`) and render a router-driven SPA.
- **Asset include**: Django templates include a small snippet (often called `*-imports.html`) that loads the built JS/CSS from `/static/...`.

## File placement conventions

### React build output

Put your compiled assets under your project’s Django static tree so `collectstatic` picks them up. For example:

- `cms/src/taccsite_custom/<your_site>/static/<your_site>/react/<your_app>/assets/...`

Your actual structure depends on your React toolchain. The only requirement is that, after `collectstatic`, the assets are reachable under `/static/...`.

### Template snippet to load assets

Create a template include that contains the script tags for your build, for example:

- `cms/src/taccsite_custom/<your_site>/templates/react/<your_app>-imports.html`

This file is intentionally a *plain include* so you can swap it between dev/prod (or between different build outputs) without changing the page template.

## Example: “widget mount” (Sysmon-style)

### 1) Add a mount point in a Django template

In the template where you want the widget to appear, add a mount element with a stable ID:

```html
<section aria-label="System monitor">
<div id="cms-sysmon"></div>
</section>
```

Your React entrypoint should check for `#cms-sysmon` and only render if present.

### 2) Include your React assets

If your templates use Sekizai (Core-CMS does), prefer adding scripts to the JS block rather than inline. A common pattern:

```django
{% load sekizai_tags %}

{% addtoblock "js" %}
{% include "react/sysmon-imports.html" %}
{% endaddtoblock %}
```

The included `react/sysmon-imports.html` should contain `<script>` (and `<link>`, if needed) pointing at your built assets under `/static/...`.

## Example: “full-page app” (tup-ui-style)

### 1) Provide a single root mount

```html
<div id="root"></div>
```

### 2) Include the SPA assets

Include your `*-imports.html` snippet on that page. If the SPA needs runtime configuration, set it in a small `<script>` block in the page template (or via a context processor), then have your React app read it from `window`.

## Notes and gotchas

- **Multiple mounts**: One React entrypoint can mount multiple widgets by checking multiple IDs (e.g. `cms-sysmon`, `cms-software`), each guarded by `if (el) { ... }`.
- **Don’t assume the mount exists**: Keep the “guarded mount” behavior so CMS editors can place/remove components without breaking pages.
- **Static URLs**: Ensure the paths in your imports snippet match where `collectstatic` will serve the assets (usually `/static/...`).