5

我正在为我的 CSS/Javascript 设置远期过期标头,以便浏览器在缓存后不再要求文件。我还有一个简单的版本控制机制,这样如果文件发生变化,客户就会知道。

基本上我有一个模板标签,我做了类似的事情

<script type="text/javascript" src="{{ MEDIA_URL }}{% versioned "javascript/c/c.js" %}"></script>

这将成为

<script type="text/javascript" src="http://x.com/media/javascript/c/c.min.js?123456"></script>.

模板标签打开一个文件javascript/c/c.js.v,在其中找到版本号并将其附加到查询字符串中。该版本由一个 shell 脚本生成(现在手动运行,可能会添加 pre-commit 钩子),该脚本检查文件是否已更改(使用git diff)。

这一切都很好,除了:

我也想为图像实现相同类型的版本控制。但是图像可以从 CSS 中引用——这是一个静态文件(由 nginx 提供)——所以那里没有模板标签。

文件版本控制的更好方法是什么?

或者,我正在考虑用一个中间件替换模板标签,该中间件会在返回响应之前更改所有链接。这比模板标签要好,模板标签可能会被错误地省略。但仍然没有解决从 CSS 引用的图像的问题。

另外,我知道将版本作为查询字符串的一部分可能会导致某些代理不缓存文件的问题 - 所以我考虑将版本作为文件名的一部分 - 例如javascript/c/c.123456.js.

注意:看起来没有办法使用 Django 来解决这个问题(显然——因为我什至不通过 Django 提供 CSS)。但必须有一个解决方案,可能涉及一些 nginx 技巧。

4

5 回答 5

1

样式表资产

对于样式表引用的资产,最好使用 Sass 和 Compass。Compass 有一个 mixin,它会在样式表中引用的静态资产的末尾自动添加版本查询参数。版本号仅在您重建样式表时更改(compass watch在本地开发时这很简单)。

模板资产

对于其他文件,我实际上会使用某种类型的 post-pull 钩子来重写一个 python 模块,其唯一目的是包含当前版本。

/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

您的后拉钩将创建:

/var/www/aweso.me/project/base/settings/version.py

其中将包含最新(或以前)的 git commit hash :

__version__ = "0763j34bf"

然后在您的模板标签中添加一个简单from .version import __version__ as ApplicationVersionsettings.live,您的模板标签可以简单地用于from settings import ApplicationVersion将该查询参数写入缓存破坏者。

于 2013-05-20T08:20:14.863 回答
0

我们使用这个简单的模板标签来根据文件修改时间生成版本号:

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

对于 1.3 之前的 Django,这个标签有更简单的版本:

@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

用法:

<link rel="stylesheet" href="{%  staticfile "css/style.css" %}" type="text/css" media="screen" />
于 2011-05-12T11:20:26.093 回答
0

将在我的预提交脚本中添加另一个步骤,将所有直接链接替换为最小化 CSS 中版本化文件的链接。

似乎没有更好的方法来做到这一点。如果您有任何想法,请告诉我,我会考虑将其标记为已接受的答案。

感谢您的意见!

于 2011-05-16T06:28:56.130 回答
-1

我认为一个简单的解决方案可能是:

  1. 将您的 css 文件编写为 Django 模板。
  2. 编写一个 Django 命令来呈现您的 css 模板(并将它们存储在可访问的地方)
  3. 在您的部署脚本中调用此命令。
于 2011-06-09T08:55:15.900 回答
-1

这也可能有帮助:http: //www.fanstatic.org/

于 2011-06-09T06:35:22.553 回答