Static file versioning with Django - html

I am setting far-future expires headers for my CSS/Javascript so that the browsers don't ever ask for the files again once they get cached. I also have a simple versioning mechanism so that if the files change, the clients will know.
Basically I have a template tag and I do something like
<script type="text/javascript" src="{{ MEDIA_URL }}{% versioned "javascript/c/c.js" %}"></script>
which will become
<script type="text/javascript" src="http://x.com/media/javascript/c/c.min.js?123456"></script>.
The template tag opens a file javascript/c/c.js.v where it finds the version number and appends it to the query string. The version is generated by a shell script (run manually for now, will probably add pre-commit hook) which checks whether the file has changed (using git diff).
This is all working fine, EXCEPT:
I want to implement the same kind of versioning for images as well. But images can be referenced from CSS - which is a static file (served by nginx) - so no template tag there.
What is a better approach for file versioning?
Alternatively, I am thinking about replacing the template tag with a middleware which changes all links before returning the response. That is better than the template tag, which can be mistakenly omitted. But still doesn't solve the issue of images referenced from CSS.
Also, I'm aware that having the version as part of the query string might cause trouble with certain proxies not caching the file - so I consider making the version part of the filename - for example javascript/c/c.123456.js.
Note: It looks like there is no way to solve this issue using Django (obviously - since I don't even serve the CSS through Django). But there has to be a solution, perhaps involving some nginx tricks.

Stylesheet Assets
For your stylesheet referenced assets, you're much better off using Sass & Compass. Compass has a mixin that will automatically add version query parameters on the end of static assets referenced within a stylesheet. The version number only changes when you rebuild the stylesheet (which is trivial with compass watch while you develop locally).
Template Assets
For other files, I would actually use a post-pull hook of some kind that rewrites a python module whose sole purpose is to contain the current version.
/var/www/aweso.me/
./files/
./private-files/
./static/
./project/
./manage.py
./fabfile.py
./.gitignore
./base/
./__init__.py
./wsgi.py
./settings/
./__init__.py
./modules
./__init__.py
./users.py
./email.py
./beta.py
./redis.py
./haystack.py
./version.py
./default.py
./local.py
./live.py
Your post pull hook would create :
/var/www/aweso.me/project/base/settings/version.py
Which would contain the latest (or previous) git commit hash :
__version__ = "0763j34bf"
Then with a simple from .version import __version__ as ApplicationVersion in your settings.live, your template tag can simply use from settings import ApplicationVersion to write that query parameter as teh cache buster.

We are using this simple templatetag to generate version number based on file modification time:
import os
import posixpath
import stat
import urllib
from django import template
from django.conf import settings
from django.contrib.staticfiles import finders
register = template.Library()
#register.simple_tag
def staticfile(path):
normalized_path = posixpath.normpath(urllib.unquote(path)).lstrip('/')
absolute_path = finders.find(normalized_path)
if not absolute_path and getattr(settings, 'STATIC_ROOT', None):
absolute_path = os.path.join(settings.STATIC_ROOT, path)
if absolute_path:
return '%s%s?v=%s' % (settings.STATIC_URL, path, os.stat(absolute_path)[stat.ST_MTIME])
return path
For pre 1.3 Django there is even simpler version of this tag:
#register.simple_tag
def staticfile(path):
file_path = os.path.join(settings.MEDIA_ROOT, path)
url = '%s%s?v=%s' % (settings.MEDIA_URL, path, os.stat(file_path)[stat.ST_MTIME])
return url
Usage:
<link rel="stylesheet" href="{% staticfile "css/style.css" %}" type="text/css" media="screen" />

Will add another step to my pre-commit script to replace all direct links with links to versioned files in the minimized CSS.
Seems there is no better way to do it. If you think of any, let me know and I'll consider marking that one as accepted answer.
Thanks for your comments!

This might help as well: http://www.fanstatic.org/

I think a simple solution might be:
Write your css files as Django templates.
Write a Django command to render your css-templates (and store them in somewhere accessible)
In your deployment script call this command.

Related

Import Polymer 2 components in Polymer 3

I am developing a web component using Polymer v3, and need to include some custom elements defined in legacy Polymer 2 components in the template HTML of my new component.
Since HTML imports are no longer supported in Polymer 3, what approach should I take to include them? If I was using Polymer 2 I could just add the following in my component's HTML file:
<link rel="import" href="../my-legacy-component.html">
I have tried adding the above link into the template HTML of my component, but it appears that doesn't work. I have also tried various import commands to reference the JS files inside the legacy component directly, but received various inscrutable JS errors so I'm not sure if that is the correct way to go either.
I can't believe there isn't a simple way to do this - would the Polymer team really introduce a new version of the library that is completely incompatible with all the components created using older versions?
Did you try to use polymer-modulizer?
Modulizer performs many different upgrade tasks, like:
Detects which .html files are used as HTML Imports and moves them to .js
Rewrites in HTML to import in JS.
Removes "module wrappers" - IIFEs that scopes your code.
Converts bower.json to package.json, using the corresponding packages on npm.
Converts "namespace references" to the proper JS module import, ie: Polymer.Async.timeOut to timeOut as imported from #polymer/polymer/lib/util/async.
Creates exports for values assigned to namespace referencs. ie, Foo.bar = {...} becomes export const bar = {...}
Rewrites namespace objects - an object with many members intended to be used as a module-like object, to JS modules.
Moves Polymer element templates from HTML into a JS template string.
Removes s if they only contained a template.
Moves other generic HTML in the document into a JS string and creates it when the module runs.
more on github
I have ran into the same problem with the module js-yaml earlier. I don't have enough reputation for a comment yet so I just write it down here.
Run this sudo npm install -g js-yaml -> This will install the missing package for the tool
Then at the root of your project, run modulizer --import-style name --out . -> This will convert your component from Polymer 2 to Polymer 3. The option --import-style name tells the tool to use package name instead of path. --out will make the tool writes those files to the directory.
After that, if no error prompts. Try to serve it with polymer serve --module-resolution=node -> Since we are using node modules now, we have to provide the --module-resolution=node option.

How can I handle html files in Luminus which aren't in "resources"?

I have this:
(defn about-page []
(layout/render "about.html" {:title "About"}))
But since I have moved the directory "templates" from "resources" to the root directory and on a server I might put it yet in another place, it doesn't work. I did it because I don't want the html templates to be embedded in the output jar.
So how can I make the code work, how can I get access to my html files in "templates" then?
And the same question for static images, css, js: I put them in the root directory for now, so they aren't in "resources". They're in "public" folder. However, when I refer to them as "public/css/css1.css", they aren't getting found, that is, the path localhost:3000/public/css/css1.css doesn't exist.
How can I tell Luminus where my statics are located now?
Templates location
Selmer's documentation describes how to change the location of the templates:
By default the templates are located relative to the ClassLoader URL.
If you'd like to set a custom location for the templates, you can use
selmer.parser/set-resource-path! to do that:
(selmer.parser/set-resource-path! "/var/html/templates/")
It's also
possible to set the root template path in a location relative to the
resource path of the application:
(set-resource-path! (clojure.java.io/resource "META-INF/foo/templates"))
This allows the templates to be refrerenced
using include and extends tags without having to specify the full
path.
To reset the resource path back to the default simply pass it a nil:
(selmer.parser/set-resource-path! nil)
The application will then look
for templates at this location. This can be useful if you're deploying
the application as a jar and would like to be able to modify the HTML
without having to redeploy it.
As you want your templates to be reload when you change them you should also remember that Selmer caches them:
When rendering files Selmer will cache the compiled template. A
recompile will be triggered if the last modified timestamp of the file
changes. Note that changes in files referenced by the template will
not trigger a recompile. This means that if your template extends or
includes other templates you must touch the file that's being rendered
for changes to take effect.
Alternatively you can turn caching on and off using
(selmer.parser/cache-on!) and (selmer.parser/cache-off!) respectively.
Assets location
Handling of static resources is configured using site-defaults in your <app>.middleware namespace. You need to configure its' :static entry to use :files instead:
(-> site-defaults
(assoc :static {:files "/var/www/html"}))
and you need to copy files from resources/public directory to that location.

yii2: where do my project's own html, css, js, and php-include files go?

Choices:
create an asset bundle (nicely explained by Ivo Renkema at How do I manage assets in Yii2?). this is what I need if I want to package my code for other use. alas, should I also do this for my own php include library functions? Or should I still stick them into the same php location as my other php files? In any case, if I want to go this route, presumably I would then customize the AppAsset class, included in the template, as explained in http://www.yiiframework.com/doc-2.0/guide-structure-assets.html .
stick my files directly into $basePath/web, where $basePath is typically something like /var/www/myapp/ (i.e., as $basePath/html/mine.html [and refer to it simply as href='/html/mine.html'], $basePath/css/mine.css , $basePath/js/mine.js, and $basePath/php/mine.php [and refer to it as $basePath= \Yii::getAlias('#webroot'); require_once('$basepath/php/mine.php') ])?
stick my local files where my php view code sits. the advantage is that the files are close to where I will use them. the disadvantage is that I may litter the view directories not only with php files, but also with my non-asset assets, even though they will be used only by these (my) php files.
it's a beginner's question for the google cache reference. it's about best practice when getting started. I can guess the answer, but we wouldn't want a novice to disseminate bad info.
If you need your CSS and JS files only in one view or one Controller you have 2 choices:
1- Create a asset bundle Here other guide if you need it.
2- Use registerJsFile() from View Class
You can acces from controller using:
Yii::$app->view->registerJsFile('js.path');
(Same with CSS files but using registerCssFile())
With the PHPfiles I always try to convert the code to yii's MVC. If you have a entire library try to add it as a component. Here a usefull guide

how to get source code for read the docs html template?

how to get source code of html template of read the docs ?
I get sphinx package from git hub but i don't know python or how to proceed with that package
I simply want HTML and css files of that template then i will modify according to my requirement
If you want to use the ReadTheDocs theme locally with Sphinx you can clone/fork the code from the Github repository below.
Source: https://github.com/snide/sphinx_rtd_theme
If you're also building your Docs using readthedocs.org you'll need to enter the following to your conf.py to avoid issues with the RTD build process:
# on_rtd is whether we are on readthedocs.org, this line of code
grabbed from docs.readthedocs.org
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if not on_rtd: # only import and set the theme if we're building docs locally
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
Otherwise, readthedocs.org uses their theme by default, so no need to specify it.

Polymer element with javascript dependencies

I've created a Polymer element for rendering markdown which uses the marked.js library. I was wondering, what is the recommended way of loading in its dependencies?
Should I just use a script tag?
<script src="../marked/lib/marked.js"></script>
Or would it be better to put all of my dependencies into an html import and link to that one file. In this case I only have one dependency but I could easily have more.
<!-- in scripts.html -->
<script src="../marked/lib/marked.js"></script>
<script src="../foo/foo.js"></script>
<script src="../bar/bar.js"></script>
<!-- in mark-down.html -->
<link rel="import" href="scripts.html">
Note: These paths assume my element (and its dependencies) are being installed with bower so they should all be siblings in bower_components.
Private resources should be installed in your component folder and used directly. But shared resources, those resources that other components my also want to use (like marked), should be handled as dependencies.
We suggest two conventions for handling shared dependencies:
always use the canonical path which is ../<package-name> (you did this already). Polymer by convention expects a flat-dependency folder (as supported by Bower), so any resource you need must always be on this path.
refer to an import for the shared resource.
In this case,
<script src="../marked/lib/marked.js">
meets the first convention. Your component can depend on marked package and expect it to exist at ../.
The second convention supports sharing. If more than one component in a project uses a script tag to load a library, the library will load multiple times. Imports, on the other hand, are de-duplicated, so you don't have this problem.
For example, if all components load marked the standard way:
<link rel="import" href="../marked-import/marked-import.html">
then you will only ever have one copy of the script loaded.
Additionally, imports allow you to indirect the actual resource. For example, normally marked-import would depend on marked and use a script tag to load the JavaScript. But in fact, any particular project author can modify the local marked-import.html to load the main code from a CDN or from any other location. By indirecting all access through the import, we create a single point of control.
Today, marked and other libraries do not include import files, so we have to fill in those gaps. Additionally, it will require coordination with other components (to have agreement on what the standard import name will be for any particular shared resource). As (and if) these conventions are adopted, such questions will lessen over time.
So, your component installed would look something like this:
/components
/mark-down - depends on marked-import
/marked-import - (controlled by user, can just depend on `../marked`)
/marked