Dependency Management In Django Using Bower
Pablo Vallejo
Software EngineerIn today's web applications it's very common to use libraries and have several dependencies that are used in the front end of our projects. Usually we start by including jQuery and then, we keep adding more and more dependencies as we need. Every time we see more developers following best practices like assets minification and concatenation, often taking advantage of Django pipeline, which makes it easy to have a list of files minified and merged into a single one.
One of the things that isn't quite used in the wild though is versioning front end dependencies in opposition with the way we version backend libraries and frameworks which is usually very specific.
Versioning front end dependencies can save us a lot of time in the process of update, keeping track of which of them are outdated and debugging quickly as we easily spot what version of each library we have.
Bower from Twitter is a popular package manager that addresses most of these cases, it helps us to install, update and delete dependencies like jQuery and Bootstrap in an easy way. On the other hand allows us to have a list of installed packages which can be updated every time we install, update or remove a library.
The Plan
In this article I want to show you how to use Bower in your Django projects, specifically we'll take a look at how to define the folders structure, how to setup Bower and get started with the basic commands. Also, we will look at how to setup
Jenkins for deployments, and fetch front end packages on build. So, without further adieu, let's get started.
Folder Structure
For the example project, we've created a simple files structure based on
AxiaCore's Django Project Template. This template comes with an app
folder in which we'll have all our assets. The example project can be downloaded from GitHub.
Get example code on GitHub:
View on GitHub
Installing NodeJS and Bower
Install Node JS, from the
website, then issue this command to have bower globally installed.
$ npm install bower -g
</pre>
The
-g
flag tells Node Package Manager (NPM) to install the package globally, so that it's available in all locations, not only in the current project.
Bower.json
bower.json
is the file that describe our project, here among other information, we have a list of all the libraries we are using. Everytime we install a new library, we can use pass the option --save
with the install command and the library will be added to bower.json
.
{ "name": "awesomeProject", "version": "0.1.0", "dependencies": { "jquery": "~2.1.1" }};
Specifying packages directory with .bowerrc
Using
.bowerrc
we can specify the folder in which dependencies are stores, by default all packages are saved in bower_components
. This is particularly helpful in Django projects, as assets are most of the times not directly stored in the root folder.
{ "directory": "app/static/bower_components" }
With this configuration, components will be saved under
app/static/bower_components
given that in this example we have all our assets in app/static
, however, the location of the assets
folder may vary from project to project.
Using .gitignore
One of the nice things of using Bower is that we don't have to store project dependencies in our repository because these can be installed by each developer with running
bower install
within the project folder. Given that, we want to have git ignoring bower_components
folder.
# ...# Ignore bower components.bower_components# ...
Installing new dependencies
Now that we have Bower installed, let's add a couple of libraries to our project.
$ bower install jquery --save
$ bower install bootstrap --save
These commands will fetch jQuery and Bootstrap to our
bower_components
folder, we are passing the --save
option, in order to have these libraries listed in bower.json
for future use.
Having all dependencies saved in
bower.json
is useful as other developers can clone the project and have all dependencies with just issuing bower install
instead of writing one command per package.
Other useful command is
search
which shows all the packages in the Bower registry that match our query.
<pre lang="bash">$ bower search underscore<br/></pre>
In order to use a package from the list, just install it with its name as seen in the search results.
bower list is another useful command that show all the packages that we have installed along with their version.
$ bower list
Including Packages In Project
Now that we have the packages, we can include them in our project.
Using Django Assets Pipeline
Django Pipeline is a nice library for concatenation and compression of assets, with it, we can list of our assets in a configuration file and call them from a template using a single tag. To use the libraries we just installed, go to settings.py
and add the following lines to include Bootstrap styles and jQuery.
# CSS Files.
PIPELINE_CSS = {
# Project libraries.
'libraries': {
'source_filenames': (
'bower_components/bootstrap/dist/css/bootstrap.css',
),
# Compress passed libraries and have
# the output in`css/libs.min.css`.
'output_filename': 'css/libs.min.css',
}
# ...
}
# JavaScript files.
PIPELINE_JS = {
# Project JavaScript libraries.
'libraries': {
'source_filenames': (
'bower_components/jquery/dist/jquery.js',
),
# Compress all passed files into `js/libs.min.js`.
'output_filename': 'js/libs.min.js',
}
# ...
}
After this setup, you can go to the template in which you want to use the libraries and include them using
compressed_js
and compressed_css
from Django Pipeline.
!-- compressed tags is created by Django Pipeline. --{% load staticfiles compressed %}!-- Include CSS files --{% compressed_css 'libraries' %}!-- ... --!-- Include JavaScript files --{% compressed_css 'libraries' %}
compressed_css
tag paints the rel's
for all the styles we specified in settings.py PIPELINE_CSS
and so does compressed_js
with the ones in PIPELINE_JS
. Note that the string we're passing to the tag is the set of files we want to use.
When in development,
compressed
tags will print markup to load each file using link
or script
, however, in production it will compress the assets and paint one single tag to load the compressed file with the concatenated assets.
Using Bower With Jenkins
One of the things that prevents developers from using Bower is that there's not so many documentation on how to build and deploy projects that use
NPM using Jenkins, however, with a little configuration, we can have Jenkins building our projects and executing NPM commands.
Jenkins is a continuous integration server that's very used in the Django community. It allows to deploy applications, run tests, linting source code and more. We can also used it to run NPM commands and fetch our project assets from Bower registry, so that we don't have to have them in our repository.
In order to run NPM with
Jenkins we have to install Node JS Plugins, which helps us with the NodeJS setup. The preferred way of installing this plugin is via the Jenkins
Plugins Interface which can be accessed by going to your Jenkins home and adding /pluginManager to the URL. Once there, in the Available
tab we can search for NodeJs Plugins and install it.
Jenkins.sh configuration.
Within Jenkins build file
jenkins.sh
, we're going to tell it to install Bower and then the packages from bower.json
.
# ...
# Keep NodeJS in the current workspace.
$ export npm_config_prefix=.npm/
$ export PATH=.npm/bin:$PATH
# Install bower.
$ npm install -g bower
# Install bower packages.
$ bower install
# ...
After adding the above lines to Jenkins build file, you can commit and push your project changes in order for it to be built, then Jenkins will take care of installing Bower and fetching needed packages.
Conclusion
I personally have found
Bower to be very helpful in my development workflow, it allows me to have dependencies organized and to manage them easily, installing, uninstalling and updating them with simple commands.
I hope you can start taking advantage of it and include it in your workflow, also, don't hesitate on telling us how you're using it!.
Special thanks to Tuts Plus for their article on bower and to Pascal Hartig's Article on Jenkins integrations with NodeJs packages.
Written by Pablo Vallejo
Pablo develops and optimizes software solutions, focusing on functionality and user experience. His expertise in coding and problem-solving ensures the creation of efficient and reliable applications.