Skip to content
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

Add better vite integration for dev and production #179

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Generatd files
# Ignore generated vite bundled files, these should be generated at deploy time
/static/sort-ui

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
40 changes: 38 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Prerequisites

- Python 3.12
- pip
- Nodejs (20.x)
---

1. Clone the project repository to your local machine
Expand All @@ -40,7 +41,11 @@ source .venv/Scripts/activate

3. Install dependencies
```bash
# Install python requirements
pip install -r requirements.txt
# Install nodejs requirements
cd assets/sort-survey-configurator
npm install
```

---
Expand Down Expand Up @@ -70,17 +75,48 @@ DJANGO_ALLOWED_HOSTS=127.0.0.1 localhost

---

7. Finally, run start the development server
7. Finally, start the development server
```bash
python manage.py runserver
```

8. Start the vite javascript server (in a different terminal)
```bash
cd assets/sort-survey-configurator
npm run dev
```

The app will be available at http://127.0.0.1:8000.

---

8. Import test data by following the instructions as [`data/README.md`](./data/README.md).
9Import test data by following the instructions as [`data/README.md`](./data/README.md).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo


# Deployment

Please read [`docs/deployment.md`](docs/deployment.md).


# Vite integration
The SORT app uses some javascript components such as the survey configurator and the survey response form. This is
implemented using the svelte framework and vite is used as the bundler. Vite also provides a live server for
development which includes HMR (hot module reloading).

In order to integrate this into the html template, a tag library is created at `/home/templatetags/vite_integration.py`.
- The `vite_client` template tag is used to include Vite's HMR javascript code.
- The `vite_asset` tag is used to include asset files (e.g. typescript files) in the template.
- In debug mode, this creates a link directly to the vite dev server normally located at `http://localhost:5173`
- In production mode, the link changes to the location of the file in the `/static/` folder


## Before deployment

The script files within `/assets/sort-survey-configurator` must be built into the static folder before deployment. This
can be done by running:

```bash
cd assets/sort-survey-configurator
npm run build
```

This will transpile the typescript files and write them into `/static/sort-ui/` folder.
6 changes: 6 additions & 0 deletions SORT/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,11 @@ def cast_to_boolean(obj: Any) -> bool:
]
AUTH_USER_MODEL = "home.User" # FA: replace username with email as unique identifiers

# Vite integration
VITE_BASE_URL = "http://localhost:5173" # Url of vite dev server
VITE_STATIC_DIR= "sort-ui" # Path to vite-generated asset directory in the static folder
VITE_MANIFEST_FILE_PATH = os.path.join(VITE_STATIC_DIR, ".vite/manifest.json")

# FA: for production:

# EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
Expand Down Expand Up @@ -212,3 +217,4 @@ def cast_to_boolean(obj: Any) -> bool:
"level": os.getenv("DJANGO_LOG_LEVEL", "WARNING"),
},
}

8 changes: 7 additions & 1 deletion assets/sort-survey-configurator/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ export default defineConfig({
customElement: true,
},
})],
server: {
cors: {
origin: "http://localhost:8000"
}
},
build: {
manifest: true,

rollupOptions: {
input: {
Expand All @@ -19,7 +25,7 @@ export default defineConfig({
output: {
chunkFileNames: `[name].[hash].js`,
entryFileNames: "[name].js",
dir: "../../static/js/sort-ui",
dir: "../../static/sort-ui",
},
},
},
Expand Down
52 changes: 52 additions & 0 deletions home/templatetags/vite_integration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import json
import logging
from os import path
from django import template
from urllib.parse import urljoin
from django.conf import settings
from django.utils.safestring import mark_safe
from django.contrib.staticfiles import finders
from django.templatetags.static import static
logger = logging.getLogger(__name__)

register = template.Library()

@register.simple_tag
def vite_client():
"""
Include vite's hot reloading code when in debug mode only.
"""
if settings.DEBUG:
vite_client_path = urljoin(settings.VITE_BASE_URL, "/@vite/client")
return mark_safe(f"<script type = 'module' src = '{vite_client_path}'> </script>")

return ""




@register.simple_tag
def vite_asset(asset_path):
"""
Link directly to asset on vite dev server in debug mode and to static assets folder in production.
"""

if settings.DEBUG:
vite_asset_path = urljoin(settings.VITE_BASE_URL, asset_path)
return mark_safe(f"<script type = 'module' src = '{vite_asset_path}' > </script>")
else:
vite_manifest_path = finders.find(settings.VITE_MANIFEST_FILE_PATH)
if vite_manifest_path:
with open(vite_manifest_path, "r") as f:
vite_manifest = json.load(f)
if asset_path in vite_manifest:
asset_static_path = path.join(settings.VITE_STATIC_DIR, vite_manifest[asset_path]["file"])
asset_static_path_found = finders.find(asset_static_path)
if asset_static_path_found:
return mark_safe(f"<script type = 'module' src = '{static(asset_static_path)}' > </script>")
else:
raise FileNotFoundError(f"Specified vite asset file {asset_static_path} cannot found.")
else:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raise exception?

Copy link
Contributor Author

@twinkarma twinkarma Mar 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in 678dc79

A FileNotFoundException is returned if either the manifest of the files specified in the manifest are not found

raise FileNotFoundError(f"Vite manifest file ({settings.VITE_MANIFEST_FILE_PATH}) cannot be found.")

return ""

This file was deleted.

27 changes: 0 additions & 27 deletions static/js/sort-ui/SurveyConfigurator.Dgvy2nbL.js

This file was deleted.

1 change: 0 additions & 1 deletion static/js/sort-ui/SurveyResponseApp.vn-uywTp.js

This file was deleted.

1 change: 0 additions & 1 deletion static/js/sort-ui/sort_survey_cd.js

This file was deleted.

Loading