Font End Development + Automation with Django
-
Upload
evan-reiser -
Category
Technology
-
view
5.387 -
download
2
description
Transcript of Font End Development + Automation with Django
Tips & Tricks for Front End Development Automation
Evan Reiser
Front End Automation? Tools / Tricks to speed up front end dev work
Why talk about this? Same reason we all like Django:▪ More time solving our biz/eng problems▪ Less time doing the same repeatable patterns
We want to: Build web apps + add features Not: waste time deploying media,
organizing assets, minifying js/css, making sprites etc.
django experience
Co-founder @ GamerNook Social Network for Gamers▪ 100k+ Members
Co-founder @ BloomSpot Luxury Daily Deals▪ 3rd Largest Daily Deals site
Co-founder @ AdStack Algorithmically Managed
Facebook Advertising
Overview
Pains with Front end Development Deploying Media Files Compressing / Combine media files Generating Sprites Automate all of this
Problems / Pains
Annoying parts of front end development Deploying media to media server / CDN Combining JS / CSS files Minimizing JS / CSS Cache-busting media files in prod Building sprite images Referencing sprites in CSS Having to do this all manually
These are all common patterns We shouldn’t have to waste time on them
Tools
django.contrib.staticfiles django_storages boto
django_compressor YUI JS/CSS Compressor
django_media_bundler PIL pngcrush
django.contrib.staticfiles
Pulls media from various places Places them in another place
Different folder Media Server Or any custom storage backend▪ S3 / CloudFront▪CDN
Media Files => CDN
1. #settings.py
2. STATICFILES_DIRS = (3. os.path.join(os.getcwd(),"media"),4. )5. STATICFILES_FINDERS = (6. 'django.contrib.staticfiles.finders.FileSystemFinder',7. 'django.contrib.staticfiles.finders.AppDirectoriesFinder',8. )9. STATIC_ROOT = os.path.join(os.getcwd(),"static")
1) Set up static files to find
Media Files => CDN
1. #settings.py
2. STATICFILES_STORAGE = 'storages.backends.s3boto.S3BotoStorage '
2) Set Storage backend to be S3 / CloudFront
• boto• Is a python library for interacting with
Amazon Web Services• django_storages• A series of storage backends including a
S3
Media Files => CDN
python manage.py collectstatic
2) Push media files to CDN
Media Files => CDN
1. #settings.py2. TEMPLATE_CONTEXT_PROCESSORS += (3. 'django.core.context_processors.static',4. )
4) Reference media in your templates
1. {# Some Template #}2. <link rel="stylesheet" href="{{STATIC_URL}}style.css" />
1. <link rel="stylesheet" href=“http://cdn.adstack.com/style.css" />
Managing Media
Managing Media CSS / JavaScript assets
We want to: Reduce Http requests Reduce bandwidth
We don’t want to: Think about front-end performance while
coding Interrupt our development
Managing Media
1. We want to reduce the number of HTTP requests for serving JS + CSS
<link rel="stylesheet" href="{{STATIC_URL}}css/admin/base.css" /><link rel="stylesheet" href="{{STATIC_URL}}css/admin/changelists.css" /><link rel="stylesheet" href="{{STATIC_URL}}css/icon_sprites.css"/><link rel="stylesheet" href="{{STATIC_URL}}css/common_10.css" /><link rel="stylesheet" href="{{STATIC_URL}}css/tablesorter.css" /><link rel="stylesheet" href="{{STATIC_URL}}css/multiselect.css" /><link rel="stylesheet" href="{{STATIC_URL}}css/superfish.css" />
<link rel="stylesheet" href="{{STATIC_URL}}css/all.css" />
Managing Media
2. We want to minify css / js content and only include what’s needed (reduce bandwidth)/*
Make sure to rename this file before you deploy to break client caching!!!*/
/* Headers */H1 {
font-weight:bold;}H2 {
font-weight;bold;}
H1,H2 {font-weight:bold}
Obviously the same thing goes for JS
Managing Media
3. Don’t want to have to change the asset names to prevent client side caching
Style.css Style2.css Style3.css Style4.css Style5.css
Managing Media
One way to do this is django_compressor Converts & combines linked or inline css/js
into cacheable static files Compression / minification support for: CSS
Tidy, YUI CSS + JS, Google’s Closure Compiler, JSmin, cssmin
Builds unique static file names to bust cache No need to heavily modify existing
templates Plus:▪ Extendable for custom post processing / filtering
via python
Managing Media Template changes are minimal
{% compress css %}<link href="{{STATIC_URL}}css/admin/base.css" /><link href="{{STATIC_URL}}css/admin/changelists.css" /><link href="{{STATIC_URL}}css/icon_sprites.css"/><link href="{{STATIC_URL}}css/common_10.css" /><link href="{{STATIC_URL}}css/tablesorter.css" /><link href="{{STATIC_URL}}css/multiselect.css" /><link href="{{STATIC_URL}}css/superfish.css" />{% endcompress %}
{% compress js %}<script src="{{STATIC_URL}}js/jquery-1.5.1.min.js"></script><script src="{{ STATIC_URL }}js/jquery.hoverIntent.js"></script><script src="{{STATIC_URL}}js/common.js"></script><script src="{{STATIC_URL}}js/jquery.multiselect.min.js"></script><script src="{{STATIC_URL}}js/jquery.cluetip.min.js"></script><script src="{{STATIC_URL}}js/jquery.tablesorter.js"></script><script src="{{ STATIC_URL }}js/jquery.tooltip.pack.js"></script><script src="{{ STATIC_URL }}js/superfish.js"></script>{% endcompress %}
Compressor Settings
1. from django.core.files.storage import get_storage_class2. from storages.backends.s3boto import S3BotoStorage3. 4. #A special Storage class that saves to S3 and Locally5. class CachedS3BotoStorage(S3BotoStorage):6. 7. def __init__(self, *args, **kwargs):8. super(CachedS3BotoStorage, self).__init__(*args, **kwargs)9. self.local_storage = get_storage_class(10. "compressor.storage.CompressorFileStorage")()11. 12. def save(self, name, content):13. name = super(CachedS3BotoStorage, self).save(name,content)14. self.local_storage._save(name, content)15. return name
We use a custom Storage Class to store the results on S3
Compressor Settings
1. import os2. STATICFILES_FINDERS += (3. 'compressor.finders.CompressorFinder',4. )
5. COMPRESS_OFFLINE = True6. COMPRESS_STORAGE = "common.common_storages.CachedS3BotoStorage"
7. COMPRESS_ROOT = os.path.join(os.path.dirname(__file__), 'media')8. COMPRESS_OUTPUT_DIR = "compress_cache"
9. COMPRESS_OFFLINE_CONTEXT = {"STATIC_URL":STATIC_URL}10.COMPRESS_URL = STATIC_URL11. 12.#post processing filters13.COMPRESS_CSS_FILTERS = ['compressor.filters.yui.YUICSSFilter‘]14.COMPRESS_JS_FILTERS = ['compressor.filters.jsmin.JSMinFilter']15.COMPRESS_YUI_BINARY = 'java -jar %s yuicompressor-2.4.6.jar'
Compressor settings for offline / pre-greneration
Managing Media
python manage.py compress
• combines static content• applies post processing filters• creates unique name from hash of
content• pushes to S3/CDN
Managing Media
{% compress css %}<link href="{{STATIC_URL}}css/admin/base.css" /><link href="{{STATIC_URL}}css/admin/changelists.css" /><link href="{{STATIC_URL}}css/icon_sprites.css"/><link href="{{STATIC_URL}}css/common_10.css" /><link href="{{STATIC_URL}}css/tablesorter.css" /><link href="{{STATIC_URL}}css/multiselect.css" /><link href="{{STATIC_URL}}css/superfish.css" />{% endcompress %}
<link rel="stylesheet" href="http://cdn.adstack.com/compress_cache/css/32dd63bd423c.css" />
When template renders Content is hashed => hash value stored
in cache Individual reference in template replaced
Automatic Sprites
What are sprites? Sprites are composite images made up of other images
Why? Reduce # HTTP requests
How? CSS is used to only show part of
the composite image
Automatic Sprites
How do we use sprites? Set them as a css background on a fixed
size element Position them so only part of the larger image shows
Cool. But this is really a pain▪ Creating images▪ Custom css for positioning
Automatic Sprites
• django_media_bundler • can help build the sprite automatically• Generates positioning CSS• Uses python + PIL to generate the sprite• Uses pngcrush to optimize the final
image size
• Use Case:• We have a folder full of icons• user.png, email.png, add.png
• We want to easily put these in templates• {% icon "email" %}
Automatic Sprites
• Simple example: lots of icons
*doing this can be a pain
Automatic Sprites
1. MEDIA_BUNDLES = (2. {"type": "png-sprite",3. "name": "icon",4. "path": os.path.join(MEDIA_ROOT,"icons"),5. "url": "../icons/",6. "css_file": os.path.join(MEDIA_ROOT,"css","icon_sprites.css"),7. "files": [8. “add.png”,9. “delete.png”,10. “user.png”,11. “delete.png”,12. “group.png”,13. ]14. },15.)
1) Configure Media bundler settings
Automatic Sprites
1. MEDIA_BUNDLES = (2. {"type": "png-sprite",3. "name": "icon",4. "path": os.path.join(MEDIA_ROOT,"icons"),5. "url": "../icons/",6. "css_file": os.path.join(MEDIA_ROOT,"css","icon_sprites.css"),7. "files": filter(lambda x: x[-4:]== '.png', 8. os.listdir(os.path.join(MEDIA_ROOT,"icons")))9. },10.)
1) Configure Media bundler settings
Automatic Sprites
python manage.py bundle_media
2) Bundle our media
3) This creates a sprite.png + sprite.css
.icon {background-image: url('http://cdn.adstack.com/icons/sprites/icon110701154833.png?675d7dfaa1e1');}
.icon_user {width: 16px;background-position: 0px 0px;height: 16px;}.icon_add {width: 16px;background-position: -16px 0px;height: 16px;}
Etc…
<style>.icon {width: 16px;height: 16px;margin: 0;padding: 0;display: inline-block;position: relative;top: 2px;}</style>
<div><span class=“icon icon_user”></span> Hello Evan</div>
Automatic Sprites4) We can then show icons using css
Hello Evan
#front_end_tags.pyfrom django import templateregister = template.Library()
@register.inclusion_tag("common/front_end/icon.html")def icon(icon_name): return locals()
{# common/front_end/icon.html #}<span class="icon icon_{{ icon_name }}"></span>
<div> {% icon "user" %} Hello Evan</div>
5) We can easily write template tags to make this easier
6) Now it’s a bit easier to develop
Automatic Sprites
Automation
Fabric Deploy Script
from fabric.api import *def cdn_deploy():
run('python manage.py bundle_media')run('python manage.py collectstatic --noinput')run('python manage.py compress')
fab cdn_deploy
References django.contrib.staticfiles
https://docs.djangoproject.com/en/dev/howto/static-files/ Boto
http://code.google.com/p/boto/ Fabric
http://docs.fabfile.org/en/1.1.1/index.html django_compressor
http://code.google.com/p/django-compressor/ Boto
http://code.google.com/p/boto/ django_storages
https://bitbucket.org/david/django-storages/wiki/Home django_media_bundler
https://github.com/fabiocorneti/django-media-bundler Pngcrush
http://pmt.sourceforge.net/pngcrush/ YUI compressor
http://developer.yahoo.com/yui/compressor/
Questions?
Evan [email protected]