├── django_vite ├── __init__.py └── templatetags │ ├── __init__.py │ └── django_vite.py ├── .gitignore ├── MANIFEST.in ├── pyproject.toml ├── .github └── workflows │ ├── pre-commit.yml │ └── pypi_publish.yml ├── .pre-commit-config.yaml ├── setup.py ├── README.md └── LICENSE /django_vite/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | -------------------------------------------------------------------------------- /django_vite/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include LICENSE 3 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 79 3 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml: -------------------------------------------------------------------------------- 1 | name: "Run pre-commit" 2 | 3 | on: 4 | pull_request: 5 | push: 6 | 7 | jobs: 8 | pre-commit: 9 | runs-on: "ubuntu-latest" 10 | steps: 11 | - uses: "actions/checkout@v2" 12 | - uses: "actions/setup-python@v2" 13 | - uses: "pre-commit/action@v2.0.3" 14 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: "https://github.com/pre-commit/pre-commit-hooks" 3 | rev: "v4.1.0" 4 | hooks: 5 | - id: "check-toml" 6 | - id: "check-yaml" 7 | - id: "end-of-file-fixer" 8 | - id: "mixed-line-ending" 9 | args: ["--fix=lf"] 10 | - id: "trailing-whitespace" 11 | 12 | - repo: "https://github.com/psf/black" 13 | rev: "22.3.0" 14 | hooks: 15 | - id: "black" 16 | 17 | - repo: "https://github.com/PyCQA/flake8" 18 | rev: "4.0.1" 19 | hooks: 20 | - id: "flake8" 21 | 22 | - repo: "https://github.com/commitizen-tools/commitizen" 23 | rev: master 24 | hooks: 25 | - id: "commitizen" 26 | stages: ["commit-msg"] 27 | -------------------------------------------------------------------------------- /.github/workflows/pypi_publish.yml: -------------------------------------------------------------------------------- 1 | name: "Publish to PyPi" 2 | 3 | on: 4 | release: 5 | types: ["published"] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: "ubuntu-latest" 10 | steps: 11 | - uses: "actions/checkout@v2" 12 | - name: "Setup Python" 13 | uses: "actions/setup-python@v2" 14 | with: 15 | python-version: "3.x" 16 | - name: "Install dependencies" 17 | run: | 18 | python -m pip install --upgrade pip 19 | pip install setuptools wheel twine 20 | - name: "Build and publish" 21 | env: 22 | TWINE_USERNAME: "${{ secrets.PYPI_USERNAME }}" 23 | TWINE_PASSWORD: "${{ secrets.PYPI_PASSWORD }}" 24 | run: | 25 | python setup.py sdist bdist_wheel 26 | twine upload dist/* 27 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from os import path 2 | 3 | from setuptools import find_packages, setup 4 | 5 | this_directory = path.abspath(path.dirname(__file__)) 6 | 7 | with open(path.join(this_directory, "README.md"), encoding="utf-8") as f: 8 | README = f.read() 9 | 10 | 11 | setup( 12 | name="django-vite", 13 | version="2.0.2", 14 | description="Integration of ViteJS in a Django project.", 15 | long_description=README, 16 | long_description_content_type="text/markdown", 17 | author="MrBin99", 18 | url="https://github.com/MrBin99/django-vite", 19 | include_package_data=True, 20 | packages=find_packages(), 21 | requires=[ 22 | "Django (>=1.11)", 23 | ], 24 | install_requires=[ 25 | "Django>=1.11", 26 | ], 27 | extras_require={"dev": ["black", "flake8"]}, 28 | ) 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Django Vite 2 | 3 | [![PyPI version](https://badge.fury.io/py/django-vite.svg)](https://badge.fury.io/py/django-vite) 4 | 5 | Integration of [ViteJS](https://vitejs.dev/) in a Django project. 6 | 7 | ## Installation 8 | 9 | ### Django 10 | 11 | ``` 12 | pip install django-vite 13 | ``` 14 | 15 | Add `django_vite` to your `INSTALLED_APPS` in your `settings.py` 16 | (before your apps that are using it). 17 | 18 | ```python 19 | INSTALLED_APPS = [ 20 | ... 21 | 'django_vite', 22 | ... 23 | ] 24 | ``` 25 | 26 | ### ViteJS 27 | 28 | Follow instructions on [https://vitejs.dev/guide/](https://vitejs.dev/guide/). 29 | And mostly the SSR part. 30 | 31 | Then in your ViteJS config file : 32 | 33 | - Set the `base` options the same as your `STATIC_URL` Django setting. 34 | - Set the `build.outDir` path to where you want the assets to compiled. 35 | - Set the `build.manifest` options to `true`. 36 | - As you are in SSR and not in SPA, you don't have an `index.html` that 37 | ViteJS can use to determine which files to compile. You need to tell it 38 | directly. In your ViteJS config file add the following : 39 | 40 | ```javascript 41 | export default defineConfig({ 42 | build { 43 | ... 44 | rollupOptions: { 45 | input: { 46 | : '' 47 | } 48 | } 49 | } 50 | } 51 | ``` 52 | 53 | ### Assets 54 | 55 | As recommended on Vite's [backend integration guide](https://vitejs.dev/guide/backend-integration.html), your assets should include the modulepreload polyfill. 56 | 57 | ```javascript 58 | // Add this at the beginning of your app entry. 59 | import 'vite/modulepreload-polyfill'; 60 | ``` 61 | 62 | ## Usage 63 | 64 | ### Configuration 65 | 66 | - Define a setting variable in your `settings.py` named `DJANGO_VITE_ASSETS_PATH` 67 | containing the absolute path to where your assets are built. 68 | 69 | - This must correspond to your `build.outDir` in your ViteJS configuration. 70 | - The `DJANGO_VITE_ASSETS_PATH` must be included in your `STATICFILES_DIRS` 71 | Django setting. 72 | 73 | - Define a setting variable in your `settings.py` named `DJANGO_VITE_DEV_MODE` 74 | containing a boolean defining if you want to include assets in development 75 | mode or production mode. 76 | 77 | - In development mode, assets are included as modules using the ViteJS 78 | webserver. This will enable HMR for your assets. 79 | - In production mode, assets are included as standard assets 80 | (no ViteJS webserver and HMR) like default Django static files. 81 | This means that your assets must be compiled with ViteJS before. 82 | - This setting may be set as the same value as your `DEBUG` setting in 83 | Django. But you can do what is good for your needs. 84 | 85 | Note : `DJANGO_VITE_ASSETS_PATH` supports `pathlib.Path` syntax or pure `str`. 86 | 87 | ### Template tags 88 | 89 | Include this in your base HTML template file. 90 | 91 | ``` 92 | {% load django_vite %} 93 | ``` 94 | 95 | Then in your `` element add this : 96 | 97 | ``` 98 | {% vite_hmr_client %} 99 | ``` 100 | 101 | - This will add a `' 371 | 372 | @staticmethod 373 | def _generate_stylesheet_tag(href: str) -> str: 374 | """ 375 | Generates and HTML stylesheet tag for CSS. 376 | 377 | Arguments: 378 | href {str} -- CSS file URL. 379 | 380 | Returns: 381 | str -- CSS link tag. 382 | """ 383 | 384 | return f'' 385 | 386 | @staticmethod 387 | def _generate_vite_server_url(path: str) -> str: 388 | """ 389 | Generates an URL to and asset served by the Vite development server. 390 | 391 | Keyword Arguments: 392 | path {str} -- Path to the asset. 393 | 394 | Returns: 395 | str -- Full URL to the asset. 396 | """ 397 | 398 | return urljoin( 399 | f"{DJANGO_VITE_DEV_SERVER_PROTOCOL}://" 400 | f"{DJANGO_VITE_DEV_SERVER_HOST}:{DJANGO_VITE_DEV_SERVER_PORT}", 401 | urljoin(DJANGO_VITE_STATIC_URL, path), 402 | ) 403 | 404 | 405 | # Make Loader instance at startup to prevent threading problems 406 | DjangoViteAssetLoader.instance() 407 | 408 | 409 | @register.simple_tag 410 | @mark_safe 411 | def vite_hmr_client() -> str: 412 | """ 413 | Generates the script tag for the Vite WS client for HMR. 414 | Only used in development, in production this method returns 415 | an empty string. 416 | 417 | Returns: 418 | str -- The script tag or an empty string. 419 | """ 420 | 421 | return DjangoViteAssetLoader.generate_vite_ws_client() 422 | 423 | 424 | @register.simple_tag 425 | @mark_safe 426 | def vite_asset( 427 | path: str, 428 | **kwargs: Dict[str, str], 429 | ) -> str: 430 | """ 431 | Generates a