Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Vue.js con Django
¿tiene sentido? @javierabadia
@VueJSMadrid
¿Tiene sentido una SPA con backend?
• Autenticación
• Persistencia
• Proceso de Datos
• Acceso a almacenes
de datos extern...
¿por qué Django frente a Node.js?
La experiencia ‘óptima’ de desarrollo
• Trabajar de forma unificada
(mismo IDE)
• Desarrollo en el backend
• debugging
• b...
La estructura clásica de Django
Vistas
Templates
Modelos
ORM
Autenticación
Middleware
Formularios
Administración
HTML
Ejemplo: Catálogo de GIFs para IoT
http://localhost:8000/ http://localhost:8000/detail/323
DEMO
Arquitectura de una SPA de Vue.js
$ vue init webpack-simple frontend
$ cd frontend
$ yarn
$ npm run dev
localhost:8080
El puente entre Django y Webpack
$ cd frontend
$ npm install --save-dev webpack-bundle-tracker
# (en un virtualenv, por su...
Todo junto
var path = require('path')
var webpack = require('webpack')
var BundleTracker = require('webpack-bundle-tracker...
def index(request):
return render(request, 'index.html', {})
# backend/views.py
{% extends 'base.html' %}
{% load render_b...
Webpack: detalles de configuración
var path = require('path')
var webpack = require('webpack')
var BundleTracker = require...
Django
:8000
localhost:8000/
HTML
localhost:8000/api/*
JSON
Implementar una API ¿REST?
urlpatterns = [
url(r'^api/pics', api.pics),
url(r'^', views.index),
]
# backend/urls.py
def pi...
Autenticación
Una posible implementación: 2PA
http://localhost:8000/login http://localhost:8000/*
create session
redirect
...
Django + auth + sessions
<script>
export default {
name: 'app',
data() {
return {
msg: 'Welcome to Your Vue.js App!',
user...
DEMO
Rutas
urlpatterns = [
url(r'^api/suggestions/$', api.suggestions),
url(r'^api/search/$', api.search),
url(r'^api/pics/(?P<...
Comentarios Finales
• APIs
• REST?
• ‘a pelo’
• django-tastypie
• django-rest-framework
• GraphQL
• graphene (django)
• ap...
Conclusión
Referencias
• Doc de Vue: https://vuejs.org/v2/guide/single-file-components.html
• Doc de Webpack: https://webpack.js.org/...
Gracias!
@javierabadia
Upcoming SlideShare
Loading in …5
×

Vue.js + Django - configuración para desarrollo con webpack y HMR

1,933 views

Published on

Presentación del meetup de Vue.js en Madrid, el 12/Sep/2017 donde explicamos cómo configurar Django y webpack para desarrollar SPAs con Vue.js y backend con Django: incluye configuración de Hot-Module-Reloading, autenticación, API y rutas.

El código de ejemplo se puede encontrar aquí: https://github.com/jabadia/gif_catalog

Published in: Technology
  • Be the first to comment

Vue.js + Django - configuración para desarrollo con webpack y HMR

  1. 1. Vue.js con Django ¿tiene sentido? @javierabadia @VueJSMadrid
  2. 2. ¿Tiene sentido una SPA con backend? • Autenticación • Persistencia • Proceso de Datos • Acceso a almacenes de datos externos • elasticsearch • mongodb • … • Acceso a APIs externas • …
  3. 3. ¿por qué Django frente a Node.js?
  4. 4. La experiencia ‘óptima’ de desarrollo • Trabajar de forma unificada (mismo IDE) • Desarrollo en el backend • debugging • breakpoints, etc • Desarrollo en el frontend • con agilidad • usando Hot Module Replacement (HMR)
  5. 5. La estructura clásica de Django Vistas Templates Modelos ORM Autenticación Middleware Formularios Administración HTML
  6. 6. Ejemplo: Catálogo de GIFs para IoT http://localhost:8000/ http://localhost:8000/detail/323
  7. 7. DEMO
  8. 8. Arquitectura de una SPA de Vue.js $ vue init webpack-simple frontend $ cd frontend $ yarn $ npm run dev localhost:8080
  9. 9. El puente entre Django y Webpack $ cd frontend $ npm install --save-dev webpack-bundle-tracker # (en un virtualenv, por supuesto) $ pip install django-webpack-loader
  10. 10. Todo junto var path = require('path') var webpack = require('webpack') var BundleTracker = require('webpack-bundle-tracker'); module.exports = { … plugins: [ new BundleTracker({filename: './webpack-stats.json'}) ] } // frontend/webpack.conf.js {% extends 'base.html' %} {% load render_bundle from webpack_loader %} {% block content %} <div id="app"></div> {% render_bundle 'main' %} {% endblock %} {# backend/templates/index.html #} { "status": "done", "publicPath": "http://localhost:8080/dist/", "chunks": { "main": [ { "name": "build.js", "publicPath": "http://localhost:8080/dist/build.js", "path": "/Users/jami/…/gif_catalog/frontend/dist/build.js" } ] } } // frontend/webpack-stats.json … WEBPACK_LOADER = { 'DEFAULT': { 'BUNDLE_DIR_NAME': 'dist/', 'STATS_FILE': os.path.join(BASE_DIR, 'frontend/webpack-stats.json'), } } # settings.py
  11. 11. def index(request): return render(request, 'index.html', {}) # backend/views.py {% extends 'base.html' %} {% load render_bundle from webpack_loader %} {% block content %} <div id="app"></div> {% render_bundle 'main' %} {% endblock %} {# backend/templates/index.html #} Django :8000 Webpack :8080 urlpatterns = [ url(r'^', views.index), ] # backend/urls.py App.vue main.js *.vue localhost:8000/ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> … </head> <body> <div id="app"></div> <script type="text/javascript" src="http://localhost:8080/dist/build.js"> </script> </body </html> HMRbuild.js
  12. 12. Webpack: detalles de configuración var path = require('path') var webpack = require('webpack') var BundleTracker = require('webpack-bundle-tracker'); module.exports = { entry: './src/main.js', output: { path: path.resolve(__dirname, './dist'), publicPath: 'http://localhost:8080/dist/', filename: 'build.js' }, module: { ... }, devServer: { historyApiFallback: true, noInfo: true, headers: { 'Access-Control-Allow-Origin': '*' } }, plugins: [ new BundleTracker({filename: './webpack-stats.json'}) ] } url absoluta incluyendo puerto activar CORS para que el cliente HMR pueda hacer peticiones al devServer de webpack // webpack.config.js
  13. 13. Django :8000 localhost:8000/ HTML localhost:8000/api/* JSON
  14. 14. Implementar una API ¿REST? urlpatterns = [ url(r'^api/pics', api.pics), url(r'^', views.index), ] # backend/urls.py def pics(request): count = GifPicture.objects.all().count() all_ids = range(count) random.shuffle(all_ids) picked_ids = all_ids[:18] gif_pictures = GifPicture.objects .filter(id__in=picked_ids) .order_by('-upload_date') result = { 'pics': gif_pictures, } return JsonResponse(result) # backend/api.py import axios from 'axios'; export default { getRandomPics() { return axios.get('/api/pics') .then(response => { return response.data.pics; }); }, } // gifPicsApi.js Django :8000 … <script> import gifPicsApi from '../services/gifPicsApi.js'; export default { … mounted() { gifPicsApi.getRandomPics().then(pics => { this.pics = pics; }); }, }; </script> // GifHome.vue
  15. 15. Autenticación Una posible implementación: 2PA http://localhost:8000/login http://localhost:8000/* create session redirect set cookie vue-routing
  16. 16. Django + auth + sessions <script> export default { name: 'app', data() { return { msg: 'Welcome to Your Vue.js App!', user: {}, } }, created() { this.user = window.user; }, } </script> // App.vue @login_required def index(request): context = { 'user': request.user, } return render(request, 'index.html', context) # backend/views.py {% extends 'base.html' %} {% load render_bundle from webpack_loader %} {% block content %} <div id="app"></div> <script> var user = { username: "{{ user.username }}", email: "{{ user.email }}", }; </script> {% render_bundle 'main' %} {% endblock %} # backend/templates/index.html
  17. 17. DEMO
  18. 18. Rutas urlpatterns = [ url(r'^api/suggestions/$', api.suggestions), url(r'^api/search/$', api.search), url(r'^api/pics/(?P<id>[0-9]+)$', api.pic_details), url(r'^api/pics/$', api.pics), url(r'^', views.index), ] # backend/urls.py Vue.use(Router); const router = new Router({ mode: 'history', routes: [ { path: '/', name: 'home', component: GifHome },{ path: '/detail/:id', name: 'detail', component: GifDetail, props:true },{ path: '*', component: Error404 }, // Not found ], }); # router.js urlpatterns = [ url(r'^admin/', admin.site.urls), url('^', include('django.contrib.auth.urls')), url(r'^', include('backend.urls')) ] # urls.py /login /logout
  19. 19. Comentarios Finales • APIs • REST? • ‘a pelo’ • django-tastypie • django-rest-framework • GraphQL • graphene (django) • apollo (vue) • (no lo he probado) • Server Side Rendering • nope • seeding • sip • SEO • pre-render • inyectar contenido en Django
  20. 20. Conclusión
  21. 21. Referencias • Doc de Vue: https://vuejs.org/v2/guide/single-file-components.html • Doc de Webpack: https://webpack.js.org/ • SurviveJS: https://survivejs.com/webpack/ • webpack-bundle-tracker: https://github.com/ezhome/webpack-bundle-tracker • django-webpack-loader: https://github.com/ezhome/django-webpack-loader • hello-vue + Django project: https://github.com/rokups/hello-vue-django • modernize Django frontend: http://owaislone.org/blog/modern-frontends-with-django/ • Django + REACT with HMR: http://owaislone.org/blog/webpack-plus-reactjs-and-django/
  22. 22. Gracias! @javierabadia

×