Comparing version 0.4.10 to 0.5.0
@@ -40,4 +40,4 @@ var path = require("path"); | ||
var args = minimist(argv.slice(2), { | ||
"boolean": ["verbose", "clean", "ignore-errors", "help", "skip-css", "amend", "quickhash", "ignore-plugin-errors", "skip-map"], | ||
"string": ["exclude", "include", "manifest-format", "manifest-path", "plugins", "clean-old", "base-dir", "passthrough", "disabled-plugins", "sourcemap-url-prefix"], | ||
"boolean": ["verbose", "clean", "ignore-errors", "help", "skip-css", "amend", "quickhash", "ignore-plugin-errors", "skip-map", "sourcemap-include-path"], | ||
"string": ["exclude", "include", "manifest-format", "manifest-path", "plugins", "clean-old", "base-dir", "passthrough", "disabled-plugins", "sourcemap-url-prefix", "hash-length", "rename-format"], | ||
"alias": { | ||
@@ -54,2 +54,4 @@ "verbose": "v", | ||
"quickhash": "q", | ||
"hash-length": "l", | ||
"rename-format": "f", | ||
"base-dir": "b" | ||
@@ -76,3 +78,3 @@ } | ||
} | ||
var options = { | ||
@@ -92,4 +94,7 @@ exclude: args.exclude || null, | ||
baseDir: args["base-dir"], | ||
sourcemapURLPrefix: args["sourcemap-url-prefix"] || "", | ||
disabledPlugins: args["disabled-plugins"] ? args["disabled-plugins"].split(";") : null | ||
sourcemapURLPrefix: args["sourcemap-url-prefix"] || "", | ||
sourcemapIncludePath: (typeof args["sourcemap-include-path"] === undefined) ? true : !!args["sourcemap-include-path"], | ||
disabledPlugins: args["disabled-plugins"] ? args["disabled-plugins"].split(";") : null, | ||
hashLength: parseInt(args["hash-length"]), | ||
renameFormat: args["rename-format"] | ||
}; | ||
@@ -119,3 +124,3 @@ | ||
} | ||
plugins.forEach(function (plugin) { | ||
@@ -122,0 +127,0 @@ loadedCallback(plugin.name); |
@@ -5,17 +5,29 @@ "use strict"; | ||
// We use MD5 hashcodes which are length 32 string containing only hexadecimal chars. | ||
var _hashedFileRegex = (/.*\-hc[a-f0-9]{32}.*/i); | ||
// Gets the correct hash generator for the specified options | ||
exports.getHashPattern = function (hashFormat, hashLength) { | ||
hashFormat = hashFormat || "{basename}-hc{hash}{extname}"; | ||
hashLength = hashLength || 32; | ||
// Determines if a filename is a hashed (generated) path, or an original path | ||
exports.isHashedFile = function (fileName) { | ||
return _hashedFileRegex.test(path.basename(fileName)); | ||
}; | ||
// Generate the regex for testing the hash | ||
var _hashedFileRegex = new RegExp(hashFormat.replace(/([[^$.|?*+()])/, "\\$1").replace(/{(base|ext)name}/gi, ".*").replace("{hash}", "[a-f0-9]{" + hashLength + "}"), "i"); | ||
// Given a full path and a target directory, will return a hashed filename | ||
// of a file which corresponds to the original, based in targetDir. | ||
exports.getHashedFileName = function (fullPath, targetDir, hashCode) { | ||
var ext = path.extname(fullPath); | ||
var basename = path.basename(fullPath, ext); | ||
return { | ||
// Determines if a filename is a hashed (generated) path, or an original path | ||
isHashedFile: function (fileName) { | ||
return _hashedFileRegex.test(path.basename(fileName)); | ||
}, | ||
return path.join(targetDir, basename + "-hc" + hashCode + ext); | ||
}; | ||
// Given a full path and a target directory, will return a hashed filename | ||
// of a file which corresponds to the original, based in targetDir. | ||
getHashedFileName: function (fullPath, targetDir, hashCode) { | ||
var extname = path.extname(fullPath); | ||
var basename = path.basename(fullPath, extname); | ||
return path.join(targetDir, | ||
hashFormat | ||
.replace("{basename}", basename) | ||
.replace("{hash}", hashCode.substr(0, hashLength)) | ||
.replace("{extname}", extname)); | ||
} | ||
}; | ||
}; |
@@ -44,3 +44,3 @@ "use strict"; | ||
var hashCodeCoalesced = hashCode || hashcodeGenerator.generateForFile(fullPath, _options.quickhash); | ||
var hashedPathPhysical = hashpattern.getHashedFileName(fullPath, targetDir, hashCodeCoalesced); | ||
var hashedPathPhysical = _options.hashpattern.getHashedFileName(fullPath, targetDir, hashCodeCoalesced); | ||
var hashedPath = path.relative(targetBaseDir, hashedPathPhysical); | ||
@@ -68,3 +68,3 @@ | ||
// do not handle css inlined data | ||
if (virtualPath.startsWith("data:")) { | ||
if (virtualPath.substring(0, 5) === "data:") { | ||
return virtualPath; | ||
@@ -82,4 +82,4 @@ } | ||
var targetPath = path.resolve(targetDir, relativePath); | ||
return path.relative(path.dirname(targetPath), entry.hashedPathPhysical); | ||
return unixifyPath(path.relative(path.dirname(targetPath), entry.hashedPathPhysical)); | ||
} | ||
@@ -157,3 +157,3 @@ return entry.hashedPath; | ||
// If the file is already hashed, don't re-hash it | ||
if (hashpattern.isHashedFile(fullPath)) { | ||
if (_options.hashpattern.isHashedFile(fullPath)) { | ||
return; | ||
@@ -213,4 +213,5 @@ } | ||
} | ||
// | ||
var updatedSourcemapText = mapProcessor.processMinFile(ext, text, mapEntry.hashedPath, _options.sourcemapURLPrefix); | ||
// Rewrite the source map tag | ||
var sourcemapFile = _options.sourcemapIncludePath ? mapEntry.hashedPath : path.basename(mapEntry.hashedPath); | ||
var updatedSourcemapText = mapProcessor.processMinFile(ext, text, sourcemapFile, _options.sourcemapURLPrefix); | ||
fsutil.writeFileSync(entry.hashedPathPhysical, updatedSourcemapText, "utf8"); | ||
@@ -317,2 +318,3 @@ updatedSourcemapText = null; | ||
_options = options || {}; | ||
_options.sourcemapIncludePath = (typeof options.sourcemapIncludePath === "undefined") ? true : options.sourcemapIncludePath; | ||
_options.sourcemapURLPrefix = options.sourcemapURLPrefix || ""; | ||
@@ -356,2 +358,5 @@ _options.processMap = options.processMap || true; | ||
} | ||
// Initialize the hash generator | ||
_options.hashpattern = hashpattern.getHashPattern(_options.renameFormat, _options.hashLength); | ||
}; | ||
@@ -521,3 +526,3 @@ | ||
if (hashpattern.isHashedFile(filePath)) { | ||
if (_options.hashpattern.isHashedFile(filePath)) { | ||
deleteFileSync(filePath); | ||
@@ -553,3 +558,3 @@ } | ||
fsutil.recurseDirSync(directory, function(filePath) { | ||
if (hashpattern.isHashedFile(filePath)) { | ||
if (_options.hashpattern.isHashedFile(filePath)) { | ||
if (fileSet[filePath]) { | ||
@@ -556,0 +561,0 @@ return; |
@@ -13,4 +13,7 @@ usage: hashly [option option=parameter ...] <source> [destination] | ||
-e, --exclude A globbing expression. Any matching files will not be processed. Takes precedence over --include. | ||
-m, --manifest-format The format for the manifest file. Currently supports "json" or "tab" (tab delimited). | ||
Default is "json" | ||
--passthrough A globbing expression. Any matching files will be copied as-is to the destination folder. | ||
Has no effect if the destination is the same as the source. | ||
-m, --manifest-format The format for the manifest file. Currently supports "json", "json-object" (json with original | ||
path as key) or "tab" (tab delimited). | ||
Default is "json". | ||
-b, --base-dir Specifies the path to a folder. If specified, all paths included in the manifest will be | ||
@@ -23,9 +26,22 @@ prefixed with this path. | ||
without incurring the performance penalty of reprocessing existing files. | ||
-s, --skip-css Skip replacement of image paths in CSS files. If not specified, relative | ||
-s, --skip-css Skip replacement of image paths in CSS files. If not specified, relative | ||
(and root relative) image paths will be replaced with the hashed version. | ||
-q, --quickhash Use the file size for binary files instead of the file contents. This makes processing large binary | ||
files extremely quick, though at a (extremely slight) risk that a hashcode will not change when a | ||
files extremely quick, though at a (extremely slight) risk that a hashcode will not change when a | ||
file is updated. | ||
-l, --hash-length Specifies the length of the hash used when renaming files. Default is 32 characters. | ||
-f, --rename-format Specifies the format to use when renaming files. Variables are specified using curly brackets | ||
(e.g., {variable}). Any other characters are directly included in the output. | ||
Available variables include: | ||
- {basename}: the base filename without extension | ||
- {hash}: the hash value | ||
- {extname}: the file extension | ||
Default is "{basename}-hc{hash}{extname}". | ||
--ignore-errors Ignore errors. Otherwise, hashly will abort on the first error. | ||
--ignore-plugin-errors Ignore errors from plugins. Takes precedence over --ignore-errors. | ||
--disabled-plugins Semicolon-delimited list of plugin names that should be disabled. | ||
-c, --clean Deletes the manifest and all files generated by hashly | ||
--clean-old Deletes files that aren't in the manifest and are older than the specified number of days. | ||
--clean-old Deletes files that aren't in the manifest and are older than the specified number of days. | ||
--sourcemap-include-path Include the absolute path to the source map in the JS/CSS source, relative to base-dir. | ||
Default: true. | ||
--sourcemap-url-prefix A URL prefix to apply to the source map tag, if it is not in the same location as the source. |
{ | ||
"name": "hashly", | ||
"version": "0.4.10", | ||
"version": "0.5.0", | ||
"description": "Renames static files with a hashcode for cache busting", | ||
@@ -5,0 +5,0 @@ "directories": { |
hashly [![Build Status](https://secure.travis-ci.org/labaneilers/hashly.png?branch=master)](http://travis-ci.org/labaneilers/hashly) | ||
====== | ||
hashly is a build-time tool which enables cache-busting for static files (images, JavaScript, CSS, etc). | ||
hashly is a build-time tool which enables cache-busting for static files (images, JavaScript, CSS, etc). | ||
hashly copies a directory structure containing static files, inserting an MD5 hash code (based on the contents of the file) into each filename. It creates a manifest file which contains a mapping between the original and hashed file names, which can be used in web applications to map canonical file names to their specific, hashed URL. This way, when a file's content changes, its URL changes; this forces CDN, proxies, and browsers to download the new file, even if they had an old version cached. | ||
This is a particularly elegant solution which allows zero-downtime deployments, with backwards AND forwards compatibility between different versions of your web application and their corresponding static files. Filename-based cache busting is much more reliable than using other techniques (i.e. querystrings with version numbers, 304 HTTP codes), and allows you to cache aggressively without fear of not being able to update static files. | ||
This is a particularly elegant solution which allows zero-downtime deployments, with backwards AND forwards compatibility between different versions of your web application and their corresponding static files. Filename-based cache busting is much more reliable than using other techniques (i.e. querystrings with version numbers, 304 HTTP codes), and allows you to cache aggressively without fear of not being able to update static files. | ||
Hashly can also update references to images in CSS files so that they point to the renamed version. | ||
Hashly can also update references to images in CSS files and sourcemaps so that they point to the renamed version. | ||
@@ -18,3 +18,3 @@ Why hashly? | ||
You should configure your CDN to set HTTP headers to force your content to be cached for as long as possible. | ||
You should configure your CDN to set HTTP headers to force your content to be cached for as long as possible. | ||
@@ -47,7 +47,8 @@ Installation | ||
-e, --exclude A globbing expression. Any matching files will not be processed. Takes precedence over --include. | ||
--passthrough A globbing expression. Any matching files will be copied as-is to the destination folder. | ||
--passthrough A globbing expression. Any matching files will be copied as-is to the destination folder. | ||
Has no effect if the destination is the same as the source. | ||
-m, --manifest-format The format for the manifest file. Currently supports "json" or "tab" (tab delimited). | ||
Default is "json" | ||
-b, --base-dir Specifies the path to a folder. If specified, all paths included in the manifest will be | ||
-m, --manifest-format The format for the manifest file. Currently supports "json", "json-object" (json with original | ||
path as key) or "tab" (tab delimited). | ||
Default is "json". | ||
-b, --base-dir Specifies the path to a folder. If specified, all paths included in the manifest will be | ||
relative to this path. | ||
@@ -59,7 +60,15 @@ --manifest-path Specifies a path for the manifest file. If not specified, the manifest is named "manifest.{ext}" | ||
without incurring the performance penalty of reprocessing existing files. | ||
-s, --skip-css Skip replacement of image paths in CSS files. If not specified, relative | ||
-s, --skip-css Skip replacement of image paths in CSS files. If not specified, relative | ||
(and root relative) image paths will be replaced with the hashed version. | ||
-q, --quickhash Use the file size for binary files instead of the file contents. This makes processing large binary | ||
files extremely quick, though at a (extremely slight) risk that a hashcode will not change when a | ||
files extremely quick, though at a (extremely slight) risk that a hashcode will not change when a | ||
file is updated. | ||
-l, --hash-length Specifies the length of the hash used when renaming files. Default is 32 characters. | ||
-f, --rename-format Specifies the format to use when renaming files. Variables are specified using curly brackets | ||
(e.g., {variable}). Any other characters are directly included in the output. | ||
Available variables include: | ||
- {basename}: the base filename without extension | ||
- {hash}: the hash value | ||
- {extname}: the file extension | ||
Default is "{basename}-hc{hash}{extname}". | ||
--ignore-errors Ignore errors. Otherwise, hashly will abort on the first error. | ||
@@ -70,2 +79,5 @@ --ignore-plugin-errors Ignore errors from plugins. Takes precedence over --ignore-errors. | ||
--clean-old Deletes files that aren't in the manifest and are older than the specified number of days. | ||
--sourcemap-include-path Include the absolute path to the source map in the JS/CSS source, relative to base-dir. | ||
Default: true. | ||
--sourcemap-url-prefix A URL prefix to apply to the source map tag, if it is not in the same location as the source. | ||
``` | ||
@@ -88,2 +100,8 @@ | ||
Use a custom format and hash length for the renamed files: | ||
```shell | ||
hashly ./source ./processed -l 10 -f "{basename}.{hash}{extname}" | ||
``` | ||
Process all .css files in directory 'source' and copy hashed files to the 'processed' directory: | ||
@@ -121,3 +139,3 @@ | ||
------------------ | ||
hashly can also read the sizes of all image file formats (including jpeg, png, gif, bmp, tif, and webp) and add this data to the manifest file. This can be extremely useful for generating markup (server side) that contains image sizes. | ||
hashly can also read the sizes of all image file formats (including jpeg, png, gif, bmp, tif, and webp) and add this data to the manifest file. This can be extremely useful for generating markup (server side) that contains image sizes. | ||
@@ -124,0 +142,0 @@ Here's a sample of the type of semantics you could enable in your favorite markup-generating server-side language: |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
50907
911
177