Permalink
Browse files

Changed cache-busting implementation for static files

Since 3.2.1 django CMS has used the ``GET`` parameter to reset the cache of its
static files. This doesn't play well with proxies, CDNs and so on.

This patch invalidates caching by changing the paths of static files instead.

The django CMS release process now requires additional steps to account for the
change (documented).
  • Loading branch information...
1 parent 9485daf commit 6c41c31634303478466da3e830424abcf3c651ea @vxsx vxsx committed Jun 29, 2016
Showing with 53 additions and 62 deletions.
  1. +2 −0 CHANGELOG.txt
  2. +4 −2 RELEASE_INFO
  3. +0 −3 cms/forms/wizards.py
  4. +3 −0 cms/static/cms/css/3.3.0/cms.base.css
  5. +3 −0 cms/static/cms/css/3.3.0/cms.pagetree.css
  6. +3 −0 cms/static/cms/css/3.3.0/cms.welcome.css
  7. 0 cms/static/cms/css/{ → 3.3.0}/cms.wizard.css
  8. +0 −3 cms/static/cms/css/cms.base.css
  9. +0 −3 cms/static/cms/css/cms.pagetree.css
  10. +0 −3 cms/static/cms/css/cms.welcome.css
  11. BIN cms/static/cms/fonts/{ → 3.3.0}/django-cms-iconfont.eot
  12. 0 cms/static/cms/fonts/{ → 3.3.0}/django-cms-iconfont.svg
  13. BIN cms/static/cms/fonts/{ → 3.3.0}/django-cms-iconfont.ttf
  14. BIN cms/static/cms/fonts/{ → 3.3.0}/django-cms-iconfont.woff
  15. BIN cms/static/cms/fonts/3.3.0/django-cms-iconfont.woff2
  16. BIN cms/static/cms/fonts/django-cms-iconfont.woff2
  17. 0 cms/static/cms/js/dist/{ → 3.3.0}/bundle.admin.base.min.js
  18. 0 cms/static/cms/js/dist/{ → 3.3.0}/bundle.admin.changeform.min.js
  19. 0 cms/static/cms/js/dist/{ → 3.3.0}/bundle.admin.pagetree.min.js
  20. 0 cms/static/cms/js/dist/{ → 3.3.0}/bundle.toolbar.min.js
  21. +2 −2 cms/static/cms/sass/components/_content.scss
  22. +6 −6 cms/static/cms/sass/components/_iconography.scss
  23. +2 −2 cms/static/cms/sass/components/_loader.scss
  24. +2 −2 cms/static/cms/sass/components/pagetree/_tree.scss
  25. +6 −6 cms/static/cms/sass/libs/_iconfont.scss
  26. +1 −1 cms/templates/admin/cms/page/change_form.html
  27. +5 −1 cms/tests/frontend/karma.conf.js
  28. +1 −1 cms/tests/test_templatetags.py
  29. +6 −1 cms/utils/urlutils.py
  30. +0 −2 cms/wizards/forms.py
  31. +5 −23 gulpfile.js
  32. +2 −1 webpack.config.js
View
@@ -5,6 +5,8 @@
tags and JavaScript is used to add event handlers and plugin data directly to
the plugin markup. This fixes most of the rendering issues that were present
because of the extra markup.
+* Changed cache-busting implementation, it is now handled by a path change,
+ not by GET parameter.
=== 3.3.1 (unreleased) ===
View
@@ -5,8 +5,10 @@
- Build newest english JS translations (django-admin.py makemessages -l en -d djangojs)
- Pull translations (tx pull -f -a)
- Compile translations (django-admin.py compilemessages)
-- Make sure css files are compiled from latest sass source (gulp sass)
-- Make sure js files are bundled and minified propery from latest source (gulp bundle)
+- Make sure icons are recreated in the new place (gulp icons)
+- Make sure CSS files are compiled from latest sass source (gulp sass)
+- Make sure JS files are bundled and minified propery from latest source (gulp bundle)
+- Make sure to remove JS, CSS and font files from the older version of CMS
- Check CHANGELOG that all closed PRs are present.
- Prepare blog post, including "Release" tag
- update AUTHORS file (python develop.py authors)
@@ -21,7 +21,6 @@
from cms.utils import permissions
from cms.utils.compat.dj import is_installed
from cms.utils.conf import get_cms_setting
-from cms.utils.urlutils import static_with_version
try:
# djangocms_text_ckeditor is not guaranteed to be available
@@ -86,8 +85,6 @@ class Media:
'cms/js/widgets/wizard.pagetypeselect.js',
)
- js = tuple(map(static_with_version, js))
-
class BaseCMSPageForm(forms.Form):
page = None
Oops, something went wrong.
Oops, something went wrong.
@@ -0,0 +1,3 @@
+/*!
+ * @copyright: https://github.com/divio/django-cms
+ */@font-face{font-family:django-cms-iconfont;src:url(../../fonts/3.3.0/django-cms-iconfont.eot);src:url(../../fonts/3.3.0/django-cms-iconfont.eot#iefix) format("eot"),url(../../fonts/3.3.0/django-cms-iconfont.woff2) format("woff2"),url(../../fonts/3.3.0/django-cms-iconfont.woff) format("woff"),url(../../fonts/3.3.0/django-cms-iconfont.ttf) format("truetype"),url(../../fonts/3.3.0/django-cms-iconfont.svg#django-cms-iconfont) format("svg");font-weight:400;font-style:normal}.cms-icon,.cms-welcome .cms-welcome-logo,.cms-welcome .cms-welcome-logo:hover{display:inline-block;font:normal normal normal 16px/1 django-cms-iconfont;text-rendering:auto;-webkit-transform:translate(0,0);transform:translate(0,0);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.cms-icon-alias:before{content:"\E001"}.cms-icon-arrow-right:before{content:"\E002"}.cms-icon-arrow-wide:before{content:"\E003"}.cms-icon-arrow:before{content:"\E004"}.cms-icon-bin:before{content:"\E005"}.cms-icon-check-o:before{content:"\E006"}.cms-icon-check-square:before{content:"\E007"}.cms-icon-check:before{content:"\E008"}.cms-icon-close:before{content:"\E009"}.cms-icon-cogs:before{content:"\E00A"}.cms-icon-copy:before{content:"\E00B"}.cms-icon-eye:before{content:"\E00C"}.cms-icon-forbidden:before{content:"\E00D"}.cms-icon-handler:before{content:"\E00E"}.cms-icon-home:before{content:"\E00F"}.cms-icon-info:before{content:"\E010"}.cms-icon-loader:before{content:"\E011"}.cms-icon-lock:before{content:"\E012"}.cms-icon-logo:before{content:"\E013"}.cms-icon-menu:before{content:"\E014"}.cms-icon-minimize:before{content:"\E015"}.cms-icon-minus-square-o:before{content:"\E016"}.cms-icon-minus-square:before{content:"\E017"}.cms-icon-minus:before{content:"\E018"}.cms-icon-paste:before{content:"\E019"}.cms-icon-pencil:before{content:"\E01A"}.cms-icon-pin:before{content:"\E01B"}.cms-icon-plus-square-o:before{content:"\E01C"}.cms-icon-plus:before{content:"\E01D"}.cms-icon-puzzle:before{content:"\E01E"}.cms-icon-scissors:before{content:"\E01F"}.cms-icon-search:before{content:"\E020"}.cms-icon-sitemap:before{content:"\E021"}.cms-icon-squares:before{content:"\E022"}.cms-icon-window:before{content:"\E023"}.cms-welcome-bg{background:#f2f2f2}.cms-welcome{color:#454545;width:60%;min-width:320px;margin:0 auto}.cms-welcome a{color:#0bf}.cms-welcome a:active,.cms-welcome a:focus,.cms-welcome a:hover{text-decoration:underline}.cms-welcome .cms-hidden{display:none}.cms-welcome .cms-welcome-footer,.cms-welcome .cms-welcome-section{box-sizing:border-box;width:60%;min-width:320px;margin:0 auto}.cms-welcome .cms-welcome-header{text-align:center}.cms-welcome .cms-welcome-heading{color:#999;font-size:22px;font-weight:200;text-align:center;padding:40px 0 15px;border-bottom:1px solid #ddd}.cms-welcome .cms-welcome-heading .cms-icon{color:#693}.cms-welcome .cms-welcome-logo,.cms-welcome .cms-welcome-logo:hover{font-size:35px;text-decoration:none;margin:50px auto 30px;color:#666}.cms-welcome .cms-welcome-logo:before,.cms-welcome .cms-welcome-logo:hover:before{content:"\E013";color:#000;-webkit-transition:color .2s;transition:color .2s}.cms-welcome .cms-welcome-logo:hover:before,.cms-welcome .cms-welcome-logo:hover:hover:before{color:#0bf}.cms-welcome .cms-welcome-section{box-shadow:0 0 5px #ddd;padding:20px;margin-bottom:5px;background:#fff}.cms-welcome .cms-welcome-section h2{font-size:16px;font-weight:700;margin:0 0 15px}.cms-welcome .cms-welcome-section p{padding:5px 0}.cms-welcome .cms-welcome-links{padding:10px 5px;margin:0 0 15px;border-bottom:1px solid #ddd}.cms-welcome .cms-welcome-links a{padding:0 5px}.cms-welcome .cms-welcome-notes{font-size:12px;line-height:16px;color:#999;padding:5px 10px}
Oops, something went wrong.
Oops, something went wrong.
@@ -1,3 +0,0 @@
-/*!
- * @copyright: https://github.com/divio/django-cms
- */@font-face{font-family:django-cms-iconfont;src:url(../fonts/django-cms-iconfont.eot?v=3.3.0);src:url(../fonts/django-cms-iconfont.eot?v=3.3.0#iefix) format("eot"),url(../fonts/django-cms-iconfont.woff2?v=3.3.0) format("woff2"),url(../fonts/django-cms-iconfont.woff?v=3.3.0) format("woff"),url(../fonts/django-cms-iconfont.ttf?v=3.3.0) format("truetype"),url(../fonts/django-cms-iconfont.svg?v=3.3.0#django-cms-iconfont) format("svg");font-weight:400;font-style:normal}.cms-icon,.cms-welcome .cms-welcome-logo,.cms-welcome .cms-welcome-logo:hover{display:inline-block;font:normal normal normal 16px/1 django-cms-iconfont;text-rendering:auto;-webkit-transform:translate(0,0);transform:translate(0,0);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.cms-icon-alias:before{content:"\E001"}.cms-icon-arrow-right:before{content:"\E002"}.cms-icon-arrow-wide:before{content:"\E003"}.cms-icon-arrow:before{content:"\E004"}.cms-icon-bin:before{content:"\E005"}.cms-icon-check-o:before{content:"\E006"}.cms-icon-check-square:before{content:"\E007"}.cms-icon-check:before{content:"\E008"}.cms-icon-close:before{content:"\E009"}.cms-icon-cogs:before{content:"\E00A"}.cms-icon-copy:before{content:"\E00B"}.cms-icon-eye:before{content:"\E00C"}.cms-icon-forbidden:before{content:"\E00D"}.cms-icon-handler:before{content:"\E00E"}.cms-icon-home:before{content:"\E00F"}.cms-icon-info:before{content:"\E010"}.cms-icon-loader:before{content:"\E011"}.cms-icon-lock:before{content:"\E012"}.cms-icon-logo:before{content:"\E013"}.cms-icon-menu:before{content:"\E014"}.cms-icon-minimize:before{content:"\E015"}.cms-icon-minus-square-o:before{content:"\E016"}.cms-icon-minus-square:before{content:"\E017"}.cms-icon-minus:before{content:"\E018"}.cms-icon-paste:before{content:"\E019"}.cms-icon-pencil:before{content:"\E01A"}.cms-icon-pin:before{content:"\E01B"}.cms-icon-plus-square-o:before{content:"\E01C"}.cms-icon-plus:before{content:"\E01D"}.cms-icon-puzzle:before{content:"\E01E"}.cms-icon-scissors:before{content:"\E01F"}.cms-icon-search:before{content:"\E020"}.cms-icon-sitemap:before{content:"\E021"}.cms-icon-squares:before{content:"\E022"}.cms-icon-window:before{content:"\E023"}.cms-welcome-bg{background:#f2f2f2}.cms-welcome{color:#454545;width:60%;min-width:320px;margin:0 auto}.cms-welcome a{color:#0bf}.cms-welcome a:active,.cms-welcome a:focus,.cms-welcome a:hover{text-decoration:underline}.cms-welcome .cms-hidden{display:none}.cms-welcome .cms-welcome-footer,.cms-welcome .cms-welcome-section{box-sizing:border-box;width:60%;min-width:320px;margin:0 auto}.cms-welcome .cms-welcome-header{text-align:center}.cms-welcome .cms-welcome-heading{color:#999;font-size:22px;font-weight:200;text-align:center;padding:40px 0 15px;border-bottom:1px solid #ddd}.cms-welcome .cms-welcome-heading .cms-icon{color:#693}.cms-welcome .cms-welcome-logo,.cms-welcome .cms-welcome-logo:hover{font-size:35px;text-decoration:none;margin:50px auto 30px;color:#666}.cms-welcome .cms-welcome-logo:before,.cms-welcome .cms-welcome-logo:hover:before{content:"\E013";color:#000;-webkit-transition:color .2s;transition:color .2s}.cms-welcome .cms-welcome-logo:hover:before,.cms-welcome .cms-welcome-logo:hover:hover:before{color:#0bf}.cms-welcome .cms-welcome-section{box-shadow:0 0 5px #ddd;padding:20px;margin-bottom:5px;background:#fff}.cms-welcome .cms-welcome-section h2{font-size:16px;font-weight:700;margin:0 0 15px}.cms-welcome .cms-welcome-section p{padding:5px 0}.cms-welcome .cms-welcome-links{padding:10px 5px;margin:0 0 15px;border-bottom:1px solid #ddd}.cms-welcome .cms-welcome-links a{padding:0 5px}.cms-welcome .cms-welcome-notes{font-size:12px;line-height:16px;color:#999;padding:5px 10px}
Binary file not shown.
Binary file not shown.
@@ -24,7 +24,7 @@ cms-plugin.cms-plugin-text-node {
max-width: none;
margin: 0 !important;
padding: 0 !important;
- background: url("../img/toolbar/render_model_icon.png") no-repeat;
+ background: url("../../img/toolbar/render_model_icon.png") no-repeat;
}
}
@@ -41,6 +41,6 @@ cms-plugin.cms-plugin-text-node {
max-width: none;
margin: 0 !important;
padding: 0 !important;
- background: url("../img/toolbar/render_model_add.png") no-repeat;
+ background: url("../../img/toolbar/render_model_add.png") no-repeat;
}
}
@@ -4,12 +4,12 @@
// default font file generated by gulp
@font-face {
font-family: "django-cms-iconfont";
- src: url("../fonts/django-cms-iconfont.eot?v=__VERSION__");
- src: url("../fonts/django-cms-iconfont.eot?v=__VERSION__#iefix") format("eot"),
- url("../fonts/django-cms-iconfont.woff2?v=__VERSION__") format("woff2"),
- url("../fonts/django-cms-iconfont.woff?v=__VERSION__") format("woff"),
- url("../fonts/django-cms-iconfont.ttf?v=__VERSION__") format("truetype"),
- url("../fonts/django-cms-iconfont.svg?v=__VERSION__#django-cms-iconfont") format("svg");
+ src: url("../../fonts/3.3.0/django-cms-iconfont.eot");
+ src: url("../../fonts/3.3.0/django-cms-iconfont.eot#iefix") format("eot"),
+ url("../../fonts/3.3.0/django-cms-iconfont.woff2") format("woff2"),
+ url("../../fonts/3.3.0/django-cms-iconfont.woff") format("woff"),
+ url("../../fonts/3.3.0/django-cms-iconfont.ttf") format("truetype"),
+ url("../../fonts/3.3.0/django-cms-iconfont.svg#django-cms-iconfont") format("svg");
font-weight: normal;
font-style: normal;
}
@@ -2,9 +2,9 @@
// LOADER
.cms-loader {
- background: $loader-bgcolor url("../img/loader.gif?uf5b664wnc") no-repeat center center !important;
+ background: $loader-bgcolor url("../../img/loader.gif?uf5b664wnc") no-repeat center center !important;
@include print-and-retina() {
- background-image: url("../img/loader@2x.gif?uf5b664wnc") !important;
+ background-image: url("../../img/loader@2x.gif?uf5b664wnc") !important;
background-size: 32px !important;
}
}
@@ -798,7 +798,7 @@
margin-top: -1px;
border: 1px solid $gray-lighter;
border-right: none;
- background: $white url('../img/pagetree/tree-li-drag.gif') no-repeat -1px center;
+ background: $white url('../../img/pagetree/tree-li-drag.gif') no-repeat -1px center;
image-rendering: pixelated;
&:hover {
@@ -906,7 +906,7 @@
height: $pagetree-cell-height;
padding: $pagetree-anchor-padding !important;
margin-left: -$pagetree-marker-size + 1;
- background: $color-primary url('../img/pagetree/tree-li-drag.gif') no-repeat -1px center;
+ background: $color-primary url('../../img/pagetree/tree-li-drag.gif') no-repeat -1px center;
color: $white;
// copy icon triggered when pressing `CMD`
.jstree-copy {
@@ -4,12 +4,12 @@
// default font file generated by gulp
@font-face {
font-family: "<%= fontName %>";
- src: url("<%= fontPath %><%= fontName %>.eot?v=__VERSION__");
- src: url("<%= fontPath %><%= fontName %>.eot?v=__VERSION__#iefix") format("eot"),
- url("<%= fontPath %><%= fontName %>.woff2?v=__VERSION__") format("woff2"),
- url("<%= fontPath %><%= fontName %>.woff?v=__VERSION__") format("woff"),
- url("<%= fontPath %><%= fontName %>.ttf?v=__VERSION__") format("truetype"),
- url("<%= fontPath %><%= fontName %>.svg?v=__VERSION__#<%= fontName %>") format("svg");
+ src: url("<%= fontPath %><%= fontName %>.eot");
+ src: url("<%= fontPath %><%= fontName %>.eot#iefix") format("eot"),
+ url("<%= fontPath %><%= fontName %>.woff2") format("woff2"),
+ url("<%= fontPath %><%= fontName %>.woff") format("woff"),
+ url("<%= fontPath %><%= fontName %>.ttf") format("truetype"),
+ url("<%= fontPath %><%= fontName %>.svg#<%= fontName %>") format("svg");
font-weight: normal;
font-style: normal;
}
@@ -13,7 +13,7 @@
{% endblock %}
{% block extrahead %}
-<script src="{% static_with_version "admin/js/urlify.js" %}" type="text/javascript"></script>
+<script src="{% static "admin/js/urlify.js" %}" type="text/javascript"></script>
<script src="{% static_with_version "cms/js/dist/bundle.admin.base.min.js" %}" type="text/javascript"></script>
<script src="{% static_with_version "cms/js/dist/bundle.admin.changeform.min.js" %}" type="text/javascript"></script>
<script type="text/javascript">
@@ -8,6 +8,7 @@
var baseConf = require('./base.conf');
var path = require('path');
+var fs = require('fs');
var argv = require('minimist')(process.argv.slice(2));
var webpack = require('webpack');
var webpackConfig = require('../../../webpack.config.js')({
@@ -42,6 +43,9 @@ webpackConfig.plugins = [
})
];
+var CMS_VERSION = fs.readFileSync('cms/__init__.py', { encoding: 'utf-8' })
+ .match(/__version__ = '(.*?)'/)[1];
+
module.exports = function (config) {
var useSauceLabs = function () {
var val = process.env.USE_SAUCE_LABS;
@@ -62,7 +66,7 @@ module.exports = function (config) {
// list of files / patterns to load in the browser
files: [
- 'cms/static/cms/css/cms.base.css',
+ 'cms/static/cms/css/' + CMS_VERSION + '/cms.base.css',
// fixtures
'cms/tests/frontend/unit/fixtures/**/*.html',
@@ -82,7 +82,7 @@ def test_json_encoder(self):
self.assertEqual('"%s"' % today.isoformat()[:-3], json_filter(today))
def test_static_with_version(self):
- expected = '<script src="/static/cms/css/cms.base.css?%(version)s" type="text/javascript"></script>'
+ expected = '<script src="/static/cms/css/%(version)s/cms.base.css" type="text/javascript"></script>'
expected = expected % {'version': cms.__version__}
template = (
@@ -61,7 +61,12 @@ def is_media_request(request):
def static_with_version(path):
- return '%s?%s' % (path, cms.__version__)
+ """
+ Changes provided path from `path/to/filename.ext` to `path/to/$CMS_VERSION/filename.ext`
+ """
+ path_re = re.compile('(.*)/([^/]*$)')
+
+ return re.sub(path_re, r'\1/%s/\2' % (cms.__version__), path)
def add_url_parameters(url, *args, **params):
@@ -56,8 +56,6 @@ class Media:
'cms/js/modules/cms.wizards.js',
)
- js = tuple(map(static_with_version, js))
-
page = forms.ModelChoiceField(
queryset=Page.objects.all(),
required=False,
View
@@ -107,22 +107,6 @@ var CMS_VERSION = fs.readFileSync('cms/__init__.py', { encoding: 'utf-8' })
// #####################################################################################################################
// #TASKS#
-/**
- * @function cacheBuster
- * @param {Object} opts
- * @param {String} [opts.version]
- * @returns {Function}
- */
-var cacheBuster = function (opts) {
- var version = opts && opts.version ? opts.version : Math.random();
-
- return function (css) {
- css.replaceValues(/__VERSION__/g, { fast: '__VERSION__' }, function () {
- return version;
- });
- };
-};
-
gulp.task('sass', function () {
gulp.src(PROJECT_PATTERNS.sass)
.pipe(gulpif(options.debug, sourcemaps.init()))
@@ -133,25 +117,22 @@ gulp.task('sass', function () {
.pipe(postcss([
autoprefixer({
cascade: false
- }),
- cacheBuster({
- version: CMS_VERSION
})
]))
.pipe(minifyCss({
rebase: false
}))
.pipe(gulpif(options.debug, sourcemaps.write()))
- .pipe(gulp.dest(PROJECT_PATH.css));
+ .pipe(gulp.dest(PROJECT_PATH.css + '/' + CMS_VERSION + '/'));
});
gulp.task('icons', function () {
gulp.src(PROJECT_PATTERNS.icons)
.pipe(iconfontCss({
fontName: 'django-cms-iconfont',
- fontPath: '../fonts/',
+ fontPath: '../../fonts/' + CMS_VERSION + '/',
path: PROJECT_PATH.sass + '/libs/_iconfont.scss',
- targetPath: '../sass/components/_iconography.scss'
+ targetPath: '../../sass/components/_iconography.scss'
}))
.pipe(iconfont({
fontName: 'django-cms-iconfont',
@@ -160,7 +141,7 @@ gulp.task('icons', function () {
.on('glyphs', function (glyphs, opts) {
gutil.log.bind(glyphs, opts);
})
- .pipe(gulp.dest(PROJECT_PATH.icons));
+ .pipe(gulp.dest(PROJECT_PATH.icons + '/' + CMS_VERSION + '/'));
});
gulp.task('lint', ['lint:javascript']);
@@ -207,6 +188,7 @@ var webpackBundle = function (opts) {
webpackOptions.PROJECT_PATH = PROJECT_PATH;
webpackOptions.debug = options.debug;
+ webpackOptions.CMS_VERSION = CMS_VERSION;
return function (done) {
var config = require('./webpack.config')(webpackOptions);
View
@@ -4,6 +4,7 @@ module.exports = function (opts) {
'use strict';
var PROJECT_PATH = opts.PROJECT_PATH;
+ var CMS_VERSION = opts.CMS_VERSION;
var debug = opts.debug;
var baseConfig = {
@@ -16,7 +17,7 @@ module.exports = function (opts) {
'admin.changeform': PROJECT_PATH.js + '/admin.changeform.js'
},
output: {
- path: PROJECT_PATH.js + '/dist/',
+ path: PROJECT_PATH.js + '/dist/' + CMS_VERSION + '/',
filename: 'bundle.[name].min.js',
jsonpFunction: 'cmsWebpackJsonp'
},

0 comments on commit 6c41c31

Please sign in to comment.