A static file compiler for Django
APACHE-2.0 License
This project is no longer maintained
A static files compiler (JavaScript, CSS, et all) which aims to solve two things:
Many projects solve the second item, but they're unfortunately not compatible (and/or very hard to make so) with sourcemap generation.
Static files are stored relative to their configuration root:
::
[site-packages]/sentry/static/sentry/js/foo.js
[site-packages]/sentry/static/sentry/js/bar.js
[site-packages]/otherapp/static/otherapp/css/bar.css
Each application would be compiled independently, based on its own configuration, and you'd end up with something like the following:
::
[site-packages]/sentry/static/sentry/dist/js/all.min.js
[site-packages]/otherapp/static/otherapp/dist/css/bar.min.css
Eventually these would be collected (using standard staticfiles) in your project static directory.
You'll need to add the library to both your INSTALLED_APPS
and STATICFILES_FINDERS
:
::
STATICFILES_FINDERS = ( "django.contrib.staticfiles.finders.FileSystemFinder", "django.contrib.staticfiles.finders.AppDirectoriesFinder", "static_compiler.finders.StaticCompilerFinder", )
INSTALLED_APPS = ( # ... "static_compiler", )
Configuration is handled via the STATIC_BUNDLES
setting, in settings.py
.
An example configuration might look like this:
::
STATIC_BUNDLES = {
"cache": "CACHE",
"packages": {
"sentry/scripts/global.min.js": {
"src": [
"sentry/scripts/core.js",
"sentry/scripts/models.js",
"sentry/scripts/templates.js",
"sentry/scripts/utils.js",
"sentry/scripts/collections.js",
"sentry/scripts/charts.js",
"sentry/scripts/views.js",
"sentry/scripts/app.js",
],
},
"sentry/styles/global.min.css": {
"src": {
"sentry/less/sentry.less": "sentry/styles/sentry.css",
},
},
},
"postcompilers": {
"*.js": ["node_modules/uglify-js/bin/uglifyjs {input} --source-map-root={relroot}/ --source-map-url={name}.map{ext} --source-map={relpath}/{name}.map{ext} -o {output}"],
},
"preprocessors": {
"*.less": ["node_modules/less/bin/lessc {input} {output}"],
},
}
There are the following top level attributes:
cache
The directory name to store the compiler's cached files in. This is relative to STATIC_ROOT
, and is only used
for compiling files.
packages
A mapping of bunches to their options (options can include top level options as well)
precompilers
A mapping of input grep patterns to a list of (ordered) commands to execute on files
in all situations (including DEBUG use).
postcompilers
A mapping of input grep patterns to a list of (ordered) commands to execute on files
which are designated for distribution (e.g. not DEBUG use).
The packages attribute accepts the following:
src A list or mapping of source files to include in this bunch. If the value is a mapping the key is the input file, and the value is the output file.
We'd make several variables available to post- and precompilers:
input absolute path to input file output absolute path to output file -- if not present will fetch from stdout ext output extension (e.g. .js) name extensionless filename from output (e.g. bundle) filename full output filename (e.g. bundle.js) path full output dir path (e.g. foo/bar) relroot the relative path to the STATIC_ROOT. e.g. ../../.. root the value of STATIC_ROOT
The process currently looks like this:
Pre-Processors
A pre-processor will **always** be run. This is nearly always a requirement as things like LESS files have to be processed
befor they can be served in a browser.
When pre-processing happens each input file is transformed to an output file (using the standard versioning scheme). For
example, if I had a bunch that included foo.less and bar.less, each would be compiled separately, and I'd end up with
two output files: foo.css, and bar.css.
The first pre-processor will change the input filename to be the expected output filename, and the following processors
will be passed that to work with.
Post-Compilers
A post-compiler runs on pre-processed inputs and is expected to concatenate the results together into a unified file.
For example, if it runs against foo.js and bar.js, it will output bundle.js.
Each post-compiler must be able to accept 1+ inputs, and he first post-compilers will be responsible for combining files and the resulting file will be passed to the additional compilers.
If no post-compilers happen, the result would be similar to the following: cat [input, input, input] > output
Specify the relative path to the bunch name (relative to the static root):
::
{% load static_compiler %}
{% staticbundle 'bundle.js' %}
You can also specify attributes, such as mimetype:
::
{% staticbundle 'bundle.foo' mimetype='text/css' media='screen' %}
If we're in DEBUG / development mode and 'bundle.js' is defined in STATIC_BUNDLES:
Otherwise:
In general it simply acts as a proxy to the Django {% static %} templatetag with the inclusion of script/link/etc HTML tags.
The flow would be just like in your project. You'd start by defining STATIC_BUNDLES (in a build_settings.py, or something along the lines), and then you'd simply do the following (pre-commit?):
::
django-admin.py --settings=build_settings.py compilestatic