├── app
├── __init__.py
├── migrations
│ └── __init__.py
├── models.py
├── admin.py
├── tests.py
├── apps.py
├── urls.py
├── views.py
├── static
│ └── src
│ │ ├── main.ts
│ │ └── pages
│ │ ├── About.vue
│ │ └── Index.vue
└── templates
│ └── index.html
├── inertia_django_vite_vue_minimal
├── __init__.py
├── asgi.py
├── wsgi.py
├── urls.py
└── settings.py
├── requirements.txt
├── .vscode
├── extensions.json
└── settings.json
├── package.json
├── vite.config.ts
├── manage.py
├── README.md
└── .gitignore
/app/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/inertia_django_vite_vue_minimal/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | # Create your models here.
4 |
--------------------------------------------------------------------------------
/app/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/app/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Django==4.2.8
2 | django-vite==3.0.1
3 | inertia-django==0.5.3
4 | pip-autoremove==0.10.0
5 | whitenoise==6.6.0
--------------------------------------------------------------------------------
/app/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class AppConfig(AppConfig):
5 | default_auto_field = "django.db.models.BigAutoField"
6 | name = "app"
7 |
--------------------------------------------------------------------------------
/app/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from . import views
4 |
5 | urlpatterns = [
6 | path("", views.index, name="index"),
7 | path("about", views.about, name="about"),
8 | ]
9 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "batisteo.vscode-django",
4 | "esbenp.prettier-vscode",
5 | "hookyqr.beautify",
6 | "ms-python.vscode-pylance",
7 | "vue.volar"
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/app/views.py:
--------------------------------------------------------------------------------
1 | from django.http import HttpRequest
2 | from inertia import render
3 |
4 |
5 | def index(request):
6 | return render(request, "Index", props={"name": "World"})
7 |
8 |
9 | def about(request):
10 | return render(request, "About", props={"pageName": "About"})
11 |
--------------------------------------------------------------------------------
/app/static/src/main.ts:
--------------------------------------------------------------------------------
1 | import "vite/modulepreload-polyfill";
2 | import { createApp, h } from "vue";
3 | import { createInertiaApp } from "@inertiajs/vue3";
4 |
5 | createInertiaApp({
6 | resolve: (name) => import(`./pages/${name}.vue`),
7 | setup({ el, App, props, plugin }) {
8 | createApp({ render: () => h(App, props) })
9 | .use(plugin)
10 | .mount(el);
11 | },
12 | });
13 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "inertia-django-vite-vue-minimal",
3 | "version": "0.0.0",
4 | "type": "module",
5 | "description": "A minimal, working template for Inertia + Django + Vite + Vue.",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build"
9 | },
10 | "dependencies": {
11 | "@inertiajs/vue3": "^1.0.14",
12 | "@types/node": "^20.10.5",
13 | "@vitejs/plugin-vue": "^5.0.0",
14 | "vite": "^5.0.10",
15 | "vue": "^3.4.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/templates/index.html:
--------------------------------------------------------------------------------
1 | {% load django_vite %}
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | {% vite_hmr_client %}
11 | {% vite_asset 'main.ts' %}
12 |
13 | Inertia + Django + Vite + Vue minimal
14 |
15 |
16 |
17 | {% block inertia %}{% endblock %}
18 |
19 |
20 |
--------------------------------------------------------------------------------
/inertia_django_vite_vue_minimal/asgi.py:
--------------------------------------------------------------------------------
1 | """
2 | ASGI config for inertia_django_vite_vue_minimal project.
3 |
4 | It exposes the ASGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.asgi import get_asgi_application
13 |
14 | os.environ.setdefault(
15 | "DJANGO_SETTINGS_MODULE", "inertia_django_vite_vue_minimal.settings"
16 | )
17 |
18 | application = get_asgi_application()
19 |
--------------------------------------------------------------------------------
/inertia_django_vite_vue_minimal/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for inertia_django_vite_vue_minimal project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault(
15 | "DJANGO_SETTINGS_MODULE", "inertia_django_vite_vue_minimal.settings"
16 | )
17 |
18 | application = get_wsgi_application()
19 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite";
2 | import { resolve } from "path";
3 | import vue from "@vitejs/plugin-vue";
4 |
5 | export default defineConfig({
6 | root: resolve("./app/static/src"),
7 | base: "/static/",
8 | plugins: [vue()],
9 | build: {
10 | outDir: resolve("./app/static/dist"),
11 | assetsDir: "",
12 | manifest: true,
13 | emptyOutDir: true,
14 | rollupOptions: {
15 | // Overwrite default .html entry to main.ts in the static directory
16 | input: resolve("./app/static/src/main.ts"),
17 | },
18 | },
19 | });
20 |
--------------------------------------------------------------------------------
/app/static/src/pages/About.vue:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
This is the {{ pageName }} page
19 |
20 |
Count: {{ count }}
21 |
22 |
23 |
24 |
29 |
--------------------------------------------------------------------------------
/app/static/src/pages/Index.vue:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
Hello {{ name }} from Inertia + Django + Vite + Vue!
19 |
20 |
Count: {{ count }}
21 |
22 |
23 |
24 |
29 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | """Run administrative tasks."""
9 | os.environ.setdefault(
10 | "DJANGO_SETTINGS_MODULE", "inertia_django_vite_vue_minimal.settings"
11 | )
12 | try:
13 | from django.core.management import execute_from_command_line
14 | except ImportError as exc:
15 | raise ImportError(
16 | "Couldn't import Django. Are you sure it's installed and "
17 | "available on your PYTHONPATH environment variable? Did you "
18 | "forget to activate a virtual environment?"
19 | ) from exc
20 | execute_from_command_line(sys.argv)
21 |
22 |
23 | if __name__ == "__main__":
24 | main()
25 |
--------------------------------------------------------------------------------
/inertia_django_vite_vue_minimal/urls.py:
--------------------------------------------------------------------------------
1 | """inertia_django_vite_vue_minimal URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/4.1/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import include, path
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 | from django.contrib import admin
17 | from django.urls import include, path
18 |
19 | urlpatterns = [
20 | path("admin/", admin.site.urls),
21 | path("", include("app.urls")),
22 | ]
23 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "beautify.language": {
3 | "html": ["django-html"]
4 | },
5 | "emmet.includeLanguages": {
6 | "django-html": "html"
7 | },
8 | "files.associations": {
9 | "**/templates/*.html": "django-html",
10 | "**/*.html": "html",
11 | "**/requirements{/**,*}.{txt,in}": "pip-requirements"
12 | },
13 | "python.analysis.completeFunctionParens": true,
14 | "python.analysis.typeCheckingMode": "basic",
15 | "python.formatting.provider": "black",
16 | "python.languageServer": "Pylance",
17 | "[django-html]": {
18 | "editor.defaultFormatter": "HookyQR.beautify",
19 | "editor.tabSize": 2
20 | },
21 | "[javascript]": {
22 | "editor.defaultFormatter": "esbenp.prettier-vscode"
23 | },
24 | "[json]": {
25 | "editor.defaultFormatter": "esbenp.prettier-vscode"
26 | },
27 | "[jsonc]": {
28 | "editor.defaultFormatter": "esbenp.prettier-vscode"
29 | },
30 | "[typescript]": {
31 | "editor.defaultFormatter": "esbenp.prettier-vscode"
32 | },
33 | "[vue]": {
34 | "editor.defaultFormatter": "esbenp.prettier-vscode"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Inertia + Django + Vite + Vue minimal template
2 |
3 | A minimal, working template for Inertia + Django + Vite + Vue.
4 |
5 | ## Technologies
6 |
7 | 1. Inertia - powered by the official [Inertia.js Django Adapter](https://github.com/inertiajs/inertia-django)
8 | 2. Django v4.2
9 | 3. Vite 5 - powered by [Django Vite](https://github.com/MrBin99/django-vite)
10 | 4. Vue 3
11 | 5. TypeScript
12 | 6. [WhiteNoise](https://whitenoise.evans.io/en/stable/index.html) - to serve static files
13 |
14 | ## How to install & run
15 |
16 | 1. Download the repo. You can either:
17 |
18 | a. Clone the repo (without the git history):
19 |
20 | ```sh
21 | npx degit https://github.com/mujahidfa/inertia-django-vite-vue-minimal
22 | ```
23 |
24 | b. Or, create a repo based on this template via the [GitHub template generator](https://github.com/mujahidfa/inertia-django-vite-vue-minimal/generate).
25 |
26 | 2. Install required Python packages.
27 |
28 | ```sh
29 | # Create and activate a virtual environment
30 | python3 -m venv .venv
31 | source .venv/bin/activate
32 |
33 | # Install required Python packages
34 | pip install -r requirements.txt
35 | ```
36 |
37 | 3. Install required Node.js packages.
38 |
39 | ```sh
40 | npm install
41 | ```
42 |
43 | 4. Run the Vite dev server:
44 |
45 | ```sh
46 | npm run dev
47 | ```
48 |
49 | 5. Run Django's default migrations:
50 |
51 | ```sh
52 | python manage.py migrate
53 | ```
54 |
55 | 6. Run the Django dev server (in a separate terminal):
56 |
57 | ```sh
58 | python manage.py runserver
59 | ```
60 |
61 | ## How to build for production
62 |
63 | 1. Set `DEBUG=False` in [settings.py](./inertia_django_vite_vue_minimal/settings.py).
64 |
65 | ```py
66 | # In settings.py
67 | ...
68 | DEBUG=False
69 | ...
70 | ```
71 |
72 | 2. Build the JS/assets for production:
73 |
74 | ```sh
75 | npm run build
76 | ```
77 |
78 | 3. Run `collectstatic`:
79 |
80 | ```sh
81 | rm -rf staticfiles/
82 | python manage.py collectstatic
83 | ```
84 |
85 | 4. Run the Django server:
86 |
87 | ```sh
88 | python manage.py runserver
89 | ```
90 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Django #
2 | *.log
3 | *.pot
4 | *.pyc
5 | __pycache__
6 | db.sqlite3
7 | media
8 | staticfiles/
9 |
10 | # Backup files #
11 | *.bak
12 |
13 | # If you are using PyCharm #
14 | # User-specific stuff
15 | .idea/**/workspace.xml
16 | .idea/**/tasks.xml
17 | .idea/**/usage.statistics.xml
18 | .idea/**/dictionaries
19 | .idea/**/shelf
20 |
21 | # AWS User-specific
22 | .idea/**/aws.xml
23 |
24 | # Generated files
25 | .idea/**/contentModel.xml
26 |
27 | # Sensitive or high-churn files
28 | .idea/**/dataSources/
29 | .idea/**/dataSources.ids
30 | .idea/**/dataSources.local.xml
31 | .idea/**/sqlDataSources.xml
32 | .idea/**/dynamic.xml
33 | .idea/**/uiDesigner.xml
34 | .idea/**/dbnavigator.xml
35 |
36 | # Gradle
37 | .idea/**/gradle.xml
38 | .idea/**/libraries
39 |
40 | # File-based project format
41 | *.iws
42 |
43 | # IntelliJ
44 | out/
45 |
46 | # JIRA plugin
47 | atlassian-ide-plugin.xml
48 |
49 | # Python #
50 | *.py[cod]
51 | *$py.class
52 |
53 | # Distribution / packaging
54 | .Python build/
55 | develop-eggs/
56 | dist/
57 | downloads/
58 | eggs/
59 | .eggs/
60 | lib/
61 | lib64/
62 | parts/
63 | sdist/
64 | var/
65 | wheels/
66 | *.egg-info/
67 | .installed.cfg
68 | *.egg
69 | *.manifest
70 | *.spec
71 |
72 | # Installer logs
73 | pip-log.txt
74 | pip-delete-this-directory.txt
75 |
76 | # Unit test / coverage reports
77 | htmlcov/
78 | .tox/
79 | .coverage
80 | .coverage.*
81 | .cache
82 | .pytest_cache/
83 | nosetests.xml
84 | coverage.xml
85 | *.cover
86 | .hypothesis/
87 |
88 | # Jupyter Notebook
89 | .ipynb_checkpoints
90 |
91 | # pyenv
92 | .python-version
93 |
94 | # celery
95 | celerybeat-schedule.*
96 |
97 | # SageMath parsed files
98 | *.sage.py
99 |
100 | # Environments
101 | .env
102 | .venv
103 | env/
104 | venv/
105 | ENV/
106 | env.bak/
107 | venv.bak/
108 |
109 | # mkdocs documentation
110 | /site
111 |
112 | # mypy
113 | .mypy_cache/
114 |
115 | # Sublime Text #
116 | *.tmlanguage.cache
117 | *.tmPreferences.cache
118 | *.stTheme.cache
119 | *.sublime-workspace
120 | *.sublime-project
121 |
122 | # sftp configuration file
123 | sftp-config.json
124 |
125 | # Package control specific files Package
126 | Control.last-run
127 | Control.ca-list
128 | Control.ca-bundle
129 | Control.system-ca-bundle
130 | GitHub.sublime-settings
131 |
132 | .history
133 |
134 | # Logs
135 | logs
136 | *.log
137 | npm-debug.log*
138 | yarn-debug.log*
139 | yarn-error.log*
140 | pnpm-debug.log*
141 | lerna-debug.log*
142 |
143 | node_modules
144 | .DS_Store
145 | dist
146 | dist-ssr
147 | coverage
148 | *.local
149 |
150 | /cypress/videos/
151 | /cypress/screenshots/
152 |
153 | # Editor directories and files
154 | .idea
155 | *.suo
156 | *.ntvs*
157 | *.njsproj
158 | *.sln
159 | *.sw?
160 |
--------------------------------------------------------------------------------
/inertia_django_vite_vue_minimal/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for inertia_django_vite_vue_minimal project.
3 |
4 | Generated by 'django-admin startproject' using Django 4.1.2.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/4.1/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/4.1/ref/settings/
11 | """
12 |
13 | from pathlib import Path
14 | import re
15 |
16 | # Build paths inside the project like this: BASE_DIR / 'subdir'.
17 | BASE_DIR = Path(__file__).resolve().parent.parent
18 |
19 |
20 | # Quick-start development settings - unsuitable for production
21 | # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
22 |
23 | # SECURITY WARNING: keep the secret key used in production secret!
24 | SECRET_KEY = "django-insecure-0-s3nzb$^1yk(!-_e553a!&b(74^d1rg()vziok)h33!oz)mhv"
25 |
26 | # SECURITY WARNING: don't run with debug turned on in production!
27 | DEBUG = True
28 |
29 | ALLOWED_HOSTS = ["*"]
30 |
31 |
32 | # Application definition
33 |
34 | INSTALLED_APPS = [
35 | "whitenoise.runserver_nostatic",
36 | "django.contrib.admin",
37 | "django.contrib.auth",
38 | "django.contrib.contenttypes",
39 | "django.contrib.sessions",
40 | "django.contrib.messages",
41 | "django.contrib.staticfiles",
42 | "django_vite",
43 | "inertia",
44 | "app",
45 | ]
46 |
47 | MIDDLEWARE = [
48 | "django.middleware.security.SecurityMiddleware",
49 | "whitenoise.middleware.WhiteNoiseMiddleware",
50 | "django.contrib.sessions.middleware.SessionMiddleware",
51 | "django.middleware.common.CommonMiddleware",
52 | "django.middleware.csrf.CsrfViewMiddleware",
53 | "django.contrib.auth.middleware.AuthenticationMiddleware",
54 | "django.contrib.messages.middleware.MessageMiddleware",
55 | "django.middleware.clickjacking.XFrameOptionsMiddleware",
56 | "inertia.middleware.InertiaMiddleware",
57 | ]
58 |
59 | ROOT_URLCONF = "inertia_django_vite_vue_minimal.urls"
60 |
61 | TEMPLATES = [
62 | {
63 | "BACKEND": "django.template.backends.django.DjangoTemplates",
64 | "DIRS": [],
65 | "APP_DIRS": True,
66 | "OPTIONS": {
67 | "context_processors": [
68 | "django.template.context_processors.debug",
69 | "django.template.context_processors.request",
70 | "django.contrib.auth.context_processors.auth",
71 | "django.contrib.messages.context_processors.messages",
72 | ],
73 | },
74 | },
75 | ]
76 |
77 | WSGI_APPLICATION = "inertia_django_vite_vue_minimal.wsgi.application"
78 |
79 |
80 | # Database
81 | # https://docs.djangoproject.com/en/4.1/ref/settings/#databases
82 |
83 | DATABASES = {
84 | "default": {
85 | "ENGINE": "django.db.backends.sqlite3",
86 | "NAME": BASE_DIR / "db.sqlite3",
87 | }
88 | }
89 |
90 |
91 | # Password validation
92 | # https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
93 |
94 | AUTH_PASSWORD_VALIDATORS = [
95 | {
96 | "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
97 | },
98 | {
99 | "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
100 | },
101 | {
102 | "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
103 | },
104 | {
105 | "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
106 | },
107 | ]
108 |
109 |
110 | # Internationalization
111 | # https://docs.djangoproject.com/en/4.1/topics/i18n/
112 |
113 | LANGUAGE_CODE = "en-us"
114 |
115 | TIME_ZONE = "UTC"
116 |
117 | USE_I18N = True
118 |
119 | USE_TZ = True
120 |
121 |
122 | # Default primary key field type
123 | # https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
124 |
125 | DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
126 |
127 |
128 | # django-vite settings
129 | # https://github.com/MrBin99/django-vite
130 | DJANGO_VITE_DEV_MODE = DEBUG # follow Django's dev mode
131 |
132 | # Where ViteJS assets are built.
133 | DJANGO_VITE_ASSETS_PATH = BASE_DIR / "app" / "static" / "dist"
134 |
135 | # If use HMR or not. We follow Django's DEBUG mode
136 | DJANGO_VITE_DEV_MODE = DEBUG
137 |
138 | # Vite 3 defaults to 5173. Default for django-vite is 3000, which is the default for Vite 2.
139 | DJANGO_VITE_DEV_SERVER_PORT = 5173
140 |
141 |
142 | # Static files (CSS, JavaScript, Images)
143 | # https://docs.djangoproject.com/en/4.1/howto/static-files/
144 |
145 | STATIC_URL = "static/"
146 |
147 | # Output directory for collectstatic to put all your static files into.
148 | STATIC_ROOT = BASE_DIR / "staticfiles"
149 |
150 | # Include DJANGO_VITE_ASSETS_PATH into STATICFILES_DIRS to be copied inside
151 | # when run command python manage.py collectstatic
152 | STATICFILES_DIRS = [DJANGO_VITE_ASSETS_PATH]
153 |
154 | # Inertia settings
155 | INERTIA_LAYOUT = BASE_DIR / "app" / "templates/index.html"
156 |
157 | # Vite generates files with 8 hash digits
158 | # http://whitenoise.evans.io/en/stable/django.html#WHITENOISE_IMMUTABLE_FILE_TEST
159 | def immutable_file_test(path, url):
160 | # Match filename with 12 hex digits before the extension
161 | # e.g. app.db8f2edc0c8a.js
162 | return re.match(r"^.+\.[0-9a-f]{8,12}\..+$", url)
163 |
164 |
165 | WHITENOISE_IMMUTABLE_FILE_TEST = immutable_file_test
166 |
--------------------------------------------------------------------------------