Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add enableCaching option #1

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,6 @@ var assetNode = new AssetRewrite(node, {
- `prepend` - Default: `''` - A string to prepend to all of the assets. Useful for CDN urls like `https://subdomain.cloudfront.net/`
- `ignore` - Default: `[]` - Ignore files from being rewritten.
- `annotation` - Default: null - A human-readable description for this plugin instance.
- `enableCaching` - Default: false - Setting to true will enable caching but may cause problems in typical usage with broccoli-asset-rev.

[![ghit.me](https://ghit.me/badge.svg?repo=rickharrison/broccoli-asset-rewrite)](https://ghit.me/repo/rickharrison/broccoli-asset-rewrite)
278 changes: 141 additions & 137 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,178 +17,180 @@ function relative(a, b) {
return relativePath.charAt(0) !== '.' ? './' + relativePath : relativePath;
}

function AssetRewrite(inputNode, options) {
if (!(this instanceof AssetRewrite)) {
return new AssetRewrite(inputNode, options);
}

options = options || {};

Filter.call(this, inputNode, {
extensions: options.replaceExtensions || ['html', 'css'],
// We should drop support for `description` in the next major release
annotation: options.description || options.annotation
});

this.assetMap = options.assetMap || {};
this.prepend = options.prepend || '';
this.ignore = options.ignore || []; // files to ignore

this.assetMapKeys = null;
}
class AssetRewrite extends Filter {

constructor(inputNode, options) {
options = options || {};

AssetRewrite.prototype = Object.create(Filter.prototype);
AssetRewrite.prototype.constructor = AssetRewrite;
super(inputNode, {
extensions: options.replaceExtensions || ['html', 'css'],
annotation: options.annotation
});

AssetRewrite.prototype.processAndCacheFile = function (srcDir, destDir, relativePath) {
this._cache = new Cache();
this.assetMap = options.assetMap || {};
this.prepend = options.prepend || '';
this.ignore = options.ignore || []; // files to ignore
this.enableCaching = options.enableCaching || false;

return Filter.prototype.processAndCacheFile.apply(this, arguments);
}

/**
* Checks that file is not being ignored and destination doesn't already have a file
* @param relativePath
* @returns {boolean}
*/

AssetRewrite.prototype.canProcessFile = function(relativePath) {
if (!this.assetMapKeys) {
this.generateAssetMapKeys();
this.assetMapKeys = null;
}

if (!this.inverseAssetMap) {
var inverseAssetMap = {};
var assetMap = this.assetMap;

Object.keys(assetMap).forEach(function(key) {
var value = assetMap[key];
inverseAssetMap[value] = key;
}, this);

this.inverseAssetMap = inverseAssetMap;
processAndCacheFile(srcDir, destDir, relativePath) {
if (!this.enableCaching) {
this._cache = new Cache();
}
return super.processAndCacheFile.apply(this, arguments);
}

/*
* relativePath can be fingerprinted or not.
* Check that neither of these variations are being ignored
/**
* Checks that file is not being ignored and destination doesn't already have a file
* @param relativePath
* @returns {boolean}
*/

if (this.ignore.indexOf(relativePath) !== -1 || this.ignore.indexOf(this.inverseAssetMap[relativePath]) !== -1) {
return false;
}

return Filter.prototype.canProcessFile.apply(this, arguments);
}
canProcessFile(relativePath) {
if (!this.assetMapKeys) {
this.generateAssetMapKeys();
}

AssetRewrite.prototype.rewriteAssetPath = function (string, assetPath, replacementPath) {

// Early exit: does the file contain the asset path?
if (string.indexOf(assetPath) === -1) return string;

var newString = string;

/*
* Replace all of the assets with their new fingerprint name
*
* Uses a regular expression to find assets in html tags, css backgrounds, handlebars pre-compiled templates, etc.
*
* ["\'(=] - Match one of "'(= exactly one time
* \\s* - Any amount of white space
* ( - Starts the first capture group
* [^"\'()=]* - Do not match any of ^"'()= 0 or more times
* [^"\n\'()\\>=]* - Do not match any of ^"\n'()\>= 0 or more times - Explicitly add \ here because of handlebars compilation
* ) - End first capture group
* (\\?[^"\')> ]*)? - Allow for query parameters to be present after the URL of an asset
* \\s* - Any amount of white space
* \\\\* - Allow any amount of \ - For handlebars compilation (includes \\\)
* \\s* - Any amount of white space
* ["\')>\s] - Match one of "'(\n> exactly one time
*/
if (!this.inverseAssetMap) {
var inverseAssetMap = {};
var assetMap = this.assetMap;

var re = new RegExp('["\'(=]\\s*([^"\'()=]*' + escapeRegExp(assetPath) + '[^"\n\'()\\>=]*)(\\?[^"\')> ]*)?\\s*\\\\*\\s*["\')>\s]', 'g');
var match = null;

/*
* This is to ignore matches that should not be changed
* Any URL encoded match that would be ignored above will be ignored by this: "'()=\
*/
var ignoreLibraryCode = new RegExp('%(22|27|5C|28|29|3D)[^"\'()=]*' + escapeRegExp(assetPath));
Object.keys(assetMap).forEach(function(key) {
var value = assetMap[key];
inverseAssetMap[value] = key;
}, this);

while (match = re.exec(newString)) {
var replaceString = '';
if (ignoreLibraryCode.exec(match[1])) {
continue;
this.inverseAssetMap = inverseAssetMap;
}

replaceString = match[1].replace(assetPath, replacementPath);
/*
* relativePath can be fingerprinted or not.
* Check that neither of these variations are being ignored
*/

if (this.prepend && replaceString.indexOf(this.prepend) !== 0) {
var removeLeadingRelativeOrSlashRegex = new RegExp('^(\\.*/)*(.*)$');
replaceString = this.prepend + removeLeadingRelativeOrSlashRegex.exec(replaceString)[2];
if (this.ignore.indexOf(relativePath) !== -1 || this.ignore.indexOf(this.inverseAssetMap[relativePath]) !== -1) {
return false;
}

newString = newString.replace(new RegExp(escapeRegExp(match[1]), 'g'), replaceString);
return super.canProcessFile.apply(this, arguments);
}

var self = this;
return newString.replace(new RegExp('sourceMappingURL=' + escapeRegExp(assetPath)), function(wholeMatch) {
var replaceString = replacementPath;
if (self.prepend && (!/^sourceMappingURL=(http|https|\/\/)/.test(wholeMatch))) {
replaceString = self.prepend + replacementPath;
rewriteAssetPath(string, assetPath, replacementPath) {

// Early exit: does the file contain the asset path?
if (string.indexOf(assetPath) === -1) return string;

var newString = string;

/*
* Replace all of the assets with their new fingerprint name
*
* Uses a regular expression to find assets in html tags, css backgrounds, handlebars pre-compiled templates, etc.
*
* ["\'(=] - Match one of "'(= exactly one time
* \\s* - Any amount of white space
* ( - Starts the first capture group
* [^"\'()=]* - Do not match any of ^"'()= 0 or more times
* [^"\n\'()\\>=]* - Do not match any of ^"\n'()\>= 0 or more times - Explicitly add \ here because of handlebars compilation
* ) - End first capture group
* (\\?[^"\')> ]*)? - Allow for query parameters to be present after the URL of an asset
* \\s* - Any amount of white space
* \\\\* - Allow any amount of \ - For handlebars compilation (includes \\\)
* \\s* - Any amount of white space
* ["\')>\s] - Match one of "'(\n> exactly one time
*/

var re = new RegExp('["\'(=]\\s*([^"\'()=]*' + escapeRegExp(assetPath) + '[^"\n\'()\\>=]*)(\\?[^"\')> ]*)?\\s*\\\\*\\s*["\')>\s]', 'g');
var match = null;

/*
* This is to ignore matches that should not be changed
* Any URL encoded match that would be ignored above will be ignored by this: "'()=\
*/
var ignoreLibraryCode = new RegExp('%(22|27|5C|28|29|3D)[^"\'()=]*' + escapeRegExp(assetPath));

while (match = re.exec(newString)) {
var replaceString = '';
if (ignoreLibraryCode.exec(match[1])) {
continue;
}
if (match[1].indexOf(replacementPath) === -1) {
replaceString = match[1].replace(assetPath, replacementPath);
} else {
// already replaced
replaceString = match[1];
}

if (this.prepend && replaceString.indexOf(this.prepend) !== 0) {
var removeLeadingRelativeOrSlashRegex = new RegExp('^(\\.*/)*(.*)$');
replaceString = this.prepend + removeLeadingRelativeOrSlashRegex.exec(replaceString)[2];
}

newString = newString.replace(new RegExp(escapeRegExp(match[1]), 'g'), replaceString);
}
return wholeMatch.replace(assetPath, replaceString);
});
};

AssetRewrite.prototype.processString = function (string, relativePath) {
var newString = string;
var self = this;
return newString.replace(new RegExp('sourceMappingURL=' + escapeRegExp(assetPath)), function(wholeMatch) {
var replaceString = replacementPath;
if (self.prepend && (!/^sourceMappingURL=(http|https|\/\/)/.test(wholeMatch))) {
replaceString = self.prepend + replacementPath;
}
return wholeMatch.replace(assetPath, replaceString);
});
};

for (var i = 0, keyLength = this.assetMapKeys.length; i < keyLength; i++) {
var key = this.assetMapKeys[i];
processString(string, relativePath) {
var newString = string;

if (this.assetMap.hasOwnProperty(key)) {
/*
* Rewrite absolute URLs
*/
for (var i = 0, keyLength = this.assetMapKeys.length; i < keyLength; i++) {
var key = this.assetMapKeys[i];

newString = this.rewriteAssetPath(newString, key, this.assetMap[key]);
if (this.assetMap.hasOwnProperty(key)) {
/*
* Rewrite absolute URLs
*/

/*
* Rewrite relative URLs. If there is a prepend, use the full absolute path.
*/
newString = this.rewriteAssetPath(newString, key, this.assetMap[key]);

var pathDiff = relative(relativePath, key).replace(/^\.\//, "");
var replacementDiff = relative(relativePath, this.assetMap[key]).replace(/^\.\//, "");
/*
* Rewrite relative URLs. If there is a prepend, use the full absolute path.
*/

if (this.prepend && this.prepend !== '') {
replacementDiff = this.assetMap[key];
}
var pathDiff = relative(relativePath, key).replace(/^\.\//, "");
var replacementDiff = relative(relativePath, this.assetMap[key]).replace(/^\.\//, "");

newString = this.rewriteAssetPath(newString, pathDiff, replacementDiff);
if (this.prepend && this.prepend !== '') {
replacementDiff = this.assetMap[key];
}

newString = this.rewriteAssetPath(newString, pathDiff, replacementDiff);
}
}
}

return newString;
};
return newString;
}

AssetRewrite.prototype.generateAssetMapKeys = function () {
var keys = Object.keys(this.assetMap);
generateAssetMapKeys () {
var keys = Object.keys(this.assetMap);

keys.sort(function (a, b) {
if (a.length < b.length) {
return 1;
}
keys.sort(function (a, b) {
if (a.length < b.length) {
return 1;
}

if (a.length > b.length) {
return -1;
}
if (a.length > b.length) {
return -1;
}

return 0;
});
return 0;
});

this.assetMapKeys = keys;
};
this.assetMapKeys = keys;
}
}

/*
* /([.*+?^=!:${}()|\[\]\/\\])/g - Replace .*+?^=!:${}()|[]/\ in filenames with an escaped version for an exact name match
Expand All @@ -197,4 +199,6 @@ function escapeRegExp(string) {
return string.replace(/([.*+?^${}()|\[\]\/\\])/g, "\\$1");
}

module.exports = AssetRewrite;
module.exports = function() {
return new AssetRewrite(...arguments);
}
Loading