npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

hashmark

v5.0.0

Published

Take contents of a file (or stdin), and output as new file with a hash in the name

Downloads

1,685

Readme

HashMark

Build Status

HashMark is a small utility which takes a file (or sdtin) as input, and writes the contents of the input to a file named with a hash digest of the file. This is useful for cache busting sticky caches - files can have far future expires headers and when the code changes, a new filename is created.

Examples:

Shell

cat file.js | ./bin/hashmark 'file.{hash}.js' # Writes to test.3eae1599bb7f187b86d6427942d172ba8dd7ee5962aab03e0839ad9d59c37eb0.js
> Computed hash: 3eae1599bb7f187b86d6427942d172ba8dd7ee5962aab03e0839ad9d59c37eb0
>
cat file.js | ./bin/hashmark -l 8 'file.{hash}.js' # Writes to test.3eae1599.js
> Computed hash: 3eae1599
>
cat file.js | ./bin/hashmark -l 4 -d md5 'dist/{hash}.js' # Writes to dist/cbd8.js
> Computed hash: cbd8
>

It is useful to use globs — meaning you can read in many files and it will output hashed versions of each:

./bin/hashmark path/to/*.js 'dist/{name}.{hash}.js'
./bin/hashmark path/to/{filea,fileb,filec}.js 'dist/{name}.{hash}.js'
./bin/hashmark **/*.js 'dist/{dir}/{name}.{hash}.js'
./bin/hashmark **/*.{js,css} 'dist/{dir}/{name}.{hash}{ext}'
./bin/hashmark **/*.{js,css} 'dist/{dir}/{hash}-{base}'

The above even works in shells that do not support globs (such as cmd.exe on Windows), because hashmark has support for expanding globs itself. Note that if your shell supports the * glob but not the ** glob (such as bash before version 4), the shell will interpret ** as two * in a row, which means that hashmark never receives the ** and therefore cannot expand it. In that case you need to quote your argument. Therefore, if you want to write cross-platform scripts it is best to always quote the args:

Available pattern keys includes all the keys returned by path.parse(filename) and hash (ie: hash, root, dir, name, base, ext).

./bin/hashmark 'dir/**/*.{js,css}' 'test/*.js' 'dist/{dir}/{name}.{hash}{ext}'

The hashmark command will output some JSON to stdout with a map of filenames and their new hashes, meaning you can pipe the hash to other programs. To make hashmark completely silent - simply pass the --silent or -s flag.

./bin/hashmark -l 4 file.js 'dist/{hash}.js' --silent

You can also output the JSON map to a file, by passing the --asset-map or -m flag. It will still be logged to stdout unless you pass --silent

./bin/hashmark -l 4 file.js 'dist/{hash}.js' --asset-map assets.json

You can specify from which directory to work from with --cwd or -c. Note: asset-map will be relative to this directory.

mkdir dist/subdir
echo 'abracadabra' > dist/subdir/file.js
./bin/hashmark --cwd dist -d md5 -l 8 '**/*.js' '{dir}/{name}-{hash}{ext}'
> {"subdir/file.js":"subdir/file-97640ef5.js"}

Integrations

replaceinfiles

Now that your assets have been renamed, you might want to update references to them in some other files (ex:background image reference in your css files). That's exactly what replaceinfiles is made for. Just pipe it to hashmark. It just work™. Full example.

Programmatically

The hashmark function can be used programmatically. You can pass it a String, Buffer or Stream as the first argument, an options object as the second argument, and a callback as the third.

The callback receives an error as the first argument (or null) and an object which maps each given file to the newly hashed file name.

var hashmark = require('hashmark');
var file = fs.createReadStream('file.js');

hashmark(file, { length: 8, digest: 'md5', 'pattern': '{hash}'}, function (err, map) {
    console.log(map);
});

The function also returns an event emitter which emits error, file and end events. File events get fired when an individual file has been hashed, and the end event is fired when all have been done. file is given two arguments - the files old name, and the new calculated filename (given the template string), and the end event is given an object mapping of all files.

var hashmark = require('hashmark');
var file = fs.createReadStream('file.js');

hashmark(file, { length: 8, digest: 'md5', pattern: 'hash'})
    .on('file', function (oldFileName, newFileName) {
        console.log('File hashed!', oldFileName, newFileName);
    })
    .on('end', function (jsonMap) {
        console.log('~FIN');
    })

Files can be a single Stream, or filename String, or an Array of Streams and/or filename Strings.

var hashmark = require('hashmark');
var file = fs.createReadStream('file.js');

hashmark([file, 'file2.js'], { length: 8, digest: 'md5', file: 'file.#.js'}, function (err, hash) {
    console.log('File written to file.' + hash + '.js');
    console.log(hash);
});

Contributing

This is such a small utility - there's very little point in contributing. If it doesn't do something that you really think it should, feel free to raise an issue - just be aware I might say no. If you can make it faster/better/stronger without changing the API/functionality then send a PR!