PyCon Spain. Almería 2016
Tomás Garzón
¿Qué son statics en Django?
- css / js / img ... --> se sirven directamente por NGINX
¿Por qué necesito gestionarlos?
Bootstrap
Tema
Estilos
Propios
Librerías Propias
Librerías JS
Templates
{
"name": "example",
"version": "0.0.1",
"description": "Example Description",
"dependencies": {
"jquery": "~2.1.4",
"bootstrap": "~3.3.6",
"moment": "~2.10.6",
}
}
Necesitamos un script que haga la magia
base.tpl
bower.json
Less/sass
Javascript
Templates underscore
Gulp
Librerías JS
Librerías CSS
Código JS proyecto
Código CSS proyecto
Código JS de templates
base.html
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{% block title %}{% endblock %}</title>
<!-- build:css(src) styles/vendor-base.css -->
<!-- bower:css -->
<!-- run `gulp inject` to automatically populate bower styles dependencies -->
<!-- endbower -->
<!-- endbuild -->
<!-- build:css({.tmp/serve,src}) styles/app-base.css -->
<!-- inject:css -->
<!-- css files will be automatically insert here -->
<!-- endinject -->
<!-- endbuild -->
{% block styles %}{% endblock %}
</head>
<body class="md-skin fixed-sidebar fixed-nav" id="page-top">
{% block content %}{% endblock %}
<!-- build:js(src) scripts/vendor-base.js -->
<!-- bower:js -->
<!-- run `gulp inject` to automatically populate bower script dependencies -->
<!-- endbower -->
<!-- endbuild -->
<!-- build:js(.tmp/serve) scripts/app-templates.js -->
<script type="text/javascript" src="templates/templates.js"></script>
<!-- endbuild -->
<!-- build:js(src) scripts/app-base.js -->
<!-- inject:js -->
<!-- js files will be automatically insert here -->
<!-- endinject -->
<!-- endbuild -->
{% block js %}{% endblock %}
</body>
</html>
Ficheros css de librerías
Ficheros css propios+tema
Ficheros js templates underscore
Ficheros js de librerías
Ficheros js propios
var gulp = require('gulp'),
jshint = require('gulp-jshint'),
uglify = require('gulp-uglify'),
concat = require('gulp-concat');
gulp.task('scripts', function () {
return gulp.src('js/*.js')
.pipe(jshint())
.pipe(uglify())
.pipe(concat('app.js'))
.pipe(gulp.dest('build')); });
¿Cómo funciona gulp?
- Necesitamos tener node instalado.
- Definimos en package.json las dependencias
- npm install
gulp scripts
gulpfile.js
Principales paquetes de Gulp:
- gulp-inject: inyecta las dependencias en el template
- gulp-wiredep: mapea las dependencias del bower.json
- gulp-less: compilar nuestros ficheros less a css
- gulp-html2tpl: compilar HTML de underscore a un fichero js
- gulp-minify-css: minimizar ficheros css
- gulp-uglify: comprimir ficheros js
- gulp-useref: concatena ficheros en uno
- gulp-rev: añade un hash para el cacheo de ficheros
Empezando por los estilos....
// bower:less
// endbower
@import "less/style";
// injector
// endinjector
index.less
gulp.task('styles', function() {
return gulp.src([
path.join(conf.paths.src, '/app/index.less')
])
.pipe($.inject(injectFiles, injectOptions))
.pipe(wiredep(_.extend({}, conf.wiredep)))
.pipe($.sourcemaps.init())
.pipe($.less(lessOptions)).on('error', conf.errorHandler('Less'))
.pipe($.sourcemaps.write())
.pipe(gulp.dest(path.join(conf.paths.tmp, '/serve/app/')));
};
Los htmls de underscore....
gulp.task('templates', function () {
return gulp.src(path.join(conf.paths.src, '/templates/**/*.html'))
.pipe($.html2tpl('templates.js'))
.pipe(gulp.dest(path.join(conf.paths.tmp, '/serve/templates/')));
});
Ejecutamos el inject en el base.tpl
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{% block title %}{% endblock %}</title>
<!-- build:css(src) styles/vendor-base.css -->
<!-- bower:css -->
<!-- run `gulp inject` to automatically populate bower styles dependencies -->
<!-- endbower -->
<!-- endbuild -->
<!-- build:css({.tmp/serve,src}) styles/app-base.css -->
<!-- inject:css -->
<!-- css files will be automatically insert here -->
<!-- endinject -->
<!-- endbuild -->
{% block styles %}{% endblock %}
</head>
<body class="md-skin fixed-sidebar fixed-nav" id="page-top">
{% block content %}{% endblock %}
<!-- build:js(src) scripts/vendor-base.js -->
<!-- bower:js -->
<!-- run `gulp inject` to automatically populate bower script dependencies -->
<!-- endbower -->
<!-- endbuild -->
<!-- build:js(.tmp/serve) scripts/app-templates.js -->
<script type="text/javascript" src="templates/templates.js"></script>
<!-- endbuild -->
<!-- build:js(src) scripts/app-base.js -->
<!-- inject:js -->
<!-- js files will be automatically insert here -->
<!-- endinject -->
<!-- endbuild -->
{% block js %}{% endblock %}
</body>
</html>
gulp.task('inject', ['styles', 'templates'], function () {
return gulp.src(conf.paths.base)
.pipe($.inject(injectStyles, injectOptions))
.pipe($.inject(injectScripts, injectOptions))
.pipe(wiredep(conf.wiredep))
.pipe(gulp.dest(path.join(conf.paths.tmp, '/serve')));
});
base.tpl "expandido"
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- Page title set in pageTitle directive -->
<title>{% block title %}{% endblock %}</title>
<!-- build:css(src) styles/vendor-base.css -->
<!-- bower:css -->
<link rel="stylesheet" href="../../frontend/bower_components/toastr/toastr.css" />
<link rel="stylesheet" href="../../frontend/bower_components/select2/dist/css/select2.min.css" />
<!-- endbower -->
<!-- endbuild -->
<!-- build:css({.tmp/serve,src}) styles/app-base.css -->
<!-- inject:css -->
<link rel="stylesheet" href="app/index.css">
<link rel="stylesheet" href="app/css/animate.css">
<!-- endinject -->
<!-- endbuild -->
{% block styles %}{% endblock %}
</head>
<body class="md-skin fixed-sidebar fixed-nav" >
{% block content %}{% endblock %}
<!-- build:js(src) scripts/vendor-base.js -->
<!-- bower:js -->
<script src="../../frontend/bower_components/jquery/dist/jquery.js"></script>
<script src="../../frontend/bower_components/bootstrap/dist/js/bootstrap.js"></script>
<script src="../../frontend/bower_components/moment/moment.js"></script>
<!-- endbower -->
<!-- endbuild -->
<!-- build:js(.tmp/serve) scripts/app-templates.js -->
<script type="text/javascript" src="templates/templates.js"></script>
<!-- endbuild -->
<!-- build:js(src) scripts/app-base.js -->
<!-- inject:js -->
<script src="modules/lib.js"></script>
<script src="modules/app.js"></script>
<!-- endinject -->
<!-- endbuild -->
{% block js %}{% endblock %}
</body>
</html>
Pasos finales
gulp.task('html-dev', ['inject'], function () {
return gulp.src(path.join(conf.paths.tmp, '/serve/base.tpl'))
.pipe($.rename('base.html'))
.pipe(assets = $.useref.assets())
.pipe(assets.restore())
.pipe($.useref())
.pipe($.revReplace())
.pipe(gulp.dest(path.join(conf.paths.dist, '/')))
.pipe($.size({ title: path.join(conf.paths.dist, '/'), showFiles: true }));
});
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- Page title set in pageTitle directive -->
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="{% static "styles/vendor-base.css" %}">
<link rel="stylesheet" href="{% static "styles/app-base.css" %}">
{% block styles %}{% endblock %}
</head>
<body class="md-skin fixed-sidebar fixed-nav">
{% block content %}{% endblock %}
<script src="{% static "scripts/vendor-base.js" %}"></script>
<script src="{% static "scripts/app-templates.js" %}"></script>
<script src="{% static "scripts/app-base.js" %}"></script>
{% block js %}{% endblock %}
</body>
</html>
Ventajas durante el desarrollo
Desplegando nuestro proyecto
gulp.task('html', ['inject'], function () {
var htmlFilter = $.filter('*.html', { restore: true });
var jsFilter = $.filter('**/*.js', { restore: true });
var cssFilter = $.filter('**/*.css', { restore: true });
var assets;
return gulp.src(path.join(conf.paths.tmp, '/serve/base.tpl'))
.pipe($.rename('base.html'))
.pipe($.rev())
.pipe(jsFilter)
.pipe($.sourcemaps.init())
.pipe($.uglify({ preserveComments: $.uglifySaveLicense })).on('error', conf.errorHandler('Uglify'))
.pipe($.sourcemaps.write('maps'))
.pipe(jsFilter.restore)
.pipe(cssFilter)
.pipe($.sourcemaps.init())
.pipe($.minifyCss({ processImport: false }))
.pipe($.sourcemaps.write('maps'))
.pipe(cssFilter.restore)
.pipe($.useref())
.pipe($.revReplace())
.pipe(htmlFilter)
.pipe($.minifyHtml({
empty: true,
spare: true,
quotes: true,
conditionals: true
}))
.pipe(htmlFilter.restore)
.pipe(gulp.dest(path.join(conf.paths.dist, '/')))
.pipe($.size({ title: path.join(conf.paths.dist, '/'), showFiles: true }));
});
base.html
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="{% static "styles/vendor-base-180e53936d.css" %}">
<link rel="stylesheet" href="{% static "styles/app-base-8807c93d9c.css" %}">
{% block styles %}{% endblock %}
</head>
<body class="md-skin fixed-sidebar fixed-nav">
{% block content %}{% endblock %}
<script src="{% static "scripts/vendor-base-9afbaab148.js" %}"></script>
<script src="{% static "scripts/app-templates-365152f0f1.js" %}"></script>
<script src="{% static "scripts/app-base-95bdff3860.js" %}"></script>
{% block js %}{% endblock %}
</body>
</html>
Tomás Garzón Hervás
PyCon ES 2016 Almería
https://github.com/ExOLever/django-gulp
tomasgarzonhervas@gmail.com