Resources¶
Static assets are usually under the control of a developer and can be managed by Cubane’s resource management system.
For Cubane, a resource is any file (usually part of the website’s code repository) that needs to be processed when deploying a website onto a production system.
See also
In opposite to static assets, media is generally speaking content that was uploaded by an author and is part of the content of the website and not its codebase. Read more about media within the topic for Media.
Requirements¶
Cubane’s resource system requires Django’s staticfiles
app. Please read
more about how Django manages static files.
Note
It is important that django.contrib.staticfiles
is loaded after
cubane
, because Cubane changes certain aspects of the runserver
management command. Those overwrite would be invalidated by
staticfiles
, if the order is reversed.
When setting up settings.INSTALLED_APPS
, please make sure that
django.contrib.staticfiles
is listing after cubane
and not before.
You can also use Cubane’s Settings environment to setup installed apps, which will take care of this automatically for you.
What the Resource Management System does¶
Cubane’s resource management system allows you to define a list of static files per Django app. In your project settings, you can then define which app’s resources are combined into a named bucket.
All resource files that are listed for each app within a bucket are then combined into one resource file. Finally, that resource file is minified and combined with a unique version number for each deployment.
In your templates, you can include resources in different ways based on each named bucket. In debug mode, all resources are included as separate files; however, in production mode, there is usually only one file included per bucket and type of resource.
Declaring Resources¶
All resources for an app are defined by the array RESOURCES
within the
__init__.py
file of your python package that is listed in your
settings.INSTALLED_APPS. Let’s assume that we had an app called myApp
,
which defined the following resources:
RESOURCES = [
'css/style.css',
'print|css/print.css',
'js/main.js',
]
Note
The order in which resource files are listed is important. Generally speaking, Cubane will process, combine and minify resources in the order as specified.
Further, you usually declare all your resources, even if they are of different type. Feel free to list all your CSS and Javascript resources together; Cubane will split resources by type later in the process automatically.
Because of the general layout of static assets managed by staticfiles
behind the scenes, we may have organized those assets in the following
structure:
myApp/
static/
myApp/
css/
style.css
print.css
js/
main.js
Each resource within the RESOURCES
array is declared relative to the
location of the static files of myApp
, which is myApp/static/myApp/...
.
In order for Cubane to process any resources, the app myApp
must be
installed in settings.INSTALLED_APP
:
INSTALLED_APPS = [
...
'myApp',
...
]
Declaring Resource Buckets¶
So far so good. Now, before we can include resources in our template, we first have to declare resource buckets and which app goes into which bucket:
In Cubane, you usually declare multiple resource buckets for different purposes: You may have a bucket for your front-end, then you might define another bucket that is inlined into the template because those resources need higher priority.
You may also have a print style as a separate file if you prefer to organise your print style that way.
Cubane’s backend system requires some style information as well and you certainly, do not want to mix this with your own front-end style.
For each bucket, Cubane will generate a separate file per resource type (for example CSS or Javascript), which can be included in a template differently.
You declare resource buckets in your application settings, for example:
RESOURCES = {
'frontend': [
'cubane.lightbox',
'myApp'
],
'inline': [
'cubane.medialoader'
]
}
The named bucket frontend
will include all resources from the
apps cubane.lightbox
and myApp
combined, in that order.
Note
The order in which apps are listed is important. Generally speaking, Cubane will process, combine and minify all resources from all apps in the order as specified.
The bucket inline
only contains the resources from only one app, which is
cubane.medialoader
. The media loader is responsible for lazy-loading
images and is therefore given its own bucket in order to inline its code into
the website markup directly for better performance. You can read more about
Cubane’s media system within the Media section.
Note
The buckets backend
and backend-inline
are reserved for Cubane’s
default backend system. Apart from those, you can declare as many buckets
as you need. If those reserved buckets are declared, then their content is
being added to the default resources that are loaded by the backend system.
For example, the following settings would load additional resources into the resource bucket that is used by the backend system.
RESOURCES = {
'backend': [
'myApp.backend_extensions'
]
}
Including Resources¶
After having declared all resource assets and buckets, we finally would
need to refer to those assets. We do this by using Cubane’s resource_tags
template library. The template library contains a set of template tags that can
be used to embed resource buckets into your template in various ways. The
following example should give you a good overview of how this works:
{% load resource_tags %}
<!DOCTYPE html>
<html>
<head>
...
<!-- inline CSS resources -->
{% inline_resources 'inline' 'css' %}
<!-- external CSS, you may want to inline above the fold css styles -->
{% resources 'frontend' 'css' %}
<!-- print resources -->
{% resources 'frontend' 'css' 'print' %}
{% resources 'inline' 'css' 'print' %}
</head>
<body>
...
<!-- inline Javascript -->
{% inline_resources 'inline' 'js' %}
<!-- external Javascript, async -->
{% resources 'frontend' 'js' %}
</body>
</html>
As a typical base template, you would – generally speaking – load CSS resources at the top and Javascript resources at the bottom. For best performance, some CSS code is critical: For example, you would want to embed a good portion of your CSS to render the above the fold content within your template itself, rather than loading an external CSS file. Other resources are less critical and can be loaded from an external file asynchronously.
The following sections will guide you through the different ways of embedding resources.
Inline Resources¶
The inline_resources
template tag will embed all resources from the given
bucket and resource type within the template itself. Usually this means
that Cubane will generate <style>...</style>
markup for CSS and
<script>...</script>
markup for Javascript code.
An example:
{% inline_resources 'inline' 'css' %}
{% inline_resources 'inline' 'js' %}
The first argument is the name of the bucket. The second argument is the type of resources that should be embedded. This argument is required since there are different ways of how resources are embedded depending on the type of resources.
Tip
For best website performance, you should always split your stylesheet into critical CSS code that must be present to render everything above the fold and any remaining CSS code for styling other – less important – parts of your website.
Critical above the fold CSS code should be inlined if such code is not too heavy in size. Any other CSS code may be loaded from an external file.
In Production mode, all embedded resources will have been combined and minified before being embedded into the template at deployment time.
Note
In Debug mode, Cubane will never actually embed content within the template. When debugging CSS or Javascript code, it is much easier to use the browser’s development tools which can refer to actual files instead of referring to inline HTML code.
External CSS¶
External CSS code can be included with the resources
template tag. Unlike
the previous example, we are now instructing the browser to load additional
resources from an external file.
An example:
<!-- css (screen only) -->
{% resources 'frontend' 'css' %}
<!-- css (print only) -->
{% resources 'frontend' 'css' 'print' %}
Unlike inline_resources
, an additional argument may be provided that
declares the CSS media type, such as screen
or print
. screen
is
assumed by default if this argument is not given.
Cubane will generate markup like <link href="..." rel="stylesheet"
media="screen">
when including CSS resources using the resources
template
tag.
In Production mode, all resources from the named bucket will have been
combined and minified into one file at deployment time. In Debug mode, Cubane
will generate individual <link>
tags, one for each resource file within the
bucket.
You can instruct the browser to load a CSS resource asynchronously by adding
the async
argument like:
<!-- load css asynchronously -->
{% resources 'frontend' 'css' 'screen' 'async' %}
Loading CSS asynchronously currently relies on Javascript. Cubane will generate a bit of inline Javascript code that will instruct the browser to load the CSS resource without blocking the rendering of the website.
Note
Browsers are beginning to support a standard markup pattern for loading CSS
(and other file types) asynchronously via <link rel="preload">
.
External Javascript¶
Like loading external CSS files, you can use the same template tag
resources
to include external Javascript files as well, like in the
following example:
<!-- external javascript, asynchronously -->
{% resources 'frontend' 'js' %}
{% resources 'frontend' 'js' True %}
<!-- external javascript, blocking -->
{% resources 'frontend' 'js' False %}
The first two lines are identical and will both instruct the browser to load an
external Javascript file (representing the frontend
bucket) asynchronously.
Note
All external Javascript code is loaded asynchronously by default.
The last line is loading the same external Javascript file by blocking the browser.
Declaring CSS Resources¶
CSS files are declared by simply referring to the path of one or multiple CSS files. Because CSS can target different media types, such as screen or print media, Cubane allows us to specify the type of media alongside each resource file:
RESOURCES = [
'screen|css/screen1.css',
'screen|css/screen2.css',
...
'print|css/print1.css',
'print|css/print2.css',
...
]
The media type if prefixed to the resource path by using the pipe character:
[<resource-prefix>] | <resource-path>
The prefix is optional. In the context of CSS files, screen
is assumed if
omitted. Therefore we could have written the following instead:
RESOURCES = [
'css/screen1.css',
'css/screen2.css',
...
'print|css/print1.css',
'print|css/print2.css',
...
]
In both cases, Cubane will combine the first two resource files for the media
type screen
and the remaining two resources for the media type print
.
Note
For CSS, the order in which resource files appear in the list may matter; Cubane will combine and minify all CSS files within the same bucket and media type in the order as specified. If your CSS files need to appear in a specific order, then please make sure that this order is reflected when listing your resources.
When working with CSS, it is quite common to use a CSS reset style to unify the default browser style to a known and precise state, so that your own style can be defined on top it.
Usually, such CSS reset style is listed at the beginning of your resource list, followed by your own style files.
Tip
Alternatively, Cubane provides a default out of the box CSS reset style.
Simply include the app cubane.cssreset
within your list of installed
Django apps like in the following example:
INSTALLED_APPS = [
...
'cubane',
'cubane.cssreset',
'myApp',
...
]
The final step is to include all resources from cubane.cssreset
within
your resource bucket of choice, let’s assume that your website is using the
frontend
bucket:
RESOURCES = {
'frontend': [
'cubane.cssreset',
'myApp',
],
...
}
Make sure that cubane.cssreset
appears before your own app containing
your own style, since the order in which CSS style information appears
matters, in particular with CSS reset style.
Declaring Javascript Resources¶
Javascript files are declared by simply referring to the path of one or multiple Javascript files:
RESOURCES = [
'js/lib/jquery.js',
'js/main.js',
...
]
The order in which Javascript files are declared may be important. For example,
if main.js
would refer to JQuery, then you should make sure that the source
for JQuery appears before main.js
.
Declaring Font Resources¶
Web Fonts play an increasingly important role. Cubane provides an automatic process for including a large number of free web fonts within your websites.
Cubane provides a default font backend which is using the google-webfonts-helper by Mario Ranftl.
You can use any font (listed on the Google WebFonts Helper website) by simply including it as a resource within your app’s list of resources like in the following example:
RESOURCES = [
'font|Open Sans',
...
]
And that’s it. In your CSS style, you can now use the font, for example:
body {
font-family: 'Open Sans', sans-serif;
}
Cubane will automatically download all required font files to your local system and will also generate all required CSS style for the declaration of the font.
Note
When referring to fonts, make sure that the name of the font is given as listed on the Google WebFonts Helper website, otherwise, Cubane will not be able to locate the exact font.
Cubane’s font system allows for further customisation and extension which would go beyond the scope of this section. Please refer to the Fonts section for further information about Cubane’s font system.
Declaring Resources with Absolute Path¶
When declaring resources, you would usually use a relative path to refer to individual resource files, as in the following example:
RESOURCES = [
'css/style.css'
'js/main.js',
...
]
The path is considered to be a relative path because it does not start with a
slash (/). Therefore the path is relative to the app that declared the list
of resources. Let’s assume that your app is called myApp
, then you may use
the following directory structure for your static assets (remember that
Cubane’s resource system requires Django’s staticfiles
):
myApp/
static/
myApp/
css/
style.css
js/
main.js
The relative path css/style.css
will be extended to
/myApp/css/style.css
, which will then refer to the correct file within the
myApp
app. Under the hood, Cubane will use Django’s staticfiles
resolution mechanism to find static files in the described way.
Instead of specifying resource based on a relative path, you can specify resources by using an absolute path instead; starting with a slash (/):
RESOURCES = [
'/myApp/css/style.css'
'/myLib/js/jquery.js',
'/myApp/js/main.js',
...
]
In this example, all resources are referred to by using absolute paths. An absolute path will not be prefixed automatically with the name of the app that declared those resources.
Instead, an absolute path is fed into Django’s staticfiles
resolution
mechanism directly. As long as the path assembles a valid path to a static
asset for any installed Django app, this will work.
Note
Please consider to use absolute paths rarely and only if it makes your life so much easier. In most cases, we find that it is a good thing that each Django app is isolated from each other; by using absolute paths, you may create hidden dependencies between your apps.
We would advise to use absolute paths only if you need to and only if you do not intend to share your app with anyone else.
Declaring Media Resources¶
Usually, resources are assets that are part of the codebase and Django’s
staticfiles
requires those assets to be located within one specific folder
per app, which is usually called static
.
On the contrary, there is media, which is usually user-generated content, like
images uploaded to the system etc. Such data is usually stored in one folder
called media
, which is not part of the code repository.
If you require assets that are downloaded from third-party sources and are of temporary nature, you may want to store such data within the media folder and not within the static folder, since the media folder is not part of the code repository.
If you wanted to serve those resources through the pipeline, then you can refer to those assets by referring to the media folder in the following way:
RESOURCES = [
'/media/imgcache/tiles.css',
...
]
In this example, we assume that you have some process for caching CSS style information that is generated by a third party. Such data is stored in the media folder for reasons outlined above.
In order to include this resource in the build process, you can simply refer to the file via an absolute path to the media folder.
Declaring External Resources¶
Usually, resources would become part of your code base and you would always refer to local files; however, sometimes you would want to include resources from external web servers.
For this reason, resources can be declared by simply specifying an absolute URL, for example
RESOURCES = [
'https://example.com/files/js/calendar.js',
...
]
In this example, the pipeline would automatically download the file
/files/js/calendar.js
from example.com at deployment time. The downloaded
file would then become part of the resource bucket which is ultimately minified
together with other javascript resources.
Pattern Expansion¶
Resources can be declared by using UNIX-style pathname pattern expansion. For
example, instead of listing all CSS style files individually you could simply
refer to all files with the extension .css
instead:
RESOURCES = [
# listing all resources individually:
'css/components/header.css',
'css/components/button.css',
'css/components/carousel.css',
'css/components/footer.css',
# using pattern expansion instead:
'css/components/*.css',
...
]
The first block is (almost) equivalent to the second block: While the first block refers to all style files individually, the second block simply refers to all CSS style files within a specific folder.
Cubane will automatically expand the pattern css/components/*.css
into a
list of individual file paths based on the expansion of the pattern. Each CSS
file within the css/components
folder will be listed in alphabetical
order.
Note
When using pattern expansions, the resulting list of individual file paths is sorted alphabetically by default. If the order in which your resource files appear matters than it may not be appropriate to use pattern expansion.
However, there are a lot of cases where the order does not matter. For CSS style files for example, if you separated your style based on independent style components then the precise order in which they appear may not matter at all.
We would advise declaring individual files where the order matters and to use pattern expansion where the order of things does not matter.
Pattern expansion is particularly useful for SVG-based icons. You can read more about SVG-based icon sets within the SVG Icons section.
Resource Templates¶
In some cases, it can be useful to embed generated data or content into resource files. Cubane is using this concept in a number of places where this is required, for example, the media loader or the font system.
Basically, you can instruct Cubane to process any resource file through Django’s template system before serving the file. This would allow you to generate parts of the resource file dynamically based on data generated by your application.
We would not advise using this technique for implementing CSS themes or performing computation for CSS style in general for your website’s theme; there are far better solutions for pre-processing CSS style information.
However, for generating short bits of CSS style or generating constants based on your settings within your Javascript files, the template system might be exactly what you need.
First, you have to rename your asset file to include the reserved extension
template
, for example, main.js
would become main.template.js
.
RESOURCES = [
# referring to a template instead of a static file will invoke
# Django's template system...
'js/main.template.js',
...
]
This is actually enough to invoke Django’s template system. In most cases, you would want to construct an additional template context for your template that contains some data required to render the template.
In your app’s __init__.py
file, define a method called
get_deploy_context()
that returns a dictionary that is used as the template
context for rendering any asset (of your app) via Django’s template system:
def get_deploy_context():
return {
'greetings': 'Hello World'
}
Finally, in your main.template.js
file, you can use Django’s template system
to generate Javascript code dynamically.
var greetings = '{{ greetings }}';
...
In Debug mode, the runserver
command will process templates as they are
requested. For example, when the browser downloads the file
/static/myApp/js/main.template.js
, then the Django template system is
invoked and the following result is returned to the browser:
var greetings = 'Hello World';
...
In Production mode, the template system is invoked only once, when the
website is deployed. All static assets are generated at deployment time and the
file main.template.js
file actually contains the final result after the
website has been deployed.
Using RequireJS¶
RequireJS is a Javascript file and module loader. If your Javascript code base is using RequireJS, Cubane can help you to automatically compile and minify your Javascript code as part of the site’s deployment.
For every RequireJS main javascript source file, you need to declare the following entry in your application’s settings file:
REQUIRE_JS = [
{
'filename': 'myProject/js/require_js_main.js',
'baseurl': 'myProject/js',
'module': 'require_js_main'
}
]
The REQUIRE_JS
settings variable declares a list of Javascript
sources that are using RequireJS as a module loader.
filename
Required. For each source, thefilename
argument is required in order to provide the path to the main entry file for your RequireJS source.
baseurl
Optional. Root directory for every module search.
module
Optional. Name of the module as declared in your main javascript file.
See also
Please refer to the RequireJS Documentation <http://requirejs.org/docs/start.html> for more information on RequireJS.