Flask-MakeStatic

Flask-MakeStatic is an extension for Flask that adds support for compilation of static files such as sass or coffeescript files.

In order to use it you simply create an assets directory and an assets.cfg file in the same directory as your static directory. assets should contain all files that require compilation and assets.cfg specifies how the files in assets should be compiled.

The simplest possible assets.cfg file would look like this:

[.*]
cp {asset} {static}

This defines a regular expression .* which matches any file in assets and copies the file to the static directory. {asset} will be replaced with the path to the file in the assets directory and {static} with the corresponding location within the static directory.

Since 0.2.0 you can also use globbing instead of regular expressions for your filename patterns, if you set the MAKESTATIC_FILEPATTERN_FORMAT configuration variable in your application configuration to 'globbing'.

As you can see the syntax is kind of like an ini file. You have sections which match files in your assets directory followed by one or more commands that are executed when a matched file is compiled.

Within these commands several substitutions are available, which you can use with the .format() string formatting syntax:

asset The absolute path to matched asset.
static The absolute path to the corresponding location in the static directory.
static_dir The absolute path to the static directory.
static_base Like static but without the file extension.

In order to compile your assets you have to first create a MakeStatic instance, this should be familiar if you have used other flask extensions:

from flask import Flask
from flask.ext.makestatic import MakeStatic

app = Flask(__name__)
makestatic = MakeStatic(app)

First of all you are probably concerned about development. During development you do not want to manually recompile all the time, so what you should do is call MakeStatic.watch() before calling flask.Flask.run():

if __name__ == '__main__':
    makestatic.watch()
    app.run(debug=True)

This will compile your assets whenever a change is detected.

In production environments using MakeStatic.watch() is not a good idea because it starts a new thread to look for changes and has to compile all assets at least once. This costs performance and may unnecessarily compile your assets in environments using multiple workers.

Instead what you want to do, is compile your assets during your deployment process. You can do this by calling MakeStatic.compile().

API

class flask.ext.makestatic.MakeStatic(app=None)

This class provides the extension interface. You can use it by calling it directly with a flask.Flask instance:

app = Flask(__name__)
make_static = MakeStatic(app)

Once initialized MakeStatic will parse the assets.cfg configuration file corresponding to the initialized application.

Since 0.3.0 MakeStatic can also be used with the factory pattern:

make_static = MakeStatic()
app = Flask(__name__)
make_static.init_app(app)

Take a look at init_app() for more information.

init_app(app)

Initializes a flask.Flask instance for use with this extension. Unlike calling MakeStatic with an app this will not bind the extension object to the given app so calls to watch() or compile() have to be done in an application context:

make_static = MakeStatic()

app = Flask(__name__)
make_static.init_app(app)
with app.app_context():
    make_static.compile()

New in version 0.3.0.

watch(sleep=0.1)

Starts a daemon thread that watches the static directory for changes and compiles the files that do change.

Returns a ThreadedWatcher, if you want to turn of watching you can call ThreadedWatcher.stop().

When run in a process started by the reloader, this does nothing to prevent the start of an unnecessary second watcher.

Parameters:sleep – The amount of time in seconds that should be slept between checks for changes, may be ignored.
compile()

Compiles all assets to static files in one go.

This works only when done within an application context of an initialized application.

Emits a RuleMissing warning for each file in assets for which no rule exists.

class flask.ext.makestatic.RuleMissing

Warning that is emitted if a rule cannot be found.

Differences to other Extensions

Quite often when discussing Flask-MakeStatic, people ask why they should use Flask-MakeStatic instead of some other extension or what the differences are.

This resource cannot provide an unbiased answer to that question, so if you want one, you will have to compare the extensions yourself but I will nevertheless attempt to provide at least a partial answer and defense for the design of this extension.

So far I am aware of two other extensions that intend to solve the same problem as Flask-MakeStatic, these are Flask-Assets and Flask-Funnel.

Unlike Flask-MakeStatic these extensions work by defining so called bundles, within the code of your application on which filters are applied, which perform the actual compilation.

In both cases you need to use extension specific code in your templates. In the case of Flask-Assets you even need to define the bundles, made up of your assets within the code of your application.

Both extensions have more knowledge about the filters you use and how you use them, this can be convenient and could possibly enable features, that cannot be provided by Flask-MakeStatic. On the other side this also restricts you, in your choice of filters. In the case of Flask-Funnel as of version 0.1.4 there is no documented way of adding any filters at all, in the case of Flask-Assets you can create your own filters and while this appears to be trivial and well documented it still requires code specifically for that purpose.

I created Flask-MakeStatic because I think that the frontend of your application, in which I include static resources, assets, and templates, should be as independent from your backend as reasonably possible. Flask-Assets and Flask-Funnel violate this principle by coupling of front- and backend and creating restrictions on the frontend beyond what I consider reasonable.

Flask-MakeStatic embraces this principle by providing you with a make inspired way to compile assets, in a way that integrates well with Flask applications.

Changelog

Version 0.3.0

In development

Version 0.2.1

  • Fixed bug in the HTML build of the documentation that could cause the title to overlap with the text in some cases.

Version 0.2.0

  • Added support for globbing instead of regular expressions, using the MAKESTATIC_FILEPATTERN_FORMAT configuration variable.
  • Increased lowest supported version of Flask to 0.10, which is the first release supporting Python 3.x.

Version 0.1.1

  • Fixed a typo in the documentation.

Version 0.1.0

Initial release.

Contributing

If you want to contribute to Flask-MakeStatic, fork the repository and create a local clone. Once you have done that, you should create a virtual environment in whichever manner you prefer. Having acticated the virtual environment you can install all tools that are useful in the development using:

$ make dev

Now you should take a look at make help. If you run that command, you will see a list of useful commands you can issue with a small description of what each one does.

If you make any changes to the code you should run make test-all before committing to ensure that your changes do not break anything on any of the supported Python versions and that the documentation builds successfully.

Running make test-all requires you to have installed the CPython implementations of all supported Python versions and PyPy. If you have not installed them already, you can do so quite easily using Homebrew on OS X.

If everything passes, commit your changes and make a pull request to master, if you introduced a new feature or make a pull request to the maintenance branch of the currently maintained version if you fixed a bug. Eventually someone will review your pull request and hopefully merge it.

License

Copyright (c) 2013 by Daniel Neuhäuser

Redistribution and use in source and binary forms of the software as well as documentation, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Fork me on GitHub