Last active
September 28, 2015 16:55
-
-
Save sveetch/de98764e52ee769c9052 to your computer and use it in GitHub Desktop.
Asset management attempt with Gruntjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"stylesheets": { | |
"css/recalbox.min.css": [ | |
"css/app.css" | |
] | |
}, | |
"javascripts": { | |
"js/modernizr.min.js": [ | |
"js/foundation5/vendor/modernizr.js" | |
], | |
"js/app.min.js": [ | |
"js/foundation5/vendor/jquery.js", | |
"js/foundation5/vendor/jquery.cookie.js", | |
"js/foundation5/foundation/foundation.js", | |
"js/foundation5/foundation/foundation.abide.js", | |
"js/foundation5/foundation/foundation.accordion.js", | |
"js/foundation5/foundation/foundation.alert.js", | |
"js/foundation5/foundation/foundation.clearing.js", | |
"js/foundation5/foundation/foundation.dropdown.js", | |
"js/foundation5/foundation/foundation.equalizer.js", | |
"js/foundation5/foundation/foundation.interchange.js", | |
"js/foundation5/foundation/foundation.joyride.js", | |
"js/foundation5/foundation/foundation.magellan.js", | |
"js/foundation5/foundation/foundation.offcanvas.js", | |
"js/foundation5/foundation/foundation.reveal.js", | |
"js/foundation5/foundation/foundation.slider.js", | |
"js/foundation5/foundation/foundation.tab.js", | |
"js/foundation5/foundation/foundation.tooltip.js", | |
"js/foundation5/foundation/foundation.topbar.js", | |
"js/foundation5/foundation/foundation.orbit.js", | |
"js/app.js" | |
] | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Assets tags | |
The assets map is a JSON file like this : :: | |
{ | |
"stylesheets": { | |
"css/recalbox.min.css": [ | |
"css/app.css" | |
] | |
}, | |
"javascripts": { | |
"js/modernizr.min.js": [ | |
"js/foundation5/vendor/modernizr.js" | |
], | |
} | |
} | |
This should be usable with grunt/gulp but without "glob" pattern. | |
Asset package key name must be the filepath to the package file and | |
contain a list of asset file to package. | |
Note also that each path is relative to static directories, for | |
gulp/grunt you would have to prepend them with the path to the project static dir (not | |
the app static dirs, as they would not be reachable from Grung/Gulp) | |
This is only common static files usage, not for usage with static files through S3/etc.. | |
""" | |
import json, os | |
from django.conf import settings | |
from django.template import Context | |
from django.template.loader import get_template | |
from django.template.defaulttags import register | |
from django.contrib.staticfiles import finders | |
class AssetMapError(Exception): | |
pass | |
class StaticfileAssetNotFound(Exception): | |
pass | |
def render_asset_tags(kind, *bundle_names): | |
""" | |
Helper to render asset tags using AssetTagsManager | |
@kind: either 'stylesheets' or 'javascripts' (or whatever root element keys existing in the asset map) | |
@bundle_names: list of bundles to get for the given kind name | |
""" | |
# Open the template fragment | |
tag_template = get_template(settings.ASSETS_TAG_TEMPLATES.get(kind)) | |
# Open and parse the JSON file for the map | |
with open(settings.ASSETS_MAP_FILEPATH, 'rb') as json_file: | |
assets_map = json.load(json_file) | |
#print "* Kind:", kind | |
manager = AssetTagsManager(assets_map[kind]) | |
return manager.render(bundle_names, tag_template) | |
@register.simple_tag | |
def stylesheet_tag(*bundle_names): | |
""" | |
Build tag for stylesheet assets | |
Usage | |
***** | |
Just gives package names (one or more) as arguments: :: | |
{% stylesheet_tag "css/item1.min.css" "css/item2.min.css" .. %} | |
Depending on settings.ASSETS_PACKAGED it would build (if True) an unique tag for the packaged asset file or (if False) tag for each package components files. | |
""" | |
return render_asset_tags('stylesheets', *bundle_names) | |
@register.simple_tag | |
def javascript_tag(*bundle_names): | |
""" | |
Build tag for javascript assets | |
Usage | |
***** | |
Just gives package names (one or more) as arguments: :: | |
{% javascript_tag "css/item1.min.js" "css/item2.min.js" .. %} | |
Depending on settings.ASSETS_PACKAGED it would build (if True) an unique tag for the packaged asset file or (if False) tag for each package components files. | |
""" | |
return render_asset_tags('javascripts', *bundle_names) | |
class AssetTagsManager(object): | |
""" | |
Manage assets using given asset map | |
This does not intend to compress/minify/uglify asset, just rendering their tags to | |
load them from your template | |
@assets_map: file maps for an asset kind (not the full asset map) | |
@packaged: switch to know if we use the packed files or the original ones | |
""" | |
def __init__(self, assets_map, packaged=True): | |
self.assets_map = assets_map # file maps for an asset kind (not the full asset map) | |
self.packaged = packaged # switch to know if we use the packed files or the original ones | |
def render_fragment(self, template, context=None): | |
""" | |
Render fragment using given django template | |
""" | |
return template.render(context) | |
def static_url(self, filepath): | |
""" | |
Have to raise a custom exception instead of output print | |
Check if given relative file path exists in any static directory but | |
only is ASSETS_STRICT is enabled. | |
Finally if there is not exception, return the static file url | |
""" | |
if settings.ASSETS_STRICT: | |
if not finders.find(filepath): | |
raise StaticfileAssetNotFound("Asset file cannot be finded in any static directory: {}".format(filepath)) | |
return os.path.join(settings.STATIC_URL, filepath) | |
def get_files(self, name): | |
""" | |
Find and return asset file url given package name | |
""" | |
try: | |
file_paths = self.assets_map[name] | |
except KeyError: | |
if settings.ASSETS_STRICT: | |
raise AssetMapError("Asset key '{}' does not exists in your asset map".format(name)) | |
else: | |
if settings.ASSETS_PACKAGED: | |
return [self.static_url(name)] | |
else: | |
return [self.static_url(item) for item in file_paths] | |
return [] | |
def render(self, names, template): | |
""" | |
Return rendered given template for each asset files of each package names | |
""" | |
tags = [] | |
for name in names: | |
asset_files = self.get_files(name) | |
for item in filter(None, asset_files): | |
tags.append( self.render_fragment(template, context=Context({"ASSET_URL": item})) ) | |
return '\n'.join(tags) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Grunt config | |
*/ | |
module.exports = function(grunt) { | |
var project_dir = 'project/', | |
static_dir = project_dir+'webapp_statics/', | |
asset_manifest = grunt.file.readJSON(project_dir+'assets.json'), | |
prepend_staticdir = function(file_map) { | |
for(var keyname in file_map){ | |
var distkey = static_dir+keyname; | |
// console.log(keyname+": "+file_map[keyname]); | |
console.log(keyname+"-> "+distkey); | |
} | |
return file_map; | |
}; | |
grunt.initConfig({ | |
pkg: grunt.file.readJSON('package.json'), | |
// watch: { | |
// cssmin: { | |
// files: ['project/webapp_statics/css/**/*.css'], | |
// tasks: ['cssmin'], | |
// options: { | |
// spawn: false, // for grunt-contrib-watch v0.5.0+, "nospawn: true" for lower versions. Without this option specified express won't be reloaded | |
// livereload: true | |
// } | |
// } | |
// }, | |
cssmin: { | |
target: { | |
options: { | |
banner: '/* Recalbox minified CSS. Minified on <%= grunt.template.today("yyyy-mm-dd hh:MM:ss")%> by GruntJS-cssmin */' | |
}, | |
files: prepend_staticdir(asset_manifest.stylesheets) | |
// files: [{ | |
// 'project/webapp_statics/css/recalbox.min.css': ['project/webapp_statics/css/*.css'] | |
// }] | |
} | |
}, | |
uglify: { | |
options: { | |
mangle: false // prevent changes to variable name. Maybe set to 'true' after testing ? | |
}, | |
target: { | |
files: prepend_staticdir(asset_manifest.javascripts) | |
// files: { | |
// 'project/webapp_statics/js/modernizr.min.js': [ | |
// 'foundation5/bower_components/modernizr/modernizr.js' | |
// ], | |
// 'project/webapp_statics/js/app.min.js': [ | |
// 'foundation5/bower_components/jquery/dist/jquery.js', | |
// 'foundation5/bower_components/jquery.cookie/jquery.cookie.js', | |
// "foundation5/bower_components/foundation/js/foundation/foundation.js", | |
// "foundation5/bower_components/foundation/js/foundation/foundation.abide.js", | |
// "foundation5/bower_components/foundation/js/foundation/foundation.accordion.js", | |
// "foundation5/bower_components/foundation/js/foundation/foundation.alert.js", | |
// "foundation5/bower_components/foundation/js/foundation/foundation.clearing.js", | |
// "foundation5/bower_components/foundation/js/foundation/foundation.dropdown.js", | |
// "foundation5/bower_components/foundation/js/foundation/foundation.equalizer.js", | |
// "foundation5/bower_components/foundation/js/foundation/foundation.interchange.js", | |
// "foundation5/bower_components/foundation/js/foundation/foundation.joyride.js", | |
// "foundation5/bower_components/foundation/js/foundation/foundation.magellan.js", | |
// "foundation5/bower_components/foundation/js/foundation/foundation.offcanvas.js", | |
// "foundation5/bower_components/foundation/js/foundation/foundation.reveal.js", | |
// "foundation5/bower_components/foundation/js/foundation/foundation.slider.js", | |
// "foundation5/bower_components/foundation/js/foundation/foundation.tab.js", | |
// "foundation5/bower_components/foundation/js/foundation/foundation.tooltip.js", | |
// "foundation5/bower_components/foundation/js/foundation/foundation.topbar.js", | |
// //"foundation5/bower_components/foundation/js/foundation/foundation.orbit.js", //Orbit Slider is deprecated | |
// 'project/webapp_statics/js/*.js' | |
// ] | |
// } | |
} | |
}, | |
jshint: { | |
all: ['Gruntfile.js', 'project/webapp_statics/**/*.js'] | |
} | |
}); | |
// Load plugins | |
grunt.loadNpmTasks('grunt-contrib-watch'); | |
grunt.loadNpmTasks('grunt-contrib-cssmin'); | |
grunt.loadNpmTasks('grunt-contrib-uglify'); | |
grunt.loadNpmTasks('grunt-contrib-jshint'); | |
// Create custom tasks | |
grunt.registerTask('server', [ 'watch' ]); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# For assets management | |
ASSETS_PACKAGED = not(DEBUG) | |
ASSETS_STRICT = False | |
ASSETS_MAP_FILEPATH = os.path.join(PROJECT_DIR, "assets.json") | |
ASSETS_TAG_TEMPLATES = { | |
"javascripts": "assets/javascript_tag.html", | |
"stylesheets": "assets/stylesheet_tag.html", | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment