├── .editorconfig
├── .gitignore
├── .jshintrc
├── .travis.yml
├── Gruntfile.js
├── LICENSE-MIT
├── README.md
├── changelog.md
├── config
├── complex.js
├── createCopies.js
├── deleteOriginals.js
├── hash.js
├── ignorePattern.js
├── imgsrcset.js
├── jsonOutput.js
├── outputDir.js
├── queryString.js
├── realpath.js
├── relativepath.js
├── relativepath2.js
├── scripts.js
├── sourceBusted.js
├── sourceBusted2.js
├── sourceBusted3.js
├── standard.js
├── stylesheets.js
├── templates.js
├── urlPrefixes.js
└── xml.js
├── license
├── package-lock.json
├── package.json
├── tasks
└── cachebust.js
└── tests
├── absolutepath
├── absolutepath.html
├── absolutepath_test.js
└── assets
│ ├── css
│ └── application.css
│ └── images
│ └── testbg.png
├── complex
├── complex.html
├── complex_test.js
├── css
│ └── complex.css
└── imgs
│ └── complex-background.jpg
├── createCopies
├── assets
│ ├── .htaccess
│ └── dontCopy.png
└── createCopies.html
├── deleteOriginals
├── assets
│ ├── delete.css
│ ├── delete.js
│ └── delete.png
├── deleteOriginalSameAssets.html
└── deleteOriginals.html
├── hash
├── assets
│ ├── hash.css
│ ├── hash.jpg
│ └── hash.js
├── hash.html
└── hash_test.js
├── ignorePattern
├── assets
│ ├── toBeIgnoredCSS.css
│ ├── toBeIgnoredJPG.jpg
│ └── toBeIgnoredJS.js
├── ignorePattern.html
└── ignorePattern_test.js
├── imgsrcset
├── assets
│ ├── imgsrcset-big.jpg
│ ├── imgsrcset-small.jpg
│ └── imgsrcset.jpg
├── imgsrcset.html
└── imgsrcset_test.js
├── jsonOutput
├── assets
│ └── jsonOutput.js
├── jsonOutput.html
└── jsonOutput_test.js
├── outputDir
├── assets
│ ├── outputDir.css
│ ├── outputDir.js
│ └── outputDir.png
├── outputDir.html
└── outputDir_test.js
├── queryString
├── css
│ └── test.css
├── imgs
│ └── background.jpg
├── queryString.html
└── queryString_test.js
├── realpath
├── css
│ └── app.css
├── lib
│ └── css
│ │ └── app.css
├── realpath.html
└── realpath_test.js
├── relativepath
├── assets
│ ├── css
│ │ └── application.css
│ └── images
│ │ └── testbg.png
├── relativepath.html
└── relativepath_test.js
├── relativepath2
├── assets
│ ├── css
│ │ └── application.css
│ └── images
│ │ └── testbg.png
├── relativepath2.html
└── relativepath2_test.js
├── scripts
├── assets
│ └── script.js
├── scripts.js
└── scripts_test.js
├── sourceBusted
├── assets
│ ├── css
│ │ └── application.css
│ └── images
│ │ └── testbg.png
├── sourceBusted.html
└── sourceBusted_test.js
├── sourceBusted2
├── assets
│ ├── css
│ │ └── application.css
│ └── images
│ │ └── testbg.png
├── sourceBusted2.html
└── sourceBusted2_test.js
├── sourceBusted3
├── assets
│ ├── css
│ │ └── application.css
│ └── images
│ │ └── testbg.png
├── sourceBusted3.html
└── sourceBusted3_test.js
├── standard
├── assets
│ ├── standard-apple-touch-icon.jpg
│ ├── standard.css
│ ├── standard.jpg
│ └── standard.js
├── standard.html
├── standard_test.js
└── subfolder
│ └── relative-standard.html
├── stylesheets
├── assets
│ ├── css-image-large.jpg
│ ├── css-image-quotes.jpg
│ ├── css-image.jpg
│ ├── fonts
│ │ ├── icons.eot
│ │ ├── icons.ttf
│ │ ├── icons.woff
│ │ └── icons.woff2
│ ├── image1.jpg
│ ├── image2.jpg
│ ├── relative-css-image-large.jpg
│ ├── relative-css-image-quotes.jpg
│ ├── relative-css-image.jpg
│ ├── relative-image1.jpg
│ ├── stylesheet1.css
│ ├── stylesheet2.css
│ ├── stylesheet3.css
│ └── stylesheet4.css
├── css
│ └── replaceCssInSubdir.css
├── stylesheet.css
└── stylesheet_test.js
├── templates
├── base.html
├── templates_test.js
└── views
│ ├── view-a.html
│ └── view-b.html
├── urlPrefixes
├── assets
│ ├── imgsrcset-big.jpg
│ ├── imgsrcset-small.jpg
│ └── imgsrcset.jpg
├── css
│ └── app.css
├── urlPrefixes.html
└── urlPrefixes_test.js
└── xml
├── assets
├── mstile-150x150.png
├── mstile-310x150.png
├── mstile-310x310.png
└── mstile-70x70.png
├── xml.xml
└── xml_test.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 | word_wrap = true
12 | wrap_width = 120
13 |
14 | [*.md]
15 | trim_trailing_whitespace = false
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | tmp
4 | .DS_STORE
5 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "curly": true,
3 | "eqeqeq": true,
4 | "immed": true,
5 | "latedef": false,
6 | "newcap": true,
7 | "noarg": true,
8 | "sub": true,
9 | "undef": true,
10 | "boss": true,
11 | "eqnull": true,
12 | "node": true
13 | }
14 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | node_js:
4 | - "10"
5 | - "8"
6 | - "6"
7 | before_script:
8 | - npm install -g grunt-cli
9 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | 'use strict';
3 |
4 | var configFiles = grunt.file.expand('./config/*.js');
5 |
6 | // Default cacheBust options
7 | var cacheBustObj = {
8 | options: {
9 | encoding: 'utf8',
10 | length: 16,
11 | algorithm: 'md5'
12 | }
13 | };
14 |
15 | // Load each cacheBust config
16 | configFiles.forEach(function(filename) {
17 | var taskName = filename.replace('./config/', '').replace('.js', '');
18 | cacheBustObj[taskName] = require(filename);
19 | });
20 |
21 | grunt.initConfig({
22 |
23 | clean: {
24 | tmp: 'tmp'
25 | },
26 |
27 | jshint: {
28 | all: [
29 | 'Gruntfile.js',
30 | 'tasks/**/*.js',
31 | '<%= nodeunit.tests %>'
32 | ],
33 | options: {
34 | jshintrc: '.jshintrc'
35 | }
36 | },
37 |
38 | copy: {
39 | main: {
40 | files: [{
41 | expand: true,
42 | dot: true,
43 | cwd: 'tests/',
44 | src: ['**', '!**/*_test.js'],
45 | dest: 'tmp/'
46 | }]
47 | }
48 | },
49 |
50 | cacheBust: cacheBustObj,
51 |
52 | nodeunit: {
53 | tests: ['tests/**/*_test.js']
54 | },
55 |
56 | watch: {
57 | task: {
58 | files: ['tasks/**/*.js', 'tests/**/*', 'config/*.js'],
59 | tasks: 'test'
60 | }
61 | }
62 |
63 | });
64 |
65 | // Load this plugins tasks
66 | grunt.loadTasks('tasks');
67 |
68 | grunt.loadNpmTasks('grunt-contrib-jshint');
69 | grunt.loadNpmTasks('grunt-contrib-copy');
70 | grunt.loadNpmTasks('grunt-contrib-clean');
71 | grunt.loadNpmTasks('grunt-contrib-nodeunit');
72 | grunt.loadNpmTasks('grunt-contrib-watch');
73 |
74 | grunt.registerTask('default', 'bust');
75 | grunt.registerTask('test', ['bust', 'nodeunit']);
76 | grunt.registerTask('bust', ['jshint', 'clean', 'copy', 'cacheBust']);
77 | };
78 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Ben Holland
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # grunt-cache-bust
2 |
3 | [](http://badge.fury.io/js/grunt-cache-bust)
4 | [](https://travis-ci.org/hollandben/grunt-cache-bust)
5 | [](https://david-dm.org/hollandben/grunt-cache-bust)
6 | [](https://gitter.im/hollandben/grunt-cache-bust?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
7 |
8 | > Bust static assets from the cache using content hashing
9 |
10 | * [Getting Started](#getting-started)
11 | * [Introduction](#the-cachebust-task)
12 | * [How it works](#how-it-works)
13 | * [Options](#options)
14 | * [Usage Examples](#usage-examples)
15 | * [CDNs](#cdns)
16 | * [Change Log](#change-log)
17 |
18 | ## PLEASE READ
19 | This plugin recently upgraded to `v1.0.0`!! There was a big change in the way the plugin works. You can read me about the changes in issue [#147](https://github.com/hollandben/grunt-cache-bust/issues/147).
20 |
21 | ## Getting Started
22 | _If you haven't used [grunt][] before, be sure to check out the [Getting Started][] guide._
23 |
24 | From the same directory as your project's [Gruntfile][Getting Started] and [package.json][], install this plugin with the following command:
25 |
26 | ```bash
27 | npm install grunt-cache-bust --save-dev
28 | ```
29 |
30 | Once the plugin has been installed, enabled it inside your Gruntfile.
31 |
32 | ```bash
33 | grunt.loadNpmTasks('grunt-cache-bust');
34 | ```
35 |
36 | [grunt]: http://gruntjs.com/
37 | [Getting Started]: https://github.com/gruntjs/grunt/blob/devel/docs/getting_started.md
38 | [package.json]: https://npmjs.org/doc/json.html
39 |
40 | ## The "cacheBust" task
41 |
42 | Use the `cacheBust` task for cache busting static files in your application. This allows the assets to have a large expiry time in the browsers cache and will only be forced to use an updated file when the contents of it changes. This is a good practice.
43 |
44 | Tell the `cacheBust` task where your static assets are and the files that reference them and let it work it's magic.
45 |
46 | ### Supported file types
47 | All of them!!
48 |
49 | ### How it works
50 | In your project's Gruntfile, add a new task called `cacheBust`.
51 |
52 | This is the most basic configuration you can have:
53 |
54 | ```js
55 | cacheBust: {
56 | taskName: {
57 | options: {
58 | assets: ['assets/**']
59 | },
60 | src: ['index.html']
61 | }
62 | }
63 | ```
64 |
65 | These are the two mandatory fields you need to supply:
66 |
67 | The `assets` option that is passed to the plugin tells it what types of files you want to hash, i.e. `css` and `js` files. You must also provide the location for these files. In the example above, they live in the `assets` folder.
68 |
69 | The `src` part of the configuration you should have seen before as it's used by pretty much every Grunt plugin. We use this to tell the plugin which files contain references to assets we're going to be adding a hash to. You can [use the `expand` configuration option here as well](http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically)
70 |
71 | **To summarise, the above configuration will hash all the files in the `assets` directory and replace any references to those files in the `index.html` file.**
72 |
73 | ### Options
74 |
75 | #### Summary
76 |
77 | ```
78 | // Here is a short summary of the options and some of their
79 | defaults. Extra details are below.
80 | {
81 | algorithm: 'md5', // Algorithm used for hashing files
82 | assets: ['css/*', 'js/*'] // File patterns for the assets you wish to hash
83 | baseDir: './', // The base directory for all assets
84 | createCopies: true, // Create hashed copies of files
85 | deleteOriginals: false, // Delete the original file after hashing
86 | encoding: 'utf8', // The encoding used when reading/writing files
87 | hash: '9ef00db36970718e', // A user defined hash for every file. Not recommended.
88 | jsonOutput: false, // Output the original => new URLs to a JSON file
89 | jsonOutputFilename: 'grunt-cache-bust.json', // The file path and name of the exported JSON. Is relative to baseDir
90 | length: 16, // The length of the hash value
91 | separator: '.', // The separator between the original file name and hash
92 | queryString: false // Use a query string for cache busting instead of rewriting files
93 | outputDir: '' // Directory where all hashed assets will be copied. Is relative to baseDir
94 | clearOutputDir: false, // Clear output directory. If outputDir was not set clear will not work
95 | urlPrefixes: ['http://owncdn.test.com/path'] // Array of Url + Path of own CDNs where hashed files are uploaded to.
96 | }
97 | ```
98 |
99 | #### options.algorithm
100 | Type: `String`
101 | Default value: `'md5'`
102 |
103 | `algorithm` is dependent on the available algorithms supported by the version of OpenSSL on the platform. Examples are `'sha1'`, `'md5'`, `'sha256'`, `'sha512'`
104 |
105 | #### options.assets
106 | Type: `Array`
107 |
108 | `assets` contains the file patterns for where all your assets live. This should point towards all the assets you wish to have busted. It uses the same glob pattern for matching files as Grunt.
109 |
110 |
111 | #### options.baseDir
112 | Type: `String`
113 | Default value: `false`
114 |
115 | When set, `cachebust` will try to find the assets using the baseDir as base path.
116 |
117 | ```js
118 | assets: {
119 | options: {
120 | baseDir: 'public/',
121 | },
122 | files: [{
123 | expand: true,
124 | cwd: 'public/',
125 | src: ['modules/**/*.html']
126 | }]
127 | }
128 | ```
129 | #### options.urlPrefixes
130 | Type: `Array of Strings`
131 | Default value: ``
132 |
133 | When set, `cachebust` will try to find the assets with this prefixes, useful for:
134 | - Asset files uploaded to a separate cdn
135 | - Asset files which are served out of a deeper path within your deployment
136 |
137 | For example:
138 |
139 | ```js
140 | cacheBust: {
141 | options: {
142 | urlPrefixes: ['/dashboard/app/app.min.js']
143 | }
144 | }
145 | ```
146 |
147 | will convert:
148 |
149 | ```html
150 |
151 | ```
152 |
153 | into
154 |
155 | ```html
156 |
157 | ```
158 |
159 | #### options.createCopies
160 | Type: `Boolean`
161 | Default value: `true`
162 |
163 | When set to `false`, `cachebust` will not create hashed copies of the files. Useful if you use server rewrites to serve your files.
164 |
165 | #### options.deleteOriginals
166 | Type: `Boolean`
167 | Default value: `false`
168 |
169 | When set, `cachebust` will delete the original versions of the files that have been hashed. For example, `style.css` will be deleted after being copied to `style.dcf1d324cb50a1f9.css`.
170 |
171 | #### options.encoding
172 | Type: `String`
173 | Default value: `'utf8'`
174 |
175 | The encoding of the file contents.
176 |
177 | #### options.hash
178 | Type: `String`
179 |
180 | A user defined value to be used as the hash value for all files. For a more beneficial caching strategy, it's advised not to supply a hash value for all files.
181 |
182 | #### options.jsonOutput
183 | Type: `Boolean`
184 | Default value: `false`
185 |
186 | When set as `true`, `cachbust` will create a json file with an object inside that contains key value pairs of the original file name, and the renamed md5 hash name for each file.
187 |
188 | Output format looks like this:
189 | ```
190 | {
191 | '/scripts/app.js' : '/scripts/app.23e6f7ac5623e96f.js',
192 | '/scripts/vendor.js': '/scripts/vendor.h421fwaj124bfaf5.js'
193 | }
194 | ```
195 |
196 | #### options.jsonOutputFilename
197 | Type: `String`
198 | Default value: `grunt-cache-bust.json`
199 |
200 | The file path and name of the exported JSON. It is exported relative to `baseDir`.
201 |
202 | #### options.length
203 | Type: `Number`
204 | Default value: `16`
205 |
206 | The number of characters of the file content hash to prefix the file name with.
207 |
208 | #### options.separator
209 | Type: `String`
210 | Default value: `.`
211 |
212 | The separator between the original file name and hash.
213 |
214 | #### options.queryString
215 | Type: `Boolean`
216 | Default value: `false`
217 |
218 | Use a query string for cache busting instead of rewriting files.
219 |
220 | ### Usage Examples
221 |
222 | #### The most basic setup
223 | ```js
224 | cacheBust: {
225 | taskName: {
226 | options: {
227 | assets: ['assets/**']
228 | },
229 | src: ['index.html']
230 | }
231 | }
232 | ```
233 |
234 | #### Bust using a query string instead of rewriting files
235 | ```js
236 | cacheBust: {
237 | taskName: {
238 | options: {
239 | assets: ['assets/**'],
240 | queryString: true
241 | },
242 | src: ['index.html']
243 | }
244 | }
245 | ```
246 |
247 | #### Bust all assets and update references in all templates and assets
248 | ```js
249 | cacheBust: {
250 | options: {
251 | assets: ['assets/**/*'],
252 | baseDir: './public/'
253 | },
254 | taskName: {
255 | files: [{
256 | expand: true,
257 | cwd: 'public/',
258 | src: ['templates/**/*.html', 'assets/**/*']
259 | }]
260 | }
261 | }
262 | ```
263 |
264 | #### Inherited options for multiple tasks
265 | ```js
266 | cacheBust: {
267 | options: {
268 | assets: ['assets/**'],
269 | baseDir: './public/'
270 | },
271 | staging: {
272 | options: {
273 | jsonOutput: true
274 | },
275 | src: ['index.html']
276 | },
277 | production: {
278 | options: {
279 | jsonOutput: false
280 | },
281 | src: ['index.html']
282 | }
283 | }
284 | ```
285 |
286 | # License
287 |
288 | MIT © [Ben Holland](https://benholland.me)
289 |
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | Change Log
2 | ==========
3 |
4 | **v1.7.0**
5 | * Add urlPrefixes option (#234)
6 |
7 | **v1.6.0**
8 | * Log out busted files in verbose mode only (#228)
9 | * Updating documentation to show the loadNpmTasks business (#231)
10 | * Fix for clearOutputDir option (#230)
11 | * Fix multiple cache bust query params being added (#227)
12 |
13 | **v1.5.1**
14 | * Fix "Warning: Cannot use 'in' operator to search" error when queryString option is passed
15 | * Fix several paths issues
16 | * Enable Busting of img srcset
17 |
18 | **v1.5.0**
19 | * Fix paths in hashed files (#211)
20 | * Files in outputDir should have files replaced (#210)
21 |
22 | **v1.4.1**
23 | * Move `fs-extra` from dev dependency to dependency
24 |
25 | **v1.4.0**
26 | * Added option `outputDir`, a directory where all hashed assets will be copied
27 |
28 | **v1.3.0**
29 | * Upgraded to `grunt@1.x.x`
30 |
31 | **v1.2.0**
32 | * Added option `queryString` to bust using a query string and keep original files intact
33 |
34 | **v1.1.0**
35 | * Added option `createCopies` to disable creating hashed copies of the files
36 |
37 | **v1.0.0**
38 | * Fundamental breaking changes - see issue [#147](https://github.com/hollandben/grunt-cache-bust/issues/147) for more details
39 | * Re-wrote the way the plugin functions. Instead of finding assets in files, the plugin now goes through a given assets folder and builds an object based on the original and hashed file name. Read more about the changes in [#147](https://github.com/hollandben/grunt-cache-bust/issues/147)
40 | * Remove string option for `jsonOutput`, enforcing the use of `jsonOutputFilename`
41 | * Sorting and reversing to collection of assets - fixes #176
42 | * Updated documentation
43 |
44 | **v0.6.1**
45 | * Support cache busting for meta tags
46 | * Support cache busting for all favicons
47 |
48 | **v0.6.0**
49 | * Support cache busting for video tag
50 | * Fix CSS processing for media queries with comments
51 | * Use passed in grunt when registering
52 |
53 | **v0.5.1**
54 | * Reading files to be hashed as a buffer rather than string
55 |
56 | **v0.5.0** - 2015-08-09
57 | * Using Node's path module to help with getting the correct paths to assets
58 |
59 | **v0.4.13** - 2015-02-27
60 | * Fixes issue with deleting the original files when referenced in more than one source file.
61 | * Fixed issue with hashe in the url of assets when referenced in CSS
62 |
63 | **v0.4.12** - 2015-02-26
64 | * Fixed tests and implementation when deleting original files.
65 |
66 | **v0.4.12** - 2015-02-25
67 | * Ignoring data-images when parsing CSS.
68 |
69 | **v0.4.12** - 2015-02-20
70 | * Added support for Windows 8.1 and IE titles browser config file.
71 |
72 | **v0.4.2** - 2015-02-19
73 | * Tidied up tests. Improved README readability.
74 |
75 | **v0.4.2** - 2015-02-18
76 | * Improved detection of remote resources
77 |
78 | **v0.4.2** - 2015-02-18
79 | * Fix for working with relative paths
80 |
81 | **v0.4.2** - 2015-02-15
82 | * Added options to remove frag hints and use a local CDN. Busting multiple values in CSS files. Bust SVG xlink:href path. Override `baseDir` on a per file basis.
83 |
--------------------------------------------------------------------------------
/config/complex.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | assets: ['**/*.{css,jpg}'],
4 | baseDir: 'tmp/complex',
5 | deleteOriginals: true,
6 | hash: '123456789'
7 | },
8 | files: [{
9 | expand: true,
10 | cwd: 'tmp/complex',
11 | src: ['css/*.css', '*.html']
12 | }]
13 | };
14 |
--------------------------------------------------------------------------------
/config/createCopies.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | baseDir: 'tmp/createCopies',
4 | createCopies: false,
5 | assets: 'assets/*'
6 | },
7 | files: [{
8 | expand: true,
9 | cwd: 'tmp/createCopies/',
10 | src: ['*.html']
11 | }]
12 | };
13 |
--------------------------------------------------------------------------------
/config/deleteOriginals.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | baseDir: 'tmp/deleteOriginals',
4 | deleteOriginals: true,
5 | assets: 'assets/*'
6 | },
7 | files: [{
8 | expand: true,
9 | cwd: 'tmp/deleteOriginals/',
10 | src: ['*.html']
11 | }]
12 | };
13 |
--------------------------------------------------------------------------------
/config/hash.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | assets: '**/*.{js,css,jpg}',
4 | baseDir: 'tmp/hash/',
5 | hash: 'abcdef123456'
6 | },
7 | src: ['tmp/hash/**/*.html']
8 | };
9 |
--------------------------------------------------------------------------------
/config/ignorePattern.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | baseDir: 'tmp/ignorePattern',
4 | assets: ['assets/*', '!assets/*.jpg']
5 | },
6 | files: [{
7 | expand: true,
8 | cwd: 'tmp/ignorePattern/',
9 | src: ['*.html']
10 | }]
11 | };
12 |
--------------------------------------------------------------------------------
/config/imgsrcset.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | assets: '**/*.jpg',
4 | baseDir: 'tmp/imgsrcset/'
5 | },
6 | src: ['tmp/imgsrcset/**/*.html']
7 | };
8 |
--------------------------------------------------------------------------------
/config/jsonOutput.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | assets: '**/*.{js,css,jpg}',
4 | baseDir: 'tmp/jsonOutput/',
5 | jsonOutput: true,
6 | jsonOutputFilename: 'jsonOutput-map.json'
7 | },
8 | src: ['tmp/jsonOutput/**/*.html']
9 | };
10 |
--------------------------------------------------------------------------------
/config/outputDir.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | baseDir: 'tmp/outputDir',
4 | outputDir: 'outputDir',
5 | assets: 'assets/*',
6 | hash: 'abcdef123456'
7 | },
8 | files: [{
9 | expand: true,
10 | cwd: 'tmp/outputDir/',
11 | src: ['outputDir.html', 'assets/outputDir.css']
12 | }]
13 | };
14 |
--------------------------------------------------------------------------------
/config/queryString.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | assets: ['**/*.{css,jpg}'],
4 | baseDir: 'tmp/queryString',
5 | queryString: true,
6 | hash: '123456789'
7 | },
8 | files: [{
9 | expand: true,
10 | cwd: 'tmp/queryString',
11 | src: ['css/*.css', '*.html']
12 | }]
13 | };
14 |
--------------------------------------------------------------------------------
/config/realpath.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | assets: ['css/*.{css,jpg}'],
4 | baseDir: 'tmp/realpath',
5 | deleteOriginals: true,
6 | hash: '123456789'
7 | },
8 | files: [{
9 | expand: true,
10 | cwd: 'tmp/realpath',
11 | src: ['css/*.css', '*.html']
12 | }]
13 | };
14 |
--------------------------------------------------------------------------------
/config/relativepath.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | assets: ['assets/**'],
4 | baseDir: 'tmp/relativepath',
5 | deleteOriginals: true,
6 | hash: '123456789',
7 | jsonOutput: true
8 | },
9 | files: [{
10 | expand: true,
11 | cwd: 'tmp/relativepath',
12 | src: ['assets/css/*.css', '*.html']
13 | }]
14 | };
15 |
--------------------------------------------------------------------------------
/config/relativepath2.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | assets: ['assets/**'],
4 | baseDir: './tmp/relativepath2/',
5 | deleteOriginals: true,
6 | hash: '123456789'
7 | },
8 | files: [{
9 | cwd: './tmp/relativepath2/',
10 | src: ['assets/css/application.css', 'relativepath2.html']
11 | }]
12 | };
13 |
--------------------------------------------------------------------------------
/config/scripts.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | baseDir: 'tmp/scripts',
4 | assets: 'assets/*'
5 | },
6 | files: [{
7 | expand: true,
8 | cwd: 'tmp/scripts/',
9 | src: ['*.js']
10 | }]
11 | };
12 |
--------------------------------------------------------------------------------
/config/sourceBusted.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | assets: ['assets/**'],
4 | baseDir: 'tmp/sourceBusted',
5 | deleteOriginals: true,
6 | hash: '123456789',
7 | },
8 | files: [{
9 | src: ['tmp/sourceBusted/assets/css/application.css', 'tmp/sourceBusted/sourceBusted.html']
10 | }]
11 | };
12 |
--------------------------------------------------------------------------------
/config/sourceBusted2.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | assets: ['assets/**'],
4 | baseDir: 'tmp/sourceBusted2',
5 | deleteOriginals: true,
6 | hash: '123456789',
7 | },
8 | files: [{
9 | cwd: './tmp/sourceBusted2/',
10 | src: ['assets/css/application.css', 'sourceBusted2.html']
11 | }]
12 | };
13 |
--------------------------------------------------------------------------------
/config/sourceBusted3.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | assets: ['assets/**'],
4 | baseDir: './tmp/sourceBusted3', // here ./tmp/
5 | deleteOriginals: true,
6 | hash: '123456789',
7 | },
8 | files: [{
9 | src: ['tmp/sourceBusted3/assets/css/application.css', 'tmp/sourceBusted3/sourceBusted3.html'] // here tmp
10 | }]
11 | };
12 |
--------------------------------------------------------------------------------
/config/standard.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | assets: '**/*.{js,css,jpg}',
4 | baseDir: 'tmp/standard/'
5 | },
6 | src: ['tmp/standard/**/*.html']
7 | };
8 |
--------------------------------------------------------------------------------
/config/stylesheets.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | baseDir: 'tmp/stylesheets',
4 | assets: 'assets/**/*'
5 | },
6 | files: [{
7 | expand: true,
8 | cwd: 'tmp/stylesheets/',
9 | src: ['**/*.css']
10 | }]
11 | };
12 |
--------------------------------------------------------------------------------
/config/templates.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | assets: 'views/*.html',
4 | baseDir: 'tmp/templates/'
5 | },
6 | src: ['tmp/templates/base.html']
7 | };
8 |
--------------------------------------------------------------------------------
/config/urlPrefixes.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | assets: ['**/*.{css,jpg}'],
4 | baseDir: 'tmp/urlPrefixes',
5 | urlPrefixes: ['http://owncdn1.test.com/path', 'http://owncdn2.test.com/path'],
6 | deleteOriginals: true,
7 | hash: '123456789'
8 | },
9 | files: [{
10 | expand: true,
11 | cwd: 'tmp/urlPrefixes',
12 | src: ['css/*.css', '*.html']
13 | }]
14 | };
15 |
--------------------------------------------------------------------------------
/config/xml.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | baseDir: 'tmp/xml',
4 | assets: 'assets/*'
5 | },
6 | files: [{
7 | expand: true,
8 | cwd: 'tmp/xml/',
9 | src: ['*.xml']
10 | }]
11 | };
12 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Ben Holland (benholland.me)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "grunt-cache-bust",
3 | "description": "Bust static assets from the cache using content hashing",
4 | "version": "1.7.0",
5 | "author": "Ben Holland ",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/hollandben/grunt-cache-bust.git"
9 | },
10 | "licenses": [
11 | {
12 | "type": "MIT",
13 | "url": "https://github.com/hollandben/grunt-cache-bust/blob/master/license"
14 | }
15 | ],
16 | "engines": {
17 | "node": ">=0.10.0"
18 | },
19 | "scripts": {
20 | "test": "grunt test"
21 | },
22 | "devDependencies": {
23 | "grunt": "^1.0.3",
24 | "grunt-contrib-clean": "^1.1.0",
25 | "grunt-contrib-copy": "^1.0.0",
26 | "grunt-contrib-jshint": "^1.1.0",
27 | "grunt-contrib-nodeunit": "^2.0.0",
28 | "grunt-contrib-watch": "^1.1.0"
29 | },
30 | "peerDependencies": {
31 | "grunt": ">=0.4.0"
32 | },
33 | "keywords": [
34 | "grunt",
35 | "grunt plugin",
36 | "cache",
37 | "bust",
38 | "bust assets"
39 | ],
40 | "dependencies": {
41 | "fs-extra": "^6.0.1"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/tasks/cachebust.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs-extra');
4 | var url = require('url');
5 | var path = require('path');
6 | var crypto = require('crypto');
7 | var _ = require('grunt').util._;
8 |
9 | var DEFAULT_OPTIONS = {
10 | algorithm: 'md5',
11 | baseDir: './',
12 | createCopies: true,
13 | deleteOriginals: false,
14 | encoding: 'utf8',
15 | jsonOutput: false,
16 | jsonOutputFilename: 'grunt-cache-bust.json',
17 | length: 16,
18 | separator: '.',
19 | queryString: false,
20 | outputDir: '',
21 | clearOutputDir: false,
22 | urlPrefixes: []
23 | };
24 |
25 | module.exports = function(grunt) {
26 | var isUsingQueryString = function(opts) {
27 | return opts.queryString;
28 | };
29 | grunt.registerMultiTask('cacheBust', 'Bust static assets from the cache using content hashing', function() {
30 | var opts = this.options(DEFAULT_OPTIONS);
31 | if( opts.baseDir.substr(-1) !== '/' ) {
32 | opts.baseDir += '/';
33 | }
34 |
35 | var discoveryOpts = {
36 | cwd: path.resolve(opts.baseDir),
37 | filter: 'isFile'
38 | };
39 |
40 | //clear output dir if it was set
41 | if (opts.clearOutputDir && opts.outputDir.length > 0) {
42 | fs.removeSync(path.resolve((discoveryOpts.cwd ? discoveryOpts.cwd + '/' +opts.outputDir : opts.outputDir)));
43 | }
44 |
45 | // Generate an asset map
46 | var assetMap = grunt.file
47 | .expand(discoveryOpts, opts.assets)
48 | .sort()
49 | .reverse()
50 | .reduce(hashFile, {});
51 |
52 | grunt.verbose.writeln('Assets found:', JSON.stringify(assetMap, null, 2));
53 |
54 | // Write out assetMap
55 | if (opts.jsonOutput === true) {
56 | grunt.file.write(path.resolve(opts.baseDir, opts.jsonOutputFilename), JSON.stringify(assetMap));
57 | }
58 |
59 | // don't just split on the filename, if the filename = 'app.css' it will replace
60 | // all app.css references, even to files in other dirs
61 | // so replace this:
62 | // "{file}"
63 | // '{file}'
64 | // ({file}) (css url(...))
65 | // /{file} (css url(...))
66 | // ={file}> (unquoted html attribute)
67 | // ={file}\s (unquoted html attribute fonllowed by more attributes)
68 | // "{file}\s (first entry of img srcset)
69 | // \s{file}\s (other entries of img srcset)
70 | // files may contain a querystring, so all with ? as closing too
71 | var replaceEnclosedBy = [
72 | ['"', '"'],
73 | ["'", "'"],
74 | ['(', ')'],
75 | ['=', '>'],
76 | ['=', ' '],
77 | ['"', ' '],
78 | [' ', ' ']
79 | ];
80 |
81 | // add urlPrefixes to enclosing scenarios
82 | if (opts.urlPrefixes && Array.isArray(opts.urlPrefixes) && opts.urlPrefixes.length > 0) {
83 | opts.urlPrefixes.forEach(function(urlPrefix) {
84 | replaceEnclosedBy.push([urlPrefix, '"']);
85 | replaceEnclosedBy.push([urlPrefix, "'"]);
86 | replaceEnclosedBy.push([urlPrefix, ")"]);
87 | replaceEnclosedBy.push([urlPrefix, ">"]);
88 | replaceEnclosedBy.push([urlPrefix, " "]);
89 | });
90 | }
91 | // don't replace references that are already cache busted
92 | if (!isUsingQueryString(opts)) {
93 | replaceEnclosedBy = replaceEnclosedBy.concat(replaceEnclosedBy.map(function(reb) {
94 | return [reb[0], '?'];
95 | }));
96 | }
97 |
98 | // Go through each source file and replace them with busted file if available
99 | var map = opts.queryString ? {} : assetMap;
100 | var files = getFilesToBeRenamed(this.files, map, opts.baseDir);
101 | files.forEach(replaceInFile);
102 | grunt.log.ok(files.length + ' file' + (files.length !== 1 ? 's ' : ' ') + 'busted.');
103 |
104 | function replaceInFile(filepath) {
105 | var markup = grunt.file.read(filepath);
106 | var baseDir = discoveryOpts.cwd + '/';
107 | var relativeFileDir = path.dirname(filepath).substr(baseDir.length);
108 | var fileDepth = 0;
109 |
110 | if (relativeFileDir !== '') {
111 | fileDepth = relativeFileDir.split('/').length;
112 | }
113 |
114 | var baseDirs = filepath.substr(baseDir.length).split('/');
115 |
116 | _.each(assetMap, function(hashed, original) {
117 | var replace = [
118 | // abs path
119 | ['/' + original, '/' + hashed],
120 | // relative
121 | [grunt.util.repeat(fileDepth, '../') + original, grunt.util.repeat(fileDepth, '../') + hashed],
122 | ];
123 | // find relative paths for shared dirs
124 | var originalDirParts = path.dirname(original).split('/');
125 | for (var i = 1; i <= fileDepth; i++) {
126 | var fileDir = originalDirParts.slice(0, i).join('/');
127 | var baseDir = baseDirs.slice(0, i).join('/');
128 | if (fileDir === baseDir) {
129 | var originalFilename = path.basename(original);
130 | var hashedFilename = path.basename(hashed);
131 | var dir = grunt.util.repeat(fileDepth - 1, '../') + originalDirParts.slice(i).join('/');
132 | if (dir.substr(-1) !== '/') {
133 | dir += '/';
134 | }
135 | replace.push([dir + originalFilename, dir + hashedFilename]);
136 | }
137 | }
138 | _.each(replace, function(r) {
139 | var original = r[0];
140 | var hashed = r[1];
141 | _.each(replaceEnclosedBy, function(reb) {
142 | markup = markup.split(reb[0] + original + reb[1]).join(reb[0] + hashed + reb[1]);
143 | });
144 | });
145 | });
146 |
147 | grunt.file.write(filepath, markup);
148 | }
149 |
150 | function hashFile(obj, file) {
151 | var absPath = path.resolve(opts.baseDir, file);
152 | var hash = generateFileHash(grunt.file.read(absPath, {
153 | encoding: null
154 | }));
155 | var newFilename = addFileHash(file, hash, opts.separator);
156 |
157 | if (!opts.queryString) {
158 | if (opts.createCopies) {
159 | grunt.file.copy(absPath, path.resolve(opts.baseDir, newFilename));
160 | }
161 |
162 | if (opts.deleteOriginals) {
163 | grunt.file.delete(absPath);
164 | }
165 | }
166 |
167 | obj[file] = newFilename;
168 |
169 | return obj;
170 | }
171 |
172 | function generateFileHash(data) {
173 | return opts.hash || crypto.createHash(opts.algorithm).update(data, opts.encoding).digest('hex').substring(0, opts.length);
174 | }
175 |
176 | function addFileHash(str, hash, separator) {
177 | if (opts.queryString) {
178 | return str + '?' + hash;
179 | } else {
180 | var parsed = url.parse(str);
181 | var pathToFile = opts.outputDir.length > 0 ? path.join(opts.outputDir, parsed.pathname.replace(/^.*[\\\/]/, '')) : parsed.pathname;
182 | var ext = path.extname(parsed.pathname);
183 |
184 | return (parsed.hostname ? parsed.protocol + parsed.hostname : '') + pathToFile.replace(ext, '') + separator + hash + ext;
185 | }
186 | }
187 |
188 | function getFilesToBeRenamed(files, assetMap, baseDir) {
189 | var originalConfig = files[0].orig;
190 | // check if fully specified filenames have been busted and replace with busted file
191 | var baseDirResolved = path.resolve(baseDir) + '/';
192 | var cwd = process.cwd() + '/';
193 | originalConfig.src = originalConfig.src.map(function(file) {
194 | if( assetMap ) {
195 | var files = [file];
196 | if(path.resolve(cwd + file).substr(0, baseDirResolved.length) === baseDirResolved) {
197 | files.push(path.resolve(cwd + file).substr(baseDirResolved.length));
198 | }
199 | var result;
200 | files.forEach(function(file2) {
201 | var fileResolved = path.resolve(baseDirResolved + file2);
202 | if (!result && fileResolved.substr(0, baseDirResolved.length) === baseDirResolved && (fileResolved.substr(baseDirResolved.length)) in assetMap) {
203 | result = assetMap[fileResolved.substr(baseDirResolved.length)];
204 | // if original file had baseDir at the start, make sure it's there now
205 | var baseDirNormalized = path.normalize(baseDir);
206 | if(path.normalize(file).substr(0, baseDirNormalized.length) === baseDirNormalized) {
207 | result = baseDir + result;
208 | }
209 | }
210 | });
211 | if(result) {
212 | return result;
213 | }
214 | }
215 | return file;
216 | });
217 |
218 | return grunt.file
219 | .expand(originalConfig, originalConfig.src)
220 | .map(function(file) {
221 |
222 | // if the file is hashed, then the hashed file should be
223 | // used instead of the original for replacement. This will
224 | // only be the case if an outputDir is being used.
225 | if (!opts.queryString && opts.outputDir && _.has(assetMap, file)) {
226 | file = assetMap[file];
227 | }
228 | grunt.verbose.writeln('Busted:', file);
229 | return path.resolve((originalConfig.cwd ? originalConfig.cwd + path.sep : '') + file);
230 | });
231 | }
232 |
233 | });
234 |
235 | };
236 |
--------------------------------------------------------------------------------
/tests/absolutepath/absolutepath.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Test
7 |
8 |
9 | Test
10 |
11 |
12 |
--------------------------------------------------------------------------------
/tests/absolutepath/absolutepath_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | relativepath: function(test) {
8 | var html = grunt.file.read('tmp/relativepath/relativepath.html');
9 | test.ok(html.match(/"\/assets\/css\/application\.123456789\.css"/), 'testing /assets/css/application.css replaced in HTML');
10 |
11 | var css = grunt.file.read('tmp/relativepath/assets/css/application.123456789.css');
12 | test.ok(css.match(/url\(\.\.\/images\/testbg\.123456789\.png\)/), 'testing ../images/testbg.png replaced in busted CSS');
13 | test.ok(css.match(/url\(\.\.\/\.\.\/assets\/images\/testbg\.123456789\.png\)/), 'testing ../../assets/images/testbg.png replaced in busted CSS');
14 |
15 | test.done();
16 | }
17 |
18 | };
19 |
--------------------------------------------------------------------------------
/tests/absolutepath/assets/css/application.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | body {
4 | background-image: url(../images/testbg.png);
5 | }
6 |
7 | div.test {
8 | background-image: url(../../assets/images/testbg.png);
9 | }
10 |
11 | div.test2 {
12 | background-image: url(/assets/images/testbg.png);
13 | }
14 |
--------------------------------------------------------------------------------
/tests/absolutepath/assets/images/testbg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/absolutepath/assets/images/testbg.png
--------------------------------------------------------------------------------
/tests/complex/complex.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Complex example
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/tests/complex/complex_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | complex: function(test) {
8 | test.expect(3);
9 |
10 | var markup = grunt.file.read('tmp/complex/complex.html');
11 | var css = grunt.file.read('tmp/complex/css/complex.123456789.css');
12 |
13 | test.ok(markup.match(/css\/complex\.123456789\.css/), 'testing css/complex.css');
14 | test.ok(markup.match(/imgs\/complex-background\.123456789\.jpg/), 'testing imgs/complex-background.jpg in markup');
15 | test.ok(css.match(/imgs\/complex-background\.123456789\.jpg/), 'testing imgs/complex-background.jpg in css');
16 |
17 | test.done();
18 | }
19 |
20 | };
21 |
--------------------------------------------------------------------------------
/tests/complex/css/complex.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: red;
3 | background-image: url('/imgs/complex-background.jpg');
4 | }
5 |
--------------------------------------------------------------------------------
/tests/complex/imgs/complex-background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/complex/imgs/complex-background.jpg
--------------------------------------------------------------------------------
/tests/createCopies/assets/.htaccess:
--------------------------------------------------------------------------------
1 | RewriteCond %{REQUEST_FILENAME} !-f
2 | RewriteCond %{REQUEST_FILENAME} !-d
3 | RewriteRule ^(.+)\.([\da-z]+)\.(js|css|png|jpg|gif)$ $1.$3 [L]
--------------------------------------------------------------------------------
/tests/createCopies/assets/dontCopy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/createCopies/assets/dontCopy.png
--------------------------------------------------------------------------------
/tests/createCopies/createCopies.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | This is a test page
5 |
6 |
7 |
8 | This image should load if you use rewrites:
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/tests/deleteOriginals/assets/delete.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: silver;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/deleteOriginals/assets/delete.js:
--------------------------------------------------------------------------------
1 | alert('JS is working');
2 |
--------------------------------------------------------------------------------
/tests/deleteOriginals/assets/delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/deleteOriginals/assets/delete.png
--------------------------------------------------------------------------------
/tests/deleteOriginals/deleteOriginalSameAssets.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | This is a test page
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/tests/deleteOriginals/deleteOriginals.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | This is a test page
5 |
6 |
7 |
8 |
9 |
10 | Have you heard?
11 |
12 | Heard what??
13 |
14 |
15 |
16 | THE BIRD IS THE WORD!!
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/hash/assets/hash.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: silver;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/hash/assets/hash.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/hash/assets/hash.jpg
--------------------------------------------------------------------------------
/tests/hash/assets/hash.js:
--------------------------------------------------------------------------------
1 | alert('JS is working');
2 |
--------------------------------------------------------------------------------
/tests/hash/hash.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | This is a test page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/tests/hash/hash_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | hash: function(test) {
8 | test.expect(3);
9 |
10 | var markup = grunt.file.read('tmp/hash/hash.html');
11 |
12 | test.ok(markup.match(/assets\/hash\.abcdef123456\.css/), 'testing assets/hash.css');
13 | test.ok(markup.match(/assets\/hash\.abcdef123456\.jpg/), 'testing assets/hash.jpg');
14 | test.ok(markup.match(/assets\/hash\.abcdef123456\.js/ ), 'testing assets/hash.js');
15 |
16 | test.done();
17 | }
18 |
19 | };
20 |
--------------------------------------------------------------------------------
/tests/ignorePattern/assets/toBeIgnoredCSS.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: silver;
3 | }
4 |
5 | h1, h2, h3 {
6 | font-size: 100px;
7 | }
8 |
--------------------------------------------------------------------------------
/tests/ignorePattern/assets/toBeIgnoredJPG.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/ignorePattern/assets/toBeIgnoredJPG.jpg
--------------------------------------------------------------------------------
/tests/ignorePattern/assets/toBeIgnoredJS.js:
--------------------------------------------------------------------------------
1 | alert('JS is working');
2 | alert('JS is still working');
3 |
--------------------------------------------------------------------------------
/tests/ignorePattern/ignorePattern.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | This is a test page
5 |
6 |
7 |
8 |
9 |
10 | Have you heard?
11 |
12 | Heard what??
13 |
14 |
15 |
16 | THE BIRD IS THE WORD!!
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/ignorePattern/ignorePattern_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | ignore: function(test) {
8 | test.expect(3);
9 |
10 | var markup = grunt.file.read('tmp/ignorePattern/ignorePattern.html');
11 |
12 | test.ok(markup.match(/assets\/toBeIgnoredCSS\.[a-z0-9]{16}\.css"/), 'testing toBeIgnoredCSS');
13 | test.ok(markup.match(/assets\/toBeIgnoredJPG\.jpg"/), 'testing toBeIgnoredJPG');
14 | test.ok(markup.match(/assets\/toBeIgnoredJS\.[a-z0-9]{16}\.js"/), 'testing toBeIgnoredJS');
15 |
16 | test.done();
17 | }
18 |
19 | };
20 |
--------------------------------------------------------------------------------
/tests/imgsrcset/assets/imgsrcset-big.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/imgsrcset/assets/imgsrcset-big.jpg
--------------------------------------------------------------------------------
/tests/imgsrcset/assets/imgsrcset-small.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/imgsrcset/assets/imgsrcset-small.jpg
--------------------------------------------------------------------------------
/tests/imgsrcset/assets/imgsrcset.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/imgsrcset/assets/imgsrcset.jpg
--------------------------------------------------------------------------------
/tests/imgsrcset/imgsrcset.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | This is a img srcset test page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/imgsrcset/imgsrcset_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | imgsrcset: function(test) {
8 | test.expect(3);
9 |
10 | var markup = grunt.file.read('tmp/imgsrcset/imgsrcset.html');
11 |
12 | test.ok(markup.match(/assets\/imgsrcset\.[a-z0-9]{16}\.jpg/), 'testing assets/imgsrcset.jpg');
13 | test.ok(markup.match(/assets\/imgsrcset-big\.[a-z0-9]{16}\.jpg/), 'testing assets/imgsrcset-big.jpg');
14 | test.ok(markup.match(/assets\/imgsrcset-small\.[a-z0-9]{16}\.jpg/), 'testing assets/imgsrcset-small.jpg');
15 |
16 | test.done();
17 | }
18 |
19 | };
20 |
--------------------------------------------------------------------------------
/tests/jsonOutput/assets/jsonOutput.js:
--------------------------------------------------------------------------------
1 | alert('JS is working');
2 |
--------------------------------------------------------------------------------
/tests/jsonOutput/jsonOutput.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/jsonOutput/jsonOutput_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | jsonOutput: function(test) {
8 | test.expect(1);
9 |
10 | var outputMap = grunt.file.read('tmp/jsonOutput/jsonOutput-map.json');
11 | var expectedMap = JSON.stringify({
12 | 'assets/jsonOutput.js': 'assets/jsonOutput.3bc124f632c7cdbc.js'
13 | });
14 |
15 | test.equal(outputMap, expectedMap, 'testing output of json file');
16 |
17 | test.done();
18 | }
19 |
20 | };
21 |
--------------------------------------------------------------------------------
/tests/outputDir/assets/outputDir.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: silver;
3 | }
4 |
5 | #complex {
6 | background-color: red;
7 | background-image: url('/assets/outputDir.png');
8 | }
9 |
--------------------------------------------------------------------------------
/tests/outputDir/assets/outputDir.js:
--------------------------------------------------------------------------------
1 | alert('JS is working');
2 |
--------------------------------------------------------------------------------
/tests/outputDir/assets/outputDir.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/outputDir/assets/outputDir.png
--------------------------------------------------------------------------------
/tests/outputDir/outputDir.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | This is a test page
5 |
6 |
7 |
8 |
9 |
10 | Have you heard?
11 |
12 | Heard what??
13 |
14 |
15 |
16 | THE BIRD IS THE WORD!!
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/outputDir/outputDir_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 | var fs = require('fs');
5 | var _ = require('grunt').util._;
6 |
7 | module.exports = {
8 |
9 | outputDir: function(test) {
10 | test.expect(8);
11 |
12 | var markup = grunt.file.read('tmp/outputDir/outputDir.html');
13 | var css = grunt.file.read('tmp/outputDir/outputDir/outputDir.abcdef123456.css');
14 | var actual = fs.readdirSync('tmp/outputDir/assets').sort();
15 | var expected = fs.readdirSync('tests/outputDir/assets').sort();
16 |
17 | test.ok(markup.match(/outputDir\/outputDir\.abcdef123456\.css/), 'testing outputDir/outputDir.css in html');
18 | test.ok(markup.match(/outputDir\/outputDir\.abcdef123456\.png/), 'testing outputDir/outputDir.png in html');
19 | test.ok(markup.match(/outputDir\/outputDir\.abcdef123456\.js/ ), 'testing outputDir/outputDir.js in html');
20 | test.ok(css.match(/outputDir\.abcdef123456\.png/ ), 'testing outputDir/outputDir.png in css');
21 |
22 | test.deepEqual(expected, actual, 'should not have files in assets folder');
23 |
24 | // original files should not be changed
25 | _.each(['outputDir.png', 'outputDir.css', 'outputDir.js'], function(file) {
26 | var original = grunt.file.read('tests/outputDir/assets/' + file);
27 | var copied = grunt.file.read('tmp/outputDir/assets/' + file);
28 | test.equal(original, copied, file + ' should not have changed');
29 | });
30 |
31 | test.done();
32 | }
33 | };
34 |
--------------------------------------------------------------------------------
/tests/queryString/css/test.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: red;
3 | background-image: url('/imgs/background.jpg');
4 | }
5 |
--------------------------------------------------------------------------------
/tests/queryString/imgs/background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/queryString/imgs/background.jpg
--------------------------------------------------------------------------------
/tests/queryString/queryString.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Query string example
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/tests/queryString/queryString_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | queryString: function(test) {
8 | test.expect(3);
9 |
10 | var markup = grunt.file.read('tmp/queryString/queryString.html');
11 | var css = grunt.file.read('tmp/queryString/css/test.css');
12 |
13 | test.ok(markup.match(/css\/test\.css\?123456789/), 'testing css/test.css');
14 | test.ok(markup.match(/imgs\/background\.jpg\?123456789/), 'testing imgs/background.jpg in markup');
15 | test.ok(css.match(/imgs\/background\.jpg\?123456789/), 'testing imgs/background.jpg in css');
16 |
17 | test.done();
18 | }
19 |
20 | };
21 |
--------------------------------------------------------------------------------
/tests/realpath/css/app.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: red;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/realpath/lib/css/app.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: green;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/realpath/realpath.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Realpath example
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/realpath/realpath_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | realpath: function(test) {
8 | //test.expect(2);
9 |
10 | var markup = grunt.file.read('tmp/realpath/realpath.html');
11 |
12 | test.ok(markup.match(/\"\/css\/app\.123456789\.css\"/), 'testing /css/app.css replaced');
13 | test.ok(markup.match(/\"\/lib\/css\/app\.css\"/), 'testing /lib/css/app.css not replaced');
14 | test.ok(!markup.match(/\"\/lib\/css\/app\.123456789\.css\"/), 'testing /lib/css/app.css not replaced');
15 |
16 | test.done();
17 | }
18 |
19 | };
20 |
--------------------------------------------------------------------------------
/tests/relativepath/assets/css/application.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | body {
4 | background-image: url(../images/testbg.png);
5 | }
6 |
7 | div.test {
8 | background-image: url(../../assets/images/testbg.png);
9 | }
10 |
11 | div.test2 {
12 | background-image: url(/assets/images/testbg.png);
13 | }
14 |
--------------------------------------------------------------------------------
/tests/relativepath/assets/images/testbg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/relativepath/assets/images/testbg.png
--------------------------------------------------------------------------------
/tests/relativepath/relativepath.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Test
7 |
8 |
9 | Test
10 |
11 |
12 |
--------------------------------------------------------------------------------
/tests/relativepath/relativepath_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | relativepath: function(test) {
8 | var html = grunt.file.read('tmp/relativepath/relativepath.html');
9 | test.ok(html.match(/"\/assets\/css\/application\.123456789\.css"/), 'testing /assets/css/application.css replaced in HTML');
10 |
11 | var css = grunt.file.read('tmp/relativepath/assets/css/application.123456789.css');
12 | test.ok(css.match(/url\(\.\.\/images\/testbg\.123456789\.png\)/), 'testing ../images/testbg.png replaced in busted CSS');
13 | test.ok(css.match(/url\(\.\.\/\.\.\/assets\/images\/testbg\.123456789\.png\)/), 'testing ../../assets/images/testbg.png replaced in busted CSS');
14 |
15 | test.done();
16 | }
17 |
18 | };
19 |
--------------------------------------------------------------------------------
/tests/relativepath2/assets/css/application.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | body {
4 | background-image: url(../images/testbg.png);
5 | }
6 |
7 | div.test {
8 | background-image: url(../../assets/images/testbg.png);
9 | }
10 |
11 | div.test2 {
12 | background-image: url(/assets/images/testbg.png);
13 | }
14 |
--------------------------------------------------------------------------------
/tests/relativepath2/assets/images/testbg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/relativepath2/assets/images/testbg.png
--------------------------------------------------------------------------------
/tests/relativepath2/relativepath2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Test
7 |
8 |
9 | Test
10 |
11 |
12 |
--------------------------------------------------------------------------------
/tests/relativepath2/relativepath2_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | relativepath: function(test) {
8 | var html = grunt.file.read('tmp/relativepath2/relativepath2.html');
9 | test.ok(html.match(/"\/assets\/css\/application\.123456789\.css"/), 'testing /assets/css/application.css replaced in HTML');
10 |
11 | var css = grunt.file.read('tmp/relativepath2/assets/css/application.123456789.css');
12 | test.ok(css.match(/url\(\.\.\/images\/testbg\.123456789\.png\)/), 'testing ../images/testbg.png replaced in busted CSS');
13 | test.ok(css.match(/url\(\.\.\/\.\.\/assets\/images\/testbg\.123456789\.png\)/), 'testing ../../assets/images/testbg.png replaced in busted CSS');
14 |
15 | test.done();
16 | }
17 |
18 | };
19 |
--------------------------------------------------------------------------------
/tests/scripts/assets/script.js:
--------------------------------------------------------------------------------
1 | alert('JS is working');
2 | alert('JS is still working');
3 |
4 | console.log('Tell me what you want, what you really really want');
5 |
--------------------------------------------------------------------------------
/tests/scripts/scripts.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | return 'assets/script.js';
3 | })();
4 |
--------------------------------------------------------------------------------
/tests/scripts/scripts_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | scripts: function(test) {
8 | test.expect(1);
9 |
10 | var markup = grunt.file.read('tmp/scripts/scripts.js');
11 |
12 | test.ok(markup.match(/script\.[a-z0-9]{16}\.js/), 'testing script');
13 |
14 | test.done();
15 | }
16 |
17 | };
18 |
--------------------------------------------------------------------------------
/tests/sourceBusted/assets/css/application.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | div.test2 {
4 | background-image: url(/assets/images/testbg.png);
5 | }
6 |
--------------------------------------------------------------------------------
/tests/sourceBusted/assets/images/testbg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/sourceBusted/assets/images/testbg.png
--------------------------------------------------------------------------------
/tests/sourceBusted/sourceBusted.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Test
7 |
8 |
9 | Test
10 |
11 |
12 |
--------------------------------------------------------------------------------
/tests/sourceBusted/sourceBusted_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | // The hardcoded source file is busted to a hashed filename, make sure that file is busted instead
8 | sourceBusted: function(test) {
9 | var html = grunt.file.read('tmp/sourceBusted/sourceBusted.html');
10 | test.ok(html.match(/\"assets\/css\/application\.123456789\.css\"/), 'testing /assets/css/application.css replaced in HTML');
11 |
12 | var css = grunt.file.read('tmp/sourceBusted/assets/css/application.123456789.css');
13 | test.ok(css.match(/url\(\/assets\/images\/testbg\.123456789\.png\)/), 'testing /assets/images/testbg.png replaced in busted CSS');
14 |
15 | test.done();
16 | }
17 |
18 | };
19 |
--------------------------------------------------------------------------------
/tests/sourceBusted2/assets/css/application.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | div.test2 {
4 | background-image: url(/assets/images/testbg.png);
5 | }
6 |
--------------------------------------------------------------------------------
/tests/sourceBusted2/assets/images/testbg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/sourceBusted2/assets/images/testbg.png
--------------------------------------------------------------------------------
/tests/sourceBusted2/sourceBusted2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Test
7 |
8 |
9 | Test
10 |
11 |
12 |
--------------------------------------------------------------------------------
/tests/sourceBusted2/sourceBusted2_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | // The hardcoded source file is busted to a hashed filename, make sure that file is busted instead
8 | sourceBusted: function(test) {
9 | var html = grunt.file.read('tmp/sourceBusted2/sourceBusted2.html');
10 | test.ok(html.match(/\"assets\/css\/application\.123456789\.css\"/), 'testing /assets/css/application.css replaced in HTML');
11 |
12 | var css = grunt.file.read('tmp/sourceBusted2/assets/css/application.123456789.css');
13 | test.ok(css.match(/url\(\/assets\/images\/testbg\.123456789\.png\)/), 'testing /assets/images/testbg.png replaced in busted CSS');
14 |
15 | test.done();
16 | }
17 |
18 | };
19 |
--------------------------------------------------------------------------------
/tests/sourceBusted3/assets/css/application.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | div.test2 {
4 | background-image: url(/assets/images/testbg.png);
5 | }
6 |
--------------------------------------------------------------------------------
/tests/sourceBusted3/assets/images/testbg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/sourceBusted3/assets/images/testbg.png
--------------------------------------------------------------------------------
/tests/sourceBusted3/sourceBusted3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Test
7 |
8 |
9 | Test
10 |
11 |
12 |
--------------------------------------------------------------------------------
/tests/sourceBusted3/sourceBusted3_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | // The hardcoded source file is busted to a hashed filename, make sure that file is busted instead
8 | sourceBusted: function(test) {
9 | var html = grunt.file.read('tmp/sourceBusted3/sourceBusted3.html');
10 | test.ok(html.match(/\"assets\/css\/application\.123456789\.css\"/), 'testing /assets/css/application.css replaced in HTML');
11 |
12 | var css = grunt.file.read('tmp/sourceBusted3/assets/css/application.123456789.css');
13 | test.ok(css.match(/url\(\/assets\/images\/testbg\.123456789\.png\)/), 'testing /assets/images/testbg.png replaced in busted CSS');
14 |
15 | test.done();
16 | }
17 |
18 | };
19 |
--------------------------------------------------------------------------------
/tests/standard/assets/standard-apple-touch-icon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/standard/assets/standard-apple-touch-icon.jpg
--------------------------------------------------------------------------------
/tests/standard/assets/standard.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: silver;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/standard/assets/standard.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/standard/assets/standard.jpg
--------------------------------------------------------------------------------
/tests/standard/assets/standard.js:
--------------------------------------------------------------------------------
1 | alert('JS is working');
2 |
--------------------------------------------------------------------------------
/tests/standard/standard.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | This is a test page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/tests/standard/standard_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | standard: function(test) {
8 | test.expect(4);
9 |
10 | var markup = grunt.file.read('tmp/standard/standard.html');
11 |
12 | test.ok(markup.match(/assets\/standard\.[a-z0-9]{16}\.css/), 'testing assets/standard.css');
13 | test.ok(markup.match(/assets\/standard\.[a-z0-9]{16}\.jpg/), 'testing assets/standard.jpg');
14 | test.ok(markup.match(/assets\/standard\.[a-z0-9]{16}\.js/ ), 'testing assets/standard.js');
15 | test.ok(markup.match(/assets\/standard-apple-touch-icon\.[a-z0-9]{16}\.jpg/), 'testing assets/standard-apple-touch-icon.jpg');
16 |
17 | test.done();
18 | },
19 |
20 | relative: function(test) {
21 | test.expect(4);
22 |
23 | var markup = grunt.file.read('tmp/standard/subfolder/relative-standard.html');
24 |
25 | test.ok(markup.match(/assets\/standard\.[a-z0-9]{16}\.css/), 'testing relative file path of assets/standard.css');
26 | test.ok(markup.match(/assets\/standard\.[a-z0-9]{16}\.jpg/), 'testing relative file path of assets/standard.jpg');
27 | test.ok(markup.match(/assets\/standard\.[a-z0-9]{16}\.js/ ), 'testing relative file path of assets/standard.js');
28 | test.ok(markup.match(/assets\/standard-apple-touch-icon\.[a-z0-9]{16}\.jpg/ ), 'testing relative file path of assets/standard-apple-touch-icon.jpg');
29 |
30 | test.done();
31 | }
32 |
33 | };
34 |
--------------------------------------------------------------------------------
/tests/standard/subfolder/relative-standard.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | This is a test page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/tests/stylesheets/assets/css-image-large.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/stylesheets/assets/css-image-large.jpg
--------------------------------------------------------------------------------
/tests/stylesheets/assets/css-image-quotes.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/stylesheets/assets/css-image-quotes.jpg
--------------------------------------------------------------------------------
/tests/stylesheets/assets/css-image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/stylesheets/assets/css-image.jpg
--------------------------------------------------------------------------------
/tests/stylesheets/assets/fonts/icons.eot:
--------------------------------------------------------------------------------
1 | icons.eot
2 |
--------------------------------------------------------------------------------
/tests/stylesheets/assets/fonts/icons.ttf:
--------------------------------------------------------------------------------
1 | icons.tff
2 |
--------------------------------------------------------------------------------
/tests/stylesheets/assets/fonts/icons.woff:
--------------------------------------------------------------------------------
1 | icons.woff
2 |
--------------------------------------------------------------------------------
/tests/stylesheets/assets/fonts/icons.woff2:
--------------------------------------------------------------------------------
1 | icons.woff2
2 |
--------------------------------------------------------------------------------
/tests/stylesheets/assets/image1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/stylesheets/assets/image1.jpg
--------------------------------------------------------------------------------
/tests/stylesheets/assets/image2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/stylesheets/assets/image2.jpg
--------------------------------------------------------------------------------
/tests/stylesheets/assets/relative-css-image-large.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/stylesheets/assets/relative-css-image-large.jpg
--------------------------------------------------------------------------------
/tests/stylesheets/assets/relative-css-image-quotes.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/stylesheets/assets/relative-css-image-quotes.jpg
--------------------------------------------------------------------------------
/tests/stylesheets/assets/relative-css-image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/stylesheets/assets/relative-css-image.jpg
--------------------------------------------------------------------------------
/tests/stylesheets/assets/relative-image1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/stylesheets/assets/relative-image1.jpg
--------------------------------------------------------------------------------
/tests/stylesheets/assets/stylesheet1.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: red;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/stylesheets/assets/stylesheet2.css:
--------------------------------------------------------------------------------
1 | .text-info {
2 | color: #3a87ad;
3 | }
4 |
5 | .text-info:hover {
6 | color: #2d6987;
7 | }
8 |
9 | .text-left {
10 | text-align: left;
11 | }
12 |
13 | .text-right {
14 | text-align: right;
15 | }
16 |
17 | .text-center {
18 | text-align: center;
19 | }
20 |
--------------------------------------------------------------------------------
/tests/stylesheets/assets/stylesheet3.css:
--------------------------------------------------------------------------------
1 | .list-unstyled {
2 | padding-left: 0;
3 | list-style: none;
4 | }
5 |
6 | .list-inline {
7 | padding-left: 0;
8 | list-style: none;
9 | }
10 |
11 | .list-inline > li {
12 | display: inline-block;
13 | padding-right: 5px;
14 | padding-left: 5px;
15 | }
16 |
17 | .list-inline > li:first-child {
18 | padding-left: 0;
19 | }
20 |
21 | dl {
22 | margin-bottom: 20px;
23 | }
24 |
25 | dt,
26 | dd {
27 | line-height: 1.428571429;
28 | }
29 |
30 | dt {
31 | font-weight: bold;
32 | }
33 |
34 | dd {
35 | margin-left: 0;
36 | }
37 |
--------------------------------------------------------------------------------
/tests/stylesheets/assets/stylesheet4.css:
--------------------------------------------------------------------------------
1 | pre code {
2 | padding: 0;
3 | font-size: inherit;
4 | color: inherit;
5 | white-space: pre-wrap;
6 | background-color: transparent;
7 | border-radius: 0;
8 | }
9 |
10 | .pre-scrollable {
11 | max-height: 340px;
12 | overflow-y: scroll;
13 | }
14 |
15 | .container {
16 | padding-right: 15px;
17 | padding-left: 15px;
18 | margin-right: auto;
19 | margin-left: auto;
20 | }
21 |
22 | .container:before,
23 | .container:after {
24 | display: table;
25 | content: " ";
26 | }
27 |
28 | .container:after {
29 | clear: both;
30 | }
31 |
--------------------------------------------------------------------------------
/tests/stylesheets/css/replaceCssInSubdir.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: red;
3 | }
4 |
5 | .image {
6 | width: auto;
7 | max-height: 120px;
8 | background: #FFFFFF url('../assets/relative-css-image.jpg') center center no-repeat;
9 | }
10 |
11 | .image-quotes {
12 | width: auto;
13 | max-height: 120px;
14 | background: #FFFFFF url("../assets/relative-css-image-quotes.jpg") center center no-repeat;
15 | }
16 |
17 | .large-image {
18 | width: 100%;
19 | background-image: url(../assets/relative-css-image-large.jpg);
20 | background-position: top center;
21 | background-size: contain;
22 | }
23 |
24 | @media only screen and (min-device-pixel-ratio: 2) and (min-resolution: 2dppx) {
25 | .large-image {
26 | background-image: url('../assets/relative-image1.jpg');
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/stylesheets/stylesheet.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: red;
3 | }
4 |
5 | .body:after {
6 | content: url('assets/image2.jpg');
7 | }
8 |
9 | .image {
10 | width: auto;
11 | max-height: 120px;
12 | background: #FFFFFF url('assets/css-image.jpg') center center no-repeat;
13 | }
14 |
15 | .image-quotes {
16 | width: auto;
17 | max-height: 120px;
18 | background: #FFFFFF url("assets/css-image-quotes.jpg") center center no-repeat;
19 | }
20 |
21 | .large-image {
22 | width: 100%;
23 | background-image: url(assets/css-image-large.jpg);
24 | background-position: top center;
25 | background-size: contain;
26 | }
27 |
28 | .external-image {
29 | background-image: url('//www.external.com/external-image1.jpg');
30 | background-image: url('http://www.external.com/external-image2.jpg');
31 | background-image: url('https://www.external.com/external-image3.jpg');
32 | }
33 |
34 | @font-face {
35 | src: local('Lato-Hairline'), url('https://fonts.gstatic.com/s/lato/v11/zJY4gsxBiSo5L7tNutxFNg.ttf');
36 | }
37 |
38 | .data-url-image {
39 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABp0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuMTAw9HKhAAAAmElEQVQoU33PQapBURjA8UtkwJuaWYGSgfQWYBMvczPmTCzAAGVuaA228BZhRCkDGSmE31FucuRfvzq3vr5zT/JSjSU7DsypEPXDkDVn2hSIytJhw4kWGaLCxgHh2gt/RBuLzNhz5caWPjnSqqw4EraFfwznf8qklWjwy4IRTerkiQoPGtPl40OehcEJvcfXl8LglLfBJLkDcMgbgHlHhK8AAAAASUVORK5CYII=);
40 | }
41 |
42 | @media only screen and (min-device-pixel-ratio: 2) and (min-resolution: 2dppx) {
43 | .large-image {
44 | background-image: url('assets/image1.jpg');
45 | }
46 | }
47 |
48 | @font-face {
49 | font-family: icons;
50 | src: url(/assets/fonts/icons.eot);
51 | src: url(/assets/fonts/icons.eot?#iefix) format(embedded-opentype),
52 | url(/assets/fonts/icons.woff) format(woff),
53 | url(/assets/fonts/icons.woff2) format(woff2),
54 | url(/assets/fonts/icons.ttf) format(truetype);
55 | font-weight: 400;
56 | font-style: normal;
57 | }
58 |
--------------------------------------------------------------------------------
/tests/stylesheets/stylesheet_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | stylesheet: function(test) {
8 | test.expect(8);
9 |
10 | var markup = grunt.file.read('tmp/stylesheets/stylesheet.css');
11 |
12 | test.ok(markup.match(/css-image\.[a-z0-9]{16}\.jpg/), 'testing an image in a CSS file');
13 | test.ok(markup.match(/css-image-quotes.[a-z0-9]{16}\.jpg/), 'testing an image in a CSS file');
14 | test.ok(markup.match(/css-image-large\.[a-z0-9]{16}\.jpg/), 'testing an image in a CSS file');
15 | test.ok(markup.match(/image1\.[a-z0-9]{16}\.jpg/), 'testing an image in a CSS file within a media query');
16 | test.ok(markup.match(/image2\.[a-z0-9]{16}\.jpg/), 'testing an image in a CSS file within a media query');
17 | test.ok(markup.match(/'\/\/www\.external\.com\/external-image1.jpg'/), 'testing an external image in a CSS file');
18 | test.ok(markup.match(/'http:\/\/www\.external\.com\/external-image2.jpg'/), 'testing an external image in a CSS file');
19 | test.ok(markup.match(/'https:\/\/www\.external\.com\/external-image3.jpg'/), 'testing an external image in a CSS file');
20 |
21 | test.done();
22 | },
23 |
24 | replaceCssInSubdir: function(test) {
25 | test.expect(4);
26 |
27 | var markup = grunt.file.read('tmp/stylesheets/css/replaceCssInSubdir.css');
28 |
29 | test.ok(markup.match(/assets\/relative-css-image\.[a-z0-9]{16}\.jpg/), 'testing the replacement of an image when css in a different subdir than asset');
30 | test.ok(markup.match(/assets\/relative-css-image-quotes\.[a-z0-9]{16}\.jpg/), 'testing the replacement of an image when css in a different subdir than asset');
31 | test.ok(markup.match(/assets\/relative-css-image-large\.[a-z0-9]{16}\.jpg/), 'testing the replacement of an image when css in a different subdir than asset');
32 | test.ok(markup.match(/assets\/relative-image1\.[a-z0-9]{16}\.jpg/), 'testing the replacement of an image when css in a different subdir than asset');
33 |
34 | test.done();
35 | },
36 |
37 | multipleUrls: function(test) {
38 | test.expect(6);
39 |
40 | var markup = grunt.file.read('tmp/stylesheets/stylesheet.css');
41 |
42 | test.ok(markup.match(/assets\/fonts\/icons\.[a-z0-9]{16}\.eot/), 'testing the that multiple urls busted');
43 | test.ok(markup.match(/assets\/fonts\/icons\.[a-z0-9]{16}\.eot\?#iefix/), 'testing the that multiple urls busted');
44 | test.ok(markup.match(/assets\/fonts\/icons\.[a-z0-9]{16}\.eot/), 'testing the that multiple urls busted');
45 | test.ok(markup.match(/assets\/fonts\/icons\.[a-z0-9]{16}\.woff/), 'testing the that multiple urls busted');
46 | test.ok(markup.match(/assets\/fonts\/icons\.[a-z0-9]{16}\.woff2/), 'testing the that multiple urls busted');
47 | test.ok(markup.match(/assets\/fonts\/icons\.[a-z0-9]{16}\.ttf/), 'testing the that multiple urls busted');
48 |
49 | test.done();
50 | },
51 |
52 | correctlyOrdered: function(test) {
53 | test.expect(2);
54 |
55 | var markup = grunt.file.read('tmp/stylesheets/stylesheet.css');
56 |
57 | test.ok(markup.match(/assets\/fonts\/icons.303f279e24e9a1ed.woff/), 'testing the correct order of replacements');
58 | test.ok(markup.match(/assets\/fonts\/icons.f90c25689874683b.woff2/), 'testing the correct order of replacements');
59 |
60 | test.done();
61 | }
62 |
63 | };
64 |
--------------------------------------------------------------------------------
/tests/templates/base.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Template example
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/tests/templates/templates_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | stylesheet: function(test) {
8 | test.expect(2);
9 |
10 | var markup = grunt.file.read('tmp/templates/base.html');
11 |
12 | test.ok(markup.match(/views\/view-b\.[a-z0-9]{16}\.html/), 'testing view A');
13 | test.ok(markup.match(/views\/view-a\.[a-z0-9]{16}\.html/), 'testing view B');
14 |
15 | test.done();
16 | }
17 |
18 | };
19 |
--------------------------------------------------------------------------------
/tests/templates/views/view-a.html:
--------------------------------------------------------------------------------
1 | View A
2 |
--------------------------------------------------------------------------------
/tests/templates/views/view-b.html:
--------------------------------------------------------------------------------
1 | View B
2 |
--------------------------------------------------------------------------------
/tests/urlPrefixes/assets/imgsrcset-big.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/urlPrefixes/assets/imgsrcset-big.jpg
--------------------------------------------------------------------------------
/tests/urlPrefixes/assets/imgsrcset-small.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/urlPrefixes/assets/imgsrcset-small.jpg
--------------------------------------------------------------------------------
/tests/urlPrefixes/assets/imgsrcset.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/urlPrefixes/assets/imgsrcset.jpg
--------------------------------------------------------------------------------
/tests/urlPrefixes/css/app.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: red;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/urlPrefixes/urlPrefixes.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Realpath example
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/tests/urlPrefixes/urlPrefixes_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | urlPrefixes: function(test) {
8 | var markup = grunt.file.read('tmp/urlPrefixes/urlPrefixes.html');
9 |
10 | test.ok(markup.match(/\/css\/app\.123456789\.css\"/), 'testing /css/app.css replaced');
11 | test.ok(markup.match(/http:\/\/owncdn1\.test\.com\/path\/css\/app\.123456789\.css\"/), 'testing http://owncdn1.test.com/path/css/app.css replaced');
12 |
13 | test.ok(markup.match(/http:\/\/owncdn1\.test\.com\/path\/assets\/imgsrcset\.123456789\.jpg/), 'testing srcset assets/imgsrcset.jpg');
14 | test.ok(markup.match(/http:\/\/owncdn1\.test\.com\/path\/assets\/imgsrcset-big\.123456789\.jpg/), 'testing srcset assets/imgsrcset-big.jpg');
15 | test.ok(markup.match(/http:\/\/owncdn2\.test\.com\/path\/assets\/imgsrcset-small\.123456789\.jpg/), 'testing srcset assets/imgsrcset-small.jpg');
16 |
17 | test.done();
18 | }
19 |
20 | };
21 |
--------------------------------------------------------------------------------
/tests/xml/assets/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/xml/assets/mstile-150x150.png
--------------------------------------------------------------------------------
/tests/xml/assets/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/xml/assets/mstile-310x150.png
--------------------------------------------------------------------------------
/tests/xml/assets/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/xml/assets/mstile-310x310.png
--------------------------------------------------------------------------------
/tests/xml/assets/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benhoIIand/grunt-cache-bust/20f63f294725e5773e77c3d62f6c08180c8e6c72/tests/xml/assets/mstile-70x70.png
--------------------------------------------------------------------------------
/tests/xml/xml.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | #2B5797
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/tests/xml/xml_test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var grunt = require('grunt');
4 |
5 | module.exports = {
6 |
7 | xml: function(test) {
8 | test.expect(4);
9 |
10 | var browserConfig = grunt.file.read('tmp/xml/xml.xml');
11 |
12 | test.ok(browserConfig.match(/assets\/mstile-70x70\.[a-z0-9]{16}\.png/), 'testing busting of an xml file');
13 | test.ok(browserConfig.match(/assets\/mstile-150x150\.[a-z0-9]{16}\.png/), 'testing busting of an xml file');
14 | test.ok(browserConfig.match(/assets\/mstile-310x310\.[a-z0-9]{16}\.png/), 'testing busting of an xml file');
15 | test.ok(browserConfig.match(/assets\/mstile-310x150\.[a-z0-9]{16}\.png/), 'testing busting of an xml file');
16 |
17 | test.done();
18 | }
19 |
20 | };
21 |
--------------------------------------------------------------------------------