Git Product home page Git Product logo

gulp-cache-buster's Introduction

gulp-cache-buster

Gulp plugin that searches for asset references (URLs) and replaces them with a cache busted representation.

This plugin was designed to work with gulp-hasher

Build Status

Install

npm install --save-dev gulp-cache-buster

Usage

Options with default values shown:

buster({
  env: 'development',
  hashes: {},
  assetRoot: '',
  assetURL: '/',
  tokenRegExp: /ASSET{(.*?)}/g,
  hashLength: 8
})
  • env: the target environment for the current build
  • hashes: an object containing mappings of asset paths to their hash digests
  • assetRoot: points to the root folder containing assets e.g. 'dist/'
  • tokenRegExp: pattern that describes how asset references are presented in your source code (css, less, jade, html, etc...)
    • With the default setting you define an asset reference like so: background-image: url(ASSET{assets/images/pingu.jpg});
    • This option is usually left as-is
  • hashLength: the number of characters to use from the asset's hash digest
    • With the default value this plugin will generate url's like so: background-image: url(http://cdn.example.com/assets/images/pingu.jpg?v=df23b44e});
    • This option is usually left as-is

If the plugin encounters an asset path that is not present in the hashes mapping, the plugin will not add the url query parameter (the ?v=df23b44e part).

Example

Given a CSS file with the following content:

.logo {
  width: 200px;
  background: url(ASSET{assets/images/logo.svg});
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}

.logo-basic {
  width: 80px;
  background: url(ASSET{assets/images/logo-basic.png});
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}

Notice that asset reference are wrapped with ASSET{<relative_path>}. This notation can be changed by setting tokenRegExp.

Furthermore, while CSS is used in this example this plugin can be passed HTML, Jade and any text files that contain the asset reference as seen in the CSS example.

There is additional support for some common switches for selecting minified and/or gzipped assets as shown below:

<link rel="stylesheet" href="ASSET{assets/styles/style.css,min}" />
<script src="ASSET{assets/scripts/vendor.js,min,gz}"></script>

If the env option is set to production these lines will turn into something like this:

<link rel="stylesheet" href="https://cdn.mysite.com/assets/styles/style.min.css?v=af1358" />
<script src="https://cdn.mysite.com/assets/scripts/vendor.min.js.gz?v=db231bc"></script>

... also assumes assetURL is https://cdn.mysite.com/

We can build the following gulpfile tasks:

var autoprefixer = require('gulp-autoprefixer');
var buster = require('gulp-cache-buster');
var gulp = require('gulp');
var hasher = require('gulp-hasher');
var imagemin = require('gulp-imagemin');
var minifyCss = require('gulp-minify-css');
var pngquant = require('imagemin-pngquant');
var rename = require('gulp-rename');


// First we build up asset hash digests using gulp-hasher
gulp.task('images', function() {
  return gulp.src('assets/images/**/*')
    .pipe(imagemin({
      progressive: true,
      svgoPlugins: [{removeViewBox: false}],
      use: [pngquant()]
    }))
    .pipe(gulp.dest('dist/assets/images/'))
    .pipe(hasher());
});

// Using gulp-cache-buster in a css workflow looks like this:
gulp.task('styles', ['images'], function() {
  return gulp.src('assets/styles/themes/*/style.less')
    .pipe(autoprefixer())
    .pipe(buster({      // <-- STARTING HERE
      assetRoot: path.join(__dirname, 'dist'),
      hashes: hasher.hashes     // since images task has run we can pass in the hashes object
    }))
    .pipe(gulp.dest('dist/assets/styles/'))
    .pipe(hasher())
    .pipe(minifyCss())
    .pipe(rename({extname: '.min.css'}))
    .pipe(gulp.dest('dist/assets/styles/'))
    .pipe(hasher());
});

See also

  • gulp-hasher which can be used with gulp-cache-buster to obtain a mapping of asset paths and their md5 digests

Contributing

Pull requests are welcome. If you add functionality, then please add unit tests to cover it.

License

MIT © George Haidar

gulp-cache-buster's People

Contributors

disintegrator avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

gulp-cache-buster's Issues

Needs more hash

Hi @disintegrator, this plugin is exactly what I'm looking for and I have it running through, creating a dist folder and a minified CSS file per your instruction but it doesn't append any sort of hash to the end of the file references within the CSS.

A colleague of mine altered the index.js of your plugin to append a simple string to the end of the outputted CSS:

'use strict';

var path = require('path');
var url = require('url');

var _ = require('lodash');
var es = require('event-stream');
var rs = require('replacestream');

var defaults = {
  hashes: {},
  assetRoot: '',
  assetURL: '/',
  tokenRegExp: /ASSET{(.*?)}/g,
  hashLength: 8
};


var plugin = function(options) {
  var opts = _.extend({}, defaults, options);
  var replaceFunc = function(m, p1) {
    var p = path.join(opts.assetRoot, p1);
    var digest = (opts.hashes[p] || '45674');
    //var digest = (opts.hashes[p] || '');
    var u = url.parse(opts.assetURL);
    u.pathname += p1;
    if (digest) {
      u.query = _.extend({}, u.query, {v: digest.substr(0, opts.hashLength)});
    }
    return url.format(u);
  };
  return es.map(function(file, cb) {
    var out = file;
    if (file.isNull()) { return cb(null, out); }
    if (file.isBuffer()) {
      file.contents = new Buffer(String(file.contents)
          .replace(opts.tokenRegExp, replaceFunc));
    }
    else if (file.isStream()) {
      out = file.pipe(rs(opts.tokenRegExp, replaceFunc));
    }
    return cb(null, out);
  });
};

module.exports = plugin;

This plugin does alter the URL of each asset to be an absolute path. What gets us is that within your index.js there's no mention of any hash production. Should we add our own gulp hash plugin and append it instead of the numbers found within your replaceFunc function [ var digest = (opts.hashes[p] || '45674');]?

Provide a regex to allow for vanilla URLs to be parsed

I understand the decision behind the ASSET { ... } wrapper - forcing users to be very explicit about which URLs get processed. But it would be nice if you provided a regex that people could copy and paste that would match all URLs defined in CSS, script, link, and img tags. I took the time to write one, as it wasn't the easiest thing:

(?:url\(|<(?:link|script|img)[^>]+(?:src|href)\s*=\s*)(?!['"]?(?:data|http))['"]?([^'"\)\s>]+)

This works on the following, not matching any remote URLs or DATA urls:

http://www.regexpal.com/?fam=94254

{
  background-image: url("foo/bar.jpg");
  background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
  background: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
  background-image: no-repeat url(/asdf/foo/bar.jpg);
  background: transparent no-repeat url(/asdf/foo/bar.jpg) top left;
  list-style: square url("/asdf/foo/bar.jpg");
  content: url("/asdf/foo/bar.jpg");
  background-image: url(http://remote.com/asdf/foo/bar.jpg);
  background-image: url("http://remote.com/asdf/foo/bar.jpg");
}
<link rel="stylesheet" href="/asdf/foo/bar.jpg" />
<link rel="stylesheet" href="http://remote.com/asdf/foo/bar.jpg" />
<script src="https://cdn.mysite.com/assets/scripts/vendor.min.js.gz"></script>
<script type="text/javascript" src='/asdf/foo/bar.jpg'></script>
<img alt="foo" src=/asdf/foo/bar.jpg>
<img alt="foo" src=/asdf/foo/bar.jpg />
<img src=https://cdn.mysite.com/assets/scripts/vendor.min.js.gz />
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" />

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.