diff --git a/docs/settings.rst b/docs/settings.rst
index 85e9f0c3..582cd9d4 100644
--- a/docs/settings.rst
+++ b/docs/settings.rst
@@ -369,6 +369,7 @@ Setting name (default value) What does it do?
value is `static`, but if your theme has
other static paths, you can put them here.
`CSS_FILE` (``'main.css'``) Specify the CSS file you want to load.
+`WEBASSETS` (``False``) Asset management with `webassets` (see below)
================================================ =====================================================
By default, two themes are available. You can specify them using the `-t` option:
@@ -418,7 +419,58 @@ adding the following to your configuration::
CSS_FILE = "wide.css"
-.. _pelican-themes: :doc:`pelican-themes`
+Asset management
+----------------
+
+The `WEBASSETS` setting allows to use the `webassets`_ module to manage assets
+(css, js). The module must first be installed::
+
+ pip install webassets
+
+`webassets` allows to concatenate your assets and to use almost all of the
+hype tools of the moment (see the `documentation`_):
+
+* css minifier (`cssmin`, `yuicompressor`, ...)
+* css compiler (`less`, `sass`, ...)
+* js minifier (`uglifyjs`, `yuicompressor`, `closure`, ...)
+
+Others filters include gzip compression, integration of images in css with
+`datauri` and more. Webassets also append a version identifier to your asset
+url to convince browsers to download new versions of your assets when you use
+far future expires headers.
+
+When using it with Pelican, `webassets` is configured to process assets in the
+``OUTPUT_PATH/theme`` directory. You can use it in your templates with a
+template tag, for example:
+
+.. code-block:: jinja
+
+ {% assets filters="cssmin", output="css/style.min.css", "css/inuit.css", "css/pygment-monokai.css", "css/main.css" %}
+
+ {% endassets %}
+
+will produce a minified css file with the version identifier:
+
+.. code-block:: html
+
+
+
+Another example for javascript:
+
+.. code-block:: jinja
+
+ {% assets filters="uglifyjs,gzip", output="js/packed.js", "js/jquery.js", "js/base.js", "js/widgets.js" %}
+
+ {% endassets %}
+
+will produce a minified and gzipped js file:
+
+.. code-block:: html
+
+
+
+.. _webassets: https://github.com/miracle2k/webassets
+.. _documentation: http://webassets.readthedocs.org/en/latest/builtin_filters.html
Example settings
================
diff --git a/pelican/__init__.py b/pelican/__init__.py
index 6b3d12fb..7e546b29 100644
--- a/pelican/__init__.py
+++ b/pelican/__init__.py
@@ -126,12 +126,17 @@ class Pelican(object):
writer = self.get_writer()
+ # pass the assets environment to the generators
+ if self.settings['WEBASSETS']:
+ generators[1].env.assets_environment = generators[0].assets_env
+ generators[2].env.assets_environment = generators[0].assets_env
+
for p in generators:
if hasattr(p, 'generate_output'):
p.generate_output(writer)
def get_generator_classes(self):
- generators = [ArticlesGenerator, PagesGenerator, StaticGenerator]
+ generators = [StaticGenerator, ArticlesGenerator, PagesGenerator]
if self.settings['PDF_GENERATOR']:
generators.append(PdfGenerator)
if self.settings['LESS_GENERATOR']: # can be True or PATH to lessc
diff --git a/pelican/generators.py b/pelican/generators.py
index ede948a4..f15db15d 100644
--- a/pelican/generators.py
+++ b/pelican/generators.py
@@ -42,7 +42,7 @@ class Generator(object):
simple_loader = FileSystemLoader(os.path.join(theme_path,
"themes", "simple", "templates"))
- self._env = Environment(
+ self.env = Environment(
loader=ChoiceLoader([
FileSystemLoader(self._templates_path),
simple_loader, # implicit inheritance
@@ -51,11 +51,11 @@ class Generator(object):
extensions=self.settings.get('JINJA_EXTENSIONS', []),
)
- logger.debug('template list: {0}'.format(self._env.list_templates()))
+ logger.debug('template list: {0}'.format(self.env.list_templates()))
# get custom Jinja filters from user settings
custom_filters = self.settings.get('JINJA_FILTERS', {})
- self._env.filters.update(custom_filters)
+ self.env.filters.update(custom_filters)
def get_template(self, name):
"""Return the template by name.
@@ -64,7 +64,7 @@ class Generator(object):
"""
if name not in self._templates:
try:
- self._templates[name] = self._env.get_template(name + '.html')
+ self._templates[name] = self.env.get_template(name + '.html')
except TemplateNotFound:
raise Exception('[templates] unable to load %s.html from %s' \
% (name, self._templates_path))
@@ -389,7 +389,23 @@ class StaticGenerator(Generator):
copy(path, source, os.path.join(output_path, destination),
final_path, overwrite=True)
+ def generate_context(self):
+
+ if self.settings['WEBASSETS']:
+ from webassets import Environment as AssetsEnvironment
+
+ # Define the assets environment that will be passed to the
+ # generators. The StaticGenerator must then be run first to have
+ # the assets in the output_path before generating the templates.
+ assets_url = self.settings['SITEURL'] + '/theme/'
+ assets_src = os.path.join(self.output_path, 'theme')
+ self.assets_env = AssetsEnvironment(assets_src, assets_url)
+
+ if logging.getLevelName(logger.getEffectiveLevel()) == "DEBUG":
+ self.assets_env.debug = True
+
def generate_output(self, writer):
+
self._copy_paths(self.settings['STATIC_PATHS'], self.path,
'static', self.output_path)
self._copy_paths(self.settings['THEME_STATIC_PATHS'], self.theme,
diff --git a/pelican/settings.py b/pelican/settings.py
index 4da66989..647d3e93 100644
--- a/pelican/settings.py
+++ b/pelican/settings.py
@@ -68,6 +68,7 @@ _DEFAULT_CONFIG = {'PATH': '.',
'ARTICLE_PERMALINK_STRUCTURE': '',
'TYPOGRIFY': False,
'LESS_GENERATOR': False,
+ 'WEBASSETS': False,
}
@@ -150,4 +151,12 @@ def configure_settings(settings, default_settings=None, filename=None):
"http://docs.notmyidea.org/alexis/pelican/settings.html#timezone "
"for more information")
+ if settings['WEBASSETS']:
+ try:
+ from webassets.ext.jinja2 import AssetsExtension
+ settings['JINJA_EXTENSIONS'].append(AssetsExtension)
+ except ImportError:
+ logger.warn("You must install the webassets module to use WEBASSETS.")
+ settings['WEBASSETS'] = False
+
return settings