connect-static-file

raw JSON →
2.0.0 verified Thu Apr 23 auth: no javascript maintenance

connect-static-file is a lightweight middleware for Connect and Express applications designed to serve a single static file. Unlike `express.static` which serves entire directories, this module focuses on efficiently delivering a specified file, making it ideal for specific assets like `index.html` or a `robots.txt`. The current stable version is 2.0.0, with its last major update occurring in 2017, suggesting a low-cadence, maintenance-focused project. A key differentiator is its `encoded` option, allowing developers to serve pre-compressed files (e.g., gzip) directly, optimizing client delivery by avoiding on-the-fly compression. It also provides fine-grained control over HTTP caching headers like `ETag`, `Last-Modified`, and `Cache-Control` (`maxAge`).

error Error: ENOENT: no such file or directory, stat '/path/to/non-existent-file.txt'
cause The `path` argument provided to `staticFile()` does not point to an actual file that exists on the filesystem.
fix
Verify that the file path argument in staticFile('/your/path', ...) is correct and the file exists at that location with proper read permissions for the Node.js process.
error Cannot GET /my-asset (HTTP 404 response)
cause The route path (e.g., `/my-asset`) used with `app.use()` does not match the incoming request URL, or no fallback is provided for `encoded` files when the client doesn't support the encoding.
fix
Ensure the URL path provided to app.use('/your-url', staticFile(...)) exactly matches the path clients are requesting. If using the encoded option, verify a non-encoded fallback middleware is provided immediately after the encoded version for browsers that don't support the encoding.
error Client receives uncompressed file despite `encoded: 'gzip'` in configuration, or `Content-Encoding` header is missing/incorrect.
cause The client's `Accept-Encoding` header does not include 'gzip', or the middleware order is incorrect, causing a fallback to be hit prematurely, or the `encoded` option is misspelled.
fix
Confirm the client's Accept-Encoding header. If it includes 'gzip', ensure your middleware order is correct with the encoded version preceding any unencoded fallback for the same route. Double-check the spelling and value of the encoded option.
breaking Version 2.0.0 removed support for Node.js v0.10. If you are on an older Node.js runtime, you must use `connect-static-file@1.x`.
fix Upgrade Node.js to a supported version (>=0.12) or downgrade to `connect-static-file@1.x` if you must use Node.js v0.10.
breaking Version 2.0.0 removed the `acceptRanges` option, which was previously enabled by default. This change should have minimal impact as the option offered little value.
fix Remove the `acceptRanges` option from your configuration if present, as it is no longer supported.
gotcha When using the `encoded` option (e.g., `encoded: 'gzip'`), `connect-static-file` will only serve the pre-encoded file if the client's `Accept-Encoding` header supports it. If not, the request is passed to the next middleware. You MUST implement a fallback middleware to serve an unencoded version or an alternative encoding if the client doesn't support the specified `encoded` type.
fix Always include a fallback middleware for the unencoded file immediately after the `encoded` version for the same route, e.g., `app.use('/bundle.js', staticFile('bundle.js.gz', {encoded: 'gzip'})); app.use('/bundle.js', staticFile('bundle.js'));`.
gotcha This middleware is designed to serve a *single* specific file per instance. It does not perform directory lookups or serve multiple files based on a path segment. Attempts to use it like `express.static` for entire directories will fail.
fix For serving entire directories of static assets, consider using `express.static`, `connect-gzip-static`, or `ecstatic`.
gotcha The `extensions` option is disabled by default (`false`) and is ignored if the requested URL already includes a file extension. It only applies if the initial file `path` cannot be found and the URL has no explicit extension (e.g., `/my-page` rather than `/my-page.html`).
fix Ensure `extensions` is explicitly set to an array (e.g., `['html', 'htm']`) if you want to use it for extension-less URLs. Remember it won't affect requests for URLs that already specify an extension.
npm install connect-static-file
yarn add connect-static-file
pnpm add connect-static-file

This quickstart demonstrates how to set up an Express server to serve a single text file and a pre-gzipped JavaScript bundle using `connect-static-file`, including a fallback for browsers that don't support gzip. It shows basic caching and custom header options.

const express = require('express');
const staticFile = require('connect-static-file');
const path = require('path');
const fs = require('fs');

const app = express();
const port = 3000;

// Create a dummy file for the example
const dummyFilePath = path.join(__dirname, 'hello.txt');
fs.writeFileSync(dummyFilePath, 'Hello from connect-static-file!');

// Serve the dummy file at /hello.txt
app.use('/hello.txt', staticFile(dummyFilePath, {
  maxAge: '1d', // Cache for 1 day
  headers: { 'X-Powered-By': 'connect-static-file' }
}));

// Serve a pre-gzipped version of a bundle if supported, with a fallback
const gzippedBundlePath = path.join(__dirname, 'bundle.js.gz');
const unzippedBundlePath = path.join(__dirname, 'bundle.js');
fs.writeFileSync(unzippedBundlePath, 'console.log("This is the uncompressed bundle.");');
// In a real app, you'd generate gzippedBundlePath via a build step
fs.writeFileSync(gzippedBundlePath, Buffer.from('\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xcbH\xcd\xc9\xc9W(\xcf/\xcaIQ\x04\x00\x9d\x1a\xa0*\x1e\x00\x00\x00', 'binary')); // Minimal gzip for 'Hello'

app.use('/bundle.js', staticFile(gzippedBundlePath, { encoded: 'gzip', maxAge: '7d' }));
app.use('/bundle.js', staticFile(unzippedBundlePath, { maxAge: '7d' })); // Fallback


app.listen(port, () => {
  console.log(`Server listening at http://localhost:${port}`);
  console.log(`Try accessing: http://localhost:${port}/hello.txt`);
  console.log(`Try accessing: http://localhost:${port}/bundle.js (will serve gzip if supported by browser)`);
});

// Cleanup dummy files on process exit
process.on('exit', () => {
  fs.unlinkSync(dummyFilePath);
  fs.unlinkSync(gzippedBundlePath);
  fs.unlinkSync(unzippedBundlePath);
});