This tutorial explains how to use BowerStatic with a WSGI application. BowerStatic doesn’t have a huge API, but your web framework may provide more integration, in which case you may only have to know even less.
The Bower object¶
To get started with BowerStatic you need a Bower instance. Typically you only have one global Bower instance in your application.
You create it like this:
import bowerstatic bower = bowerstatic.Bower()
Integrating BowerStatic with a WSGI app¶
For BowerStatic to function, we need to wrap your WSGI application with BowerStatic’s middleware. Here’s to do this for our bower object:
app = bower.wrap(my_wsgi_app)
Your web framework may have special BowerStatic integration instead that does this for you.
Later on we will go into more details about what happens here (both an injector and publisher get installed).
Declaring Bower Directories¶
Bower manages a directory in which it installs components (jQuery, React, Ember, etc). This directory is called bower_components by default. Bower installs components into this directory as sub-directories. Bower makes sure that the components fit together according to their dependency requirements.
Each bower_components directory is an “isolated universe” of components. Components in a bower_components directory can depend on each other only – they cannot depend on components in another bower_components directory.
You need to let BowerStatic know where a bower_components directory is by registering it with the bower object:
components = bower.components('components', '/path/to/bower_components')
Bowerstatic needs an absolute path to the components. With the help of module_relative_path you can use a path relative to the calling module:
components = bower.components('components', bowerstatic.module_relative_path('path/relative/to/calling/module'))
You can register multiple bower_components directories with the bower object. You need to give each a unique name; in the example it is components. This name is used in the URL used to serve components in this directory to the web.
The object returned we assign to a variable components that we use later.
Including Static Resources in a HTML page¶
Now that we have a components object we can start including static resources from these components in a HTML page. BowerStatic provides an easy, automatic way for you to do this from Python.
Using the components object we created earlier for a bower_components directory, you create a include function:
include = components.includer(environ)
You need to create the include function within your WSGI application, typically just before you want to use it. You need to pass in the WSGI environ object, as this is where the inclusions are stored. You can create the include function as many times as you like for a WSGI environ; the inclusions are shared.
Now that we have include, we can use it to include resources:
This specifies you want to include the dist/jquery.js resource from within the installed jquery component. This refers to an actual file in the jQuery component; in bower_components there is a directory jquery with the sub-path dist/jquery.js inside. It is an error to refer to a non-existent file.
If you call include somewhere in code where also a HTML page is generated, BowerStatic adds the following <script> tag to that HTML page automatically:
Supporting additional types of resources¶
There are all kinds of resource types out there on the web, and BowerStatic does not know how to include all of them on a HTML page. You can tell the bower object how to handle a new resource type like this:
def render_foo(url): return "<foo>%s</foo>" % url bower.renderer('.foo', render_foo)
If you now include a resource like example.foo, that resource gets included on the web page as <foo>/path/to/example.foo</foo>.
You can also use renderer() to override existing behavior of how a resource with a particular extension is to be included.
If you include a resource with an unrecognized extension, a bowerstatic.Error is raised.
Let’s look at the URLs used by BowerStatic:
- The BowerStatic signature. You can change the default signature used by passing a signature argument to the Bower constructor.
- The unique name of the bower_components directory which you registered with the bower object.
- The name of the installed component as given by the name field in bower.json.
- The version number of the installed component as given by the version field in bower.json.
- A relative path to a file within the component.
BowerStatic makes sure that resources are served with caching headers set to cache them forever . This means that after the first time a web browser accesses the browser, it does not have to request them from the server again. This takes load off your web server.
To take more load off your web server, you can install a install a caching proxy like Varnish or Squid in front of your web server, or use Apache’s mod_cache. With those installed, the WSGI server only has to serve the resource once, and then it is served by cache after that.
|||Well, for 10 years. But that’s forever in web time.|
Bower has a concept of a main end-point for a component in its bower.json. You can include the main endpoint by including the component with its name without any file path after it:
This includes the file listed in the main field in bower.json. In the case of jQuery, this is the same file as we already included in the earlier examples: dist/jquery.js.
A component can also specify an array of files in main. In this case only the first endpoint listed in this array is included.
The endpoint system is aware of Bower component dependencies. Suppose you include ‘jquery-ui’:
The jquery-ui component specifies in the dependencies field in its bower.json that it depends on the jquery component. When you include the jquery-ui endpoint, BowerStatic automatically also include the jquery endpoint for you. You therefore get two inclusions in your HTML:
If main lists a resource with an extension that has no renderer registered for it, that resource is not included.
WSGI Publisher and Injector¶
Earlier we described bower.wrap to wrap your WSGI application with the BowerStatic functionality. This is enough for many applications. Sometimes you may want to be able to use the static resource publishing and injecting-into-HTML behavior separately from each other, however.
BowerStatic uses the publisher WSGI middleware to wrap a WSGI application so it can serve static resources automatically:
app = bower.publisher(my_wsgi_app)
app is now a WSGI application that does everything my_wsgi_app does, as well as serve Bower components under the special URL /bowerstatic.
BowerStatic also automates the inclusion of static resources in your HTML page, by inserting the appropriate <script> and <link> tags. This is done by another WSGI middleware, the injector.
You need to wrap the injector around your WSGI application as well:
app = bower.injector(my_wsgi_app)
Before we saw bower.wrap. This wraps both a publisher and an injector around a WSGI application. So this:
app = bower.wrap(my_wsgi_app)
is equivalent to this:
app = bower.publisher(bower.injector(my_wsgi_app))
Using the Publisher and Injector with WebOb¶
injector = bower.injector(wsgi=None) publisher = bower.publisher(wsgi=None) response = publisher.publish(request, injector.inject(request, response))
All that is required is a WebOb request and a response.