├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── backend ├── __init__.py ├── settings.py ├── settingsdev.py ├── templates │ └── index.html ├── urls.py ├── views.py └── wsgi.py ├── frontend ├── App.vue ├── assets │ └── logo.png └── main.js ├── manage ├── package.json ├── requirements-dev.txt ├── requirements.txt ├── server.js ├── static └── .gitkeep └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["es2015", { "modules": false }], 4 | "stage-2" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.json] 12 | indent_size = 2 13 | 14 | [.babelrc] 15 | indent_size = 2 16 | 17 | [*.md] 18 | trim_trailing_whitespace = false 19 | 20 | [Makefile] 21 | indent_style = tab 22 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | static/**/*.js 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | parserOptions: { 5 | sourceType: 'module' 6 | }, 7 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 8 | extends: 'standard', 9 | // required to lint *.vue files 10 | plugins: [ 11 | 'html' 12 | ], 13 | // add your custom rules here 14 | 'rules': { 15 | // allow paren-less arrow functions 16 | 'arrow-parens': 0, 17 | // allow async-await 18 | 'generator-star-spacing': 0, 19 | // allow debugger during development 20 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 21 | // 4 space indentation 22 | 'indent': ['error', 4], 23 | // Allow extra semicolons 24 | 'semi': 0 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | static/dist 4 | npm-debug.log 5 | .idea 6 | .venv 7 | db.sqlite3 8 | webpack-stats.json 9 | __pycache__ 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | 26 | Author: Rokas Kupstys 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Use development settings for running django dev server. 2 | export DJANGO_SETTINGS_MODULE=backend.settingsdev 3 | 4 | # Initializes virtual environment with basic requirements. 5 | prod: 6 | pip install -r requirements.txt 7 | npm install --production 8 | 9 | # Installs development requirements. 10 | dev: 11 | pip install -r requirements.txt 12 | pip install -r requirements-dev.txt 13 | npm install 14 | 15 | # Runs development server. 16 | # This step depends on `make dev`, however dependency is excluded to speed up dev server startup. 17 | run: 18 | npm run dev & python ./manage runserver 19 | 20 | # Creates migrations and migrates database. 21 | # This step depends on `make dev`, however dependency is excluded to speed up dev server startup. 22 | migrate: 23 | python ./manage makemigrations 24 | python ./manage migrate 25 | 26 | # Builds files for distribution which will be placed in /static/dist 27 | build: prod migrate 28 | npm run build 29 | 30 | # Cleans up folder by removing virtual environment, node modules and generated files. 31 | clean: 32 | rm -rf node_modules 33 | rm -rf static/dist 34 | 35 | # Run linter 36 | lint: 37 | @npm run lint --silent 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hello-vue + Django 2 | 3 | This is a boilerplate project for using vuejs with Django. 4 | 5 | ### 中文详细教程 6 | [Django + Vue 单页面应用的开发环境搭建步骤](http://www.jianshu.com/p/fe74907e16b9) 7 | 8 | ### Features 9 | * Django backend in `./backend` 10 | * vuejs (v2) frontend in `./frontend` 11 | * Hot-reload with vue-loader 12 | * eslint linter integration 13 | * Makefile to make your life easy 14 | 15 | 16 | ### Development environment setup 17 | 18 | These steps will install all required dependencies including development ones, run migrations and start dev server. 19 | 20 | ```bash 21 | make dev 22 | make migrate 23 | make run 24 | ``` 25 | 26 | ### Deployment 27 | 28 | These steps will install productio dependencies and build vuejs application to `static/dist` folder. 29 | 30 | ```bash 31 | make prod 32 | make build 33 | ``` 34 | 35 | ### Be aware 36 | 37 | For the sake of simplicity Django config is contained within it's own backend app. In real world setting you would 38 | probably want to remove `backend` from `INSTALLED_APPS`, create a new app and move `backend.views` to it. 39 | 40 | You probably want to create python virtual environment as well. Default python instance available will be used. 41 | -------------------------------------------------------------------------------- /backend/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kele59/hello-vue-django/65053fa67dbefaaf41246f232f67ec4c6d7ea23d/backend/__init__.py -------------------------------------------------------------------------------- /backend/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for backend project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.10.4. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.10/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.10/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | # Quick-start development settings - unsuitable for production 19 | # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ 20 | 21 | # SECURITY WARNING: keep the secret key used in production secret! 22 | SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'VERY_SECRET_KEY_THAT_YOU_SHOULD_CHANGE') 23 | 24 | # SECURITY WARNING: don't run with debug turned on in production! 25 | DEBUG = False 26 | 27 | ALLOWED_HOSTS = [] 28 | 29 | # Application definition 30 | 31 | INSTALLED_APPS = [ 32 | 'django.contrib.admin', 33 | 'django.contrib.auth', 34 | 'django.contrib.contenttypes', 35 | 'django.contrib.sessions', 36 | 'django.contrib.messages', 37 | 'django.contrib.staticfiles', 38 | 'webpack_loader', 39 | 'backend' 40 | ] 41 | 42 | MIDDLEWARE = [ 43 | 'django.middleware.security.SecurityMiddleware', 44 | 'django.contrib.sessions.middleware.SessionMiddleware', 45 | 'django.middleware.common.CommonMiddleware', 46 | 'django.middleware.csrf.CsrfViewMiddleware', 47 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 48 | 'django.contrib.messages.middleware.MessageMiddleware', 49 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 50 | ] 51 | 52 | ROOT_URLCONF = 'backend.urls' 53 | 54 | TEMPLATES = [ 55 | { 56 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 57 | 'DIRS': [], 58 | 'APP_DIRS': True, 59 | 'OPTIONS': { 60 | 'context_processors': [ 61 | 'django.template.context_processors.debug', 62 | 'django.template.context_processors.request', 63 | 'django.contrib.auth.context_processors.auth', 64 | 'django.contrib.messages.context_processors.messages', 65 | ], 66 | }, 67 | }, 68 | ] 69 | 70 | WSGI_APPLICATION = 'backend.wsgi.application' 71 | 72 | # Database 73 | # https://docs.djangoproject.com/en/1.10/ref/settings/#databases 74 | 75 | DATABASES = { 76 | 'default': { 77 | 'ENGINE': 'django.db.backends.sqlite3', 78 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 79 | } 80 | } 81 | 82 | # Password validation 83 | # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators 84 | 85 | AUTH_PASSWORD_VALIDATORS = [ 86 | { 87 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 88 | }, 89 | { 90 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 91 | }, 92 | { 93 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 94 | }, 95 | { 96 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 97 | }, 98 | ] 99 | 100 | # Internationalization 101 | # https://docs.djangoproject.com/en/1.10/topics/i18n/ 102 | 103 | LANGUAGE_CODE = 'en-us' 104 | TIME_ZONE = 'UTC' 105 | USE_I18N = True 106 | USE_L10N = True 107 | USE_TZ = True 108 | 109 | # Static files (CSS, JavaScript, Images) 110 | # https://docs.djangoproject.com/en/1.10/howto/static-files/ 111 | 112 | STATIC_URL = '/static/' 113 | STATICFILES_DIRS = [ 114 | os.path.join(BASE_DIR, 'static'), 115 | ] 116 | 117 | WEBPACK_LOADER = { 118 | 'DEFAULT': { 119 | 'BUNDLE_DIR_NAME': 'dist/', 120 | 'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'), 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /backend/settingsdev.py: -------------------------------------------------------------------------------- 1 | from .settings import * 2 | 3 | DEBUG = True 4 | INTERNAL_IPS = ['127.0.0.1'] 5 | ALLOWED_HOSTS += INTERNAL_IPS 6 | ALLOWED_HOSTS.append('localhost') 7 | INSTALLED_APPS.append('debug_toolbar') 8 | MIDDLEWARE.append('debug_toolbar.middleware.DebugToolbarMiddleware') 9 | -------------------------------------------------------------------------------- /backend/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | {% load render_bundle from webpack_loader %} 3 | 4 | 5 | 6 | hello-vue 7 | 8 | 9 |
10 | {% render_bundle 'main' %} 11 | 12 | 13 | -------------------------------------------------------------------------------- /backend/urls.py: -------------------------------------------------------------------------------- 1 | """backend URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.10/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: url(r'^$', 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: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf import settings 17 | from django.conf.urls import url, include 18 | from django.contrib import admin 19 | 20 | import backend.views 21 | 22 | urlpatterns = [ 23 | url(r'^admin/', admin.site.urls), 24 | url(r'^$', backend.views.index) 25 | ] 26 | 27 | if settings.DEBUG: 28 | import debug_toolbar 29 | urlpatterns.append(url(r'^__debug__/', include(debug_toolbar.urls))) 30 | -------------------------------------------------------------------------------- /backend/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | 4 | def index(request): 5 | return render(request, 'index.html') 6 | -------------------------------------------------------------------------------- /backend/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for backend 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/1.10/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /frontend/App.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 32 | 33 | 61 | -------------------------------------------------------------------------------- /frontend/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kele59/hello-vue-django/65053fa67dbefaaf41246f232f67ec4c6d7ea23d/frontend/assets/logo.png -------------------------------------------------------------------------------- /frontend/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | // eslint-disable-next-line no-new 5 | new Vue({ 6 | el: '#app', 7 | render: h => h(App) 8 | }); 9 | -------------------------------------------------------------------------------- /manage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django 15 | except ImportError: 16 | raise ImportError( 17 | 'Couldn\'t import Django. Are you sure it\'s installed and ' 18 | 'available on your PYTHONPATH environment variable? Did you ' 19 | 'forget to activate a virtual environment?' 20 | ) 21 | raise 22 | execute_from_command_line(sys.argv) 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello-vue-django", 3 | "description": "A Vue.js project", 4 | "version": "1.0.0", 5 | "author": " <>", 6 | "private": true, 7 | "scripts": { 8 | "lint": "eslint --ext .js,.vue frontend", 9 | "dev": "cross-env NODE_ENV=development node server.js", 10 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules" 11 | }, 12 | "dependencies": { 13 | "vue": "^2.1.0" 14 | }, 15 | "devDependencies": { 16 | "babel-core": "^6.0.0", 17 | "babel-eslint": "^7.0.0", 18 | "babel-loader": "^6.0.0", 19 | "babel-preset-es2015": "^6.0.0", 20 | "babel-preset-stage-2": "^6.22.0", 21 | "cross-env": "^3.0.0", 22 | "css-loader": "^0.26.1", 23 | "eslint-friendly-formatter": "^2.0.5", 24 | "eslint-loader": "^1.5.0", 25 | "eslint": "^3.12.2", 26 | "eslint-config-standard": "^6.2.1", 27 | "eslint-plugin-html": "^1.7.0", 28 | "eslint-plugin-promise": "^3.4.0", 29 | "eslint-plugin-standard": "^2.0.1", 30 | "file-loader": "^0.9.0", 31 | "vue-loader": "^10.0.0", 32 | "vue-template-compiler": "^2.1.0", 33 | "webpack": "^2.1.0-beta.25", 34 | "webpack-bundle-tracker": "^0.2.0", 35 | "webpack-dev-server": "^2.1.0-beta.9" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | django-debug-toolbar 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django 2 | django-webpack-loader 3 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var config = require('./webpack.config'); 4 | 5 | // Dev server address specified in webpack.config.js 6 | var listen_addr = 'localhost'; 7 | // Dev server port specified in webpack.config.js 8 | var listen_port = 8001; 9 | 10 | new WebpackDevServer(webpack(config), { 11 | publicPath: config.output.publicPath, 12 | hot: true, 13 | inline: true, 14 | headers: { "Access-Control-Allow-Origin": "*" }, 15 | historyApiFallback: true 16 | }).listen(listen_port, listen_addr, function (err, result) 17 | { 18 | if (err) 19 | { 20 | console.log(err); 21 | } 22 | 23 | console.log('Listening at ' + listen_addr + ':' + listen_port); 24 | }); 25 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kele59/hello-vue-django/65053fa67dbefaaf41246f232f67ec4c6d7ea23d/static/.gitkeep -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var BundleTracker = require('webpack-bundle-tracker'); 4 | 5 | // Directory for deployed assets. It should be within our static files path. 6 | // Backslash at the end is not required. 7 | var dist_dir = '/static/dist'; 8 | // Controls use of hot-reload devserver. When this is used you must also run `node server.js` 9 | var use_hot_reload = process.env.NODE_ENV !== 'production'; 10 | // Dev server address specified in server.js 11 | var dev_server_addr = 'localhost'; 12 | // Dev server port specified in server.js 13 | var dev_server_port = 8001; 14 | 15 | module.exports = { 16 | entry: ['./frontend/main.js'], 17 | output: { 18 | path: path.resolve(__dirname, '.' + dist_dir + '/'), 19 | filename: '[name]-[hash].js', 20 | publicPath: dist_dir + '/', 21 | }, 22 | plugins: [ 23 | new BundleTracker({filename: './webpack-stats.json'}), 24 | ], 25 | module: { 26 | rules: [ 27 | { 28 | test: /\.vue$/, 29 | loader: 'vue-loader', 30 | options: { 31 | loaders: { 32 | // Since sass-loader (weirdly) has SCSS as its default parse mode, we map 33 | // the "scss" and "sass" values for the lang attribute to the right configs here. 34 | // other preprocessors should work out of the box, no loader config like this nessessary. 35 | 'scss': 'vue-style-loader!css-loader!sass-loader', 36 | 'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax' 37 | } 38 | // other vue-loader options go here 39 | } 40 | }, 41 | { 42 | test: /\.js$/, 43 | loader: 'babel-loader', 44 | exclude: /node_modules/ 45 | }, 46 | { 47 | test: /\.(png|jpg|gif|svg)$/, 48 | loader: 'file-loader', 49 | options: { 50 | name: '[name].[ext]?[hash]' 51 | } 52 | } 53 | ] 54 | }, 55 | resolve: { 56 | alias: { 57 | 'vue$': 'vue/dist/vue.common.js' 58 | } 59 | }, 60 | devServer: { 61 | historyApiFallback: true, 62 | noInfo: true 63 | }, 64 | performance: { 65 | hints: false 66 | }, 67 | devtool: '#eval-source-map' 68 | }; 69 | 70 | if (process.env.NODE_ENV === 'production') 71 | { 72 | module.exports.devtool = '#source-map' 73 | // http://vue-loader.vuejs.org/en/workflow/production.html 74 | module.exports.plugins = (module.exports.plugins || []).concat([ 75 | new webpack.DefinePlugin({ 76 | 'process.env': { 77 | NODE_ENV: '"production"' 78 | } 79 | }), 80 | new webpack.optimize.UglifyJsPlugin({ 81 | sourceMap: true, 82 | compress: { 83 | warnings: false 84 | } 85 | }), 86 | new webpack.LoaderOptionsPlugin({ 87 | minimize: true 88 | }) 89 | ]) 90 | } 91 | else if (use_hot_reload) 92 | { 93 | module.exports.entry.push('webpack-dev-server/client?http://' + dev_server_addr + ':' + dev_server_port); 94 | module.exports.entry.push('webpack/hot/only-dev-server'); 95 | module.exports.output['publicPath'] = 'http://' + dev_server_addr + ':' + dev_server_port + dist_dir + '/'; 96 | module.exports.plugins.push(new webpack.HotModuleReplacementPlugin()); 97 | module.exports.plugins.push(new webpack.NoEmitOnErrorsPlugin()); // don't reload if there is an error 98 | } 99 | --------------------------------------------------------------------------------