django-vite

repository·master·Indexed 21 days ago

https://github.com/mrbin99/django-vite

An integration tool that allows developers to use ViteJS as a frontend asset bundler within a Django project. It supports development mode with Hot Module Replacement (HMR) and production mode via manifest files. The library provides Django template tags for loading assets, React refresh scripts, and legacy polyfills, and supports multi-app configurations and custom asset loading logic for remote sources like S3.

Tokens
3.4K
Snippets
11
Records
12
Agent score
24%

What's inside django-vite

  1. Configure multiple Vite apps

    master

    You can use django-vite with multiple independent Vite configurations by defining multiple entries in the DJANGO_VITE dictionary.

    In your templates, specify which app to use via the app argument in the tag:

    {# Uses the 'default' app #}
    {% vite_asset 'src/main.ts' %}
    
    {# Uses 'external_app_1' #}
    {% vite_asset 'src/other.ts' app='external_app_1' %}
    DJANGO_VITE = {
      "default": {
        "dev_mode": True,
      },
      "external_app_1": {
        "dev_mode": False,
        # ... other config
      },
    }
  2. Extend DjangoViteAppClient for custom loading logic

    master
    You can customize how manifest.json is loaded (for example, loading it from an S3 bucket instead of the local filesystem) by providing a custom class to the app_client_class configuration key. This class must be the fully qualified Python path to a class that extends django_vite.core.asset_loader.DjangoViteAppClient.
  3. Install django-vite in Django

    master

    To integrate ViteJS with Django, follow these steps:

    1. Install the package via pip:

      pip install django-vite
    2. Add django_vite to your INSTALLED_APPS in settings.py. It should be placed before any of your own apps that depend on it.

    INSTALLED_APPS = [
        ...
        'django_vite',
        ...
    ]
  4. Load assets from a CDN (S3)

    master

    If your manifest.json is hosted on a remote source like S3, you must subclass DjangoViteAppClient and its ManifestClient to override how the manifest is loaded.

    1. Implement S3ManifestClient: Override load_manifest() to fetch the JSON from S3.
    2. Implement S3DjangoViteAppClient: Set your custom ManifestClient class.
    3. Configure Django: Pass the custom client class to the app_client_class setting.
    # myapp/django_vite_s3.py
    import json
    import boto3
    from django_vite.core.asset_loader import ManifestClient, DjangoViteAppClient
    
    class S3ManifestClient(ManifestClient):
        def load_manifest(self):
            s3 = boto3.client("s3")
            res = s3.get_object(Bucket='your-bucket', Key='manifest.json')
            return json.loads(res["Body"].read())
    
    class S3DjangoViteAppClient(DjangoViteAppClient):
        ManifestClient = S3ManifestClient
    
    # settings.py
    DJANGO_VITE = {
        "default": {
            "dev_mode": False,
            "app_client_class": "myapp.django_vite_s3.S3DjangoViteAppClient",
        }
    }
    class S3ManifestClient(ManifestClient):
        def load_manifest(self):
            s3 = boto3.client("s3")
            res = s3.get_object(Bucket='django-vite-public-example', Key='manifest.json')
            manifest_content = res["Body"].read()
            return json.loads(manifest_content)
    
    class S3DjangoViteAppClient(DjangoViteAppClient):
        ManifestClient = S3ManifestClient
  5. Configure static_url_prefix for asset isolation

    master

    Use static_url_prefix to avoid conflicts with other static files. This requires synchronization between Django settings and your Vite configuration.

    1. Set static_url_prefix in settings.py.
    2. Add the prefix to your Vite base config.
    3. (Production) Ensure the prefix is part of your Vite build.outDir.
    # settings.py
    DJANGO_VITE_STATIC_URL_PREFIX = 'bundler'
    STATICFILES_DIRS = (('bundler', '/srv/app/bundler/dist'),)
    // vite.config.js
    export default defineConfig({
      base: '/static/bundler/',
      ...
    })
  6. Configure ViteJS for Django integration

    master

    When setting up ViteJS for use with Django (SSR mode), you must configure your vite.config.js to match Django's static file structure.

    Key requirements:

    • Set base to match your Django STATIC_URL.
    • Set build.outDir to the directory where assets will be compiled (ensure this directory is included in Django's STATICFILES_DIRS).
    • Set build.manifest to manifest.json.
    • Since there is no index.html in SSR, you must explicitly define your entry points in build.rollupOptions.input.

    Note: As recommended by Vite, include the modulepreload polyfill at the beginning of your application entry point.

    export default defineConfig({
      ...
      base: "/static/",
      build: {
        ...
        manifest: "manifest.json",
        outDir: resolve("./assets"),
        rollupOptions: {
          input: {
            <unique key>: '<path to your asset>'
          }
        }
      }
    })
  7. Configure django-vite settings

    master

    You can configure django-vite using a dictionary in settings.py or via legacy module-level settings.

    Dictionary Configuration (Recommended): Use the DJANGO_VITE dictionary to define one or more app configurations. This supports multi-app setups.

    DJANGO_VITE = {
      "default": {
        "dev_mode": True
      }
    }

    Legacy Configuration:

    DJANGO_VITE_DEV_MODE = True

    Dev Mode Behavior:

    • dev_mode=True: Assets are loaded as modules via the ViteJS webserver, enabling Hot Module Replacement (HMR).
    • dev_mode=False: Assets are loaded as standard static files. You must compile assets with ViteJS before use.
  8. Configure django-vite settings in settings.py

    master

    In version 3.x, you can define configuration for each app using the DJANGO_VITE dictionary in your settings.py. This is the preferred method over using legacy module-level settings (e.g., DJANGO_VITE_DEV_MODE).

    # settings.py
    DJANGO_VITE = {
        'dev_mode': True,
        'dev_server_port': 5173,
        # ... other settings
    }
  9. Configure Whitenoise for Vite immutable assets

    master

    When using Whitenoise, Vite-generated files (which include hashes) are not automatically treated as immutable. To ensure correct cache-control headers, define a custom WHITENOISE_IMMUTABLE_FILE_TEST that matches Vite's hash pattern (e.g., filename-HASH.ext).

    import re
    
    # Match vite (rollup)-generated hashes, e.g., `some_file-CSliV9zW.js`
    def immutable_file_test(path, url):
        return re.match(r"^.+[.-][0-9a-zA-Z_-]{8,12}\..+$", url)
    
    WHITENOISE_IMMUTABLE_FILE_TEST = immutable_file_test
  10. Override attributes in vite_asset tags

    master

    The {% vite_asset %} tag allows you to override or add custom attributes to the generated <script> tag. By default, it uses type="module" and crossorigin="".

    Examples:

    • Adding custom attributes: {% vite_asset 'path/to/asset' foo="bar" data_turbo_track="reload" %}
    • Using context variables: {% vite_asset 'path/to/asset' foo=request.GET.bar %}
    • Overriding default attributes (e.g., crossorigin): {% vite_asset 'path/to/asset' crossorigin="anonymous" %}
    {% vite_asset '<path to your asset>' foo="bar" hello="world" data_turbo_track="reload" %}
  11. Use django-vite template tags

    master

    To use the library in your Django templates, first load the tags:

    {% load django_vite %}

    Core Tags

    • {% vite_hmr_client %}: Add this to your <head>. It includes the ViteJS HMR client script only if dev_mode is True.
    • {% vite_asset '<path>' %}: Loads a JS/TS script as a module (type="module"). In production, it automatically loads dependent CSS files from manifest.json. The path should be relative to your Vite root or a key in manifest.json.
    • {% vite_asset_url '<path>' %}: Returns only the URL of the asset without any surrounding HTML tags. Warning: This does not resolve dependent assets (like CSS).
    • {% vite_react_refresh %}: Generates the script needed for React HMR. You can pass attributes like nonce for CSP support: {% vite_react_refresh nonce="{{ request.csp_nonce }}" %}.
    • {% vite_legacy_polyfills %}: Add this before the closing </body> tag to load polyfills for legacy browsers (only works in production).
    • {% vite_legacy_asset '<path>' %}: Loads the legacy version of an asset (e.g., main-legacy.js) with a nomodule attribute for older browsers.
    {% load django_vite %}
    
    <head>
      {% vite_hmr_client %}
      {% vite_asset 'src/main.ts' %}
    </head>
    
    <body>
      ... 
      {% vite_legacy_polyfills %}
      {% vite_legacy_asset 'src/main-legacy.js' %}
    </body>
  12. Reference: django-vite configuration variables

    master

    The following configuration options are available within the DJANGO_VITE dictionary. Note that legacy keys are provided for backward compatibility but should be migrated to the new dictionary format.

    ### dev_mode
    - Type: `bool` (Default: `False`)
    - Legacy Key: `DJANGO_VITE_DEV_MODE`
    - Description: Indicates whether to serve assets via the ViteJS development server or from compiled production assets.
    
    ### dev_server_protocol
    - Type: `str` (Default: `"http"`)
    - Legacy Key: `DJANGO_VITE_DEV_SERVER_PROTOCOL`
    - Description: The protocol used by the ViteJS webserver.
    
    ### dev_server_host
    - Type: `str` (Default: `"localhost"`)
    - Legacy Key: `DJANGO_VITE_DEV_SERVER_HOST`
    - Description: The `server.host` in `vite.config.js` for the ViteJS development server.
    
    ### dev_server_port
    - Type: `int` (Default: `5173`)
    - Legacy Key: `DJANGO_VITE_DEV_SERVER_PORT`
    - Description: The `server.port` in `vite.config.js` for the ViteJS development server.
    
    ### static_url_prefix
    - Type: `str` (Default: `""`)
    - Legacy Key: `DJANGO_VITE_STATIC_URL_PREFIX`
    - Description: The directory prefix for static files built by ViteJS. Used in both dev and production modes.
    
    ### manifest_path
    - Type: `str | Path` (Default: `Path(settings.STATIC_ROOT) / static_url_prefix / "manifest.json"`)
    - Legacy Key: `DJANGO_VITE_MANIFEST_PATH`
    - Description: The absolute path to the ViteJS manifest file located in `build.outDir`.
    
    ### legacy_polyfills_motif
    - Type: `str` (Default: `"legacy-polyfills"`)
    - Legacy Key: `DJANGO_VITE_LEGACY_POLYFILLS_MOTIF`
    - Description: Motif used to identify assets for polyfills in `manifest.json` (requires `@vitejs/plugin-legacy`).
    
    ### ws_client_url
    - Type: `str` (Default: `"@vite/client"`)
    - Legacy Key: `DJANGO_VITE_WS_CLIENT_URL`
    - Description: The path to the HMR client used in the `vite_hmr_client` tag.
    
    ### react_refresh_url
    - Type: `str` (Default: `"@react-refresh"`)
    - Legacy Key: `DJANGO_VITE_REACT_REFRESH_URL`
    - Description: Path for Javascript needed to support React HMR.
    
    ### app_client_class
    - Type: `str` (Default: `"django_vite.core.asset_loader.DjangoViteAppClient"`)
    - Description: Fully qualified name of a Python class to extend or replace `DjangoViteAppClient` (e.g., for loading manifests from S3).