A modest express.js middleware to locally cache assets (images, videos, audio, etc.) for faster access and proxying, for use in e.g. Electron apps.

For offline use of dynamic assets, e.g. in your Electron app or local express server.

Usage

const express = require ( " express " ) ; const fileCacheMiddleware = require ( " express-asset-file-cache-middleware " ) ; const app = express ( ) ; app . get ( " /assets/:asset_id " , async ( req , res , next ) => { res . locals . fetchUrl = ` https://cdn.example.org/path/to/actual/asset/ ${ req . params . asset_id } ` ; res . locals . cacheKey = ` ${ someExpirableUniqueKey } ` ; next ( ) ; } , fileCacheMiddleware ( { cacheDir : " /tmp " , maxSize : 10 * 1024 * 1024 * 1024 } ) , ( req , res ) => { res . set ( { " Content-Type " : res . locals . contentType , " Content-Length " : res . locals . contentLength } ) ; res . end ( res . locals . buffer , " binary " ) ; } ) ; app . listen ( 3000 ) ;

It works by fetching your asset in between two callbacks on e.g. a route, by attaching a fetchUrl onto res.locals . When the asset isn't cached on disk already, it will write it into a directory specified by the option cacheDir . If it finds a file that's alread there, it will use that.

The asset's contentType and contentLength are stored base64 encoded in the filename, thus no offline database is necessary

Note that setting cacheKey and cacheDir isn't strictly necessary, it will fall back to res.local.fetchUrl and path.join(process.cwd(), "/tmp") , respectively.

LRU Eviction

To avoid cluttering your device, an LRU (least recently used) cache eviction strategy is in place. Per default, when your cache dir grows over 1 GB of size, the least recently used (accessed) files will be evicted (deleted), until enough disk space is available again. You can change the cache dir size by specifying options.maxSize (in bytes) when creating the middleware.

Install

$ npm install express-asset-file-cache-middleware

or

$ yarn add express-asset-file-cache-middleware

API

Input

The URL of the asset to cache.

A unique, expireable cache key. If your asset contains a checksum/digest, you're already done, because it falls back to res.locals.fetchUrl .

Output

To further process the response, the following entries of res.locals are set:

The cached asset as a binary buffer. Most likely, you will end the request chain with

res . end ( res . locals . buffer , " binary " ) ;

res.locals.contentType and res.locals.contentLength

If you're serving your assets in the response, you'll need to set

res . set ( { " Content-Type " : res . locals . contentType , " Content-Length " : res . locals . contentLength } ) ;

Options

You can pass the following options to the middleware:

cacheDir (optional)

The root directory where the file cache will be located. Falls back to path.join(process.cwd(), "/tmp") .

logger (optional)

A logger to use for debugging, e.g. Winston, console, etc.

maxSize (optional)

The maximum size of the cache directory, from which LRU eviction is applied. Defaults to 1 GB (1024 * 1024 * 1024).

Tests

Run the test suite:

$ npm install $ npm test

License

The MIT License (MIT)

Copyright (c) 2019 Julian Rubisch

Contributors ✨

Thanks goes to these wonderful people (emoji key):

This project follows the all-contributors specification. Contributions of any kind welcome!