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

ucdn

v0.22.0

Published

A µcompress based CDN utility, compatible with both Express and native http module

Downloads

1,143

Readme

µcdn

Build Status Coverage Status

delivering packages

Social Media Photo by Eduardo Casajús Gorostiaga on Unsplash

A ucompress based utility that accepts a configuration object with a source path, an optional dest, which fallbacks to the temp folder, plus eventually extra headers property to pollute headers via allow-origin among other details.

📣 Community Announcement

Please ask questions in the dedicated forum to help the community around this project grow ♥


Example

The following example will serve every file within any folder in the source directory, automatically optimizing on demand all operations, including the creation of brotli, gzip, or deflate.

import {createServer} from 'http';
import {join} from 'path';

import umeta from 'umeta';
const {dirName} = umeta(import.meta);

import ucdn from 'ucdn';
const callback = cdn({
  cacheTimeout: 1000 * 60, // 1 min cache
  source: join(dirName, 'source'),
  // dest: join(dirName, 'dest')
});

createServer(callback).listen(8080);

The callback works with Express too, and similar modules, where all non existent files in the source folder will be ignored, and anything else will execute regularly.

const {join} = require('path');

const express = require('express');
const ucdn = require('ucdn');

const app = express();
app.use(ucdn({
  source: join(__dirname, 'source'),
  dest: join(__dirname, 'dest')
}));
app.get('/unknown', (req, res) => {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('OK');
});
app.listen(8080);

As binary file

It is possible to bootstrap a micro CDN right away via npx ucdn. Pass --help to see options.

The --verbose output

If started via --verbose flag, each request will be logged producing the following output example:

200 XXms /full/path.html.gzip

404 /full/nope.html

200 /favicon.ico

404 /full/nope.html

304 /full/path.html.gzip

500 /full/error-during-compression

Please note that 200 is the file status in the cdn, not the response status for the browser. The status indeed indicates that the file wasn't known/compressed yet, and it took Xms to be generated.

On the other hand, whenever a file was already known, it will be served like a 304 as the cdn didn't need to perform any operation.

Basically, the status reflects the cdn and not whenever a browser is requesting new content or not.

About API

If ucdn is started with an --api ./path flag, files in that folder will be used as fallback.

The API folder does not need to be reachable, or included, within static assets (source).

// @file ./api/hello.js
// @start ucdn --api ./api --source ./public

const headers = {'content-type': 'text/html;charset=utf-8'};

// export a function that will receive
// the request and response from the server
module.exports = (req, res) => {
  res.writeHead(200, headers);
  res.end('<h1>Hello API!</h1>');
};

Please note that currently, and for the time being, files in API folder must be CommonJS compatible, and with a .js extension.

If your project uses ESM instead, remember to put {"type":"commonjs"} inside the ./api/package.json file.

Performance

Differently from other solutions, the compression is done once, and once only, per each required static asset, reducing both RAM and CPU overhead in the long run, but being a bit slower than express static, with or without compressed outcome, in the very first time a file, that hasn't been optimized yet, is requested.

However, once each file cache is ready, µcdn is 1.2x, up to 2.5x, faster than express with static and compress, and it performs specially well in IoT devices that are capable of running NodeJS.

About cacheTimeout

The purpose of this module is to do the least amount of disk operations, including lightweight operations such as fs.stat(...) or fs.readFile(...). There are also heavy operations such the runtime compression, which should be guarded against concurrent requests.

In order to do so, µcdn uses an internal cache mechanism that avoid checking stats, parsing JSON, or compressing missing or updated assets during this timeout, which is by default 1000 milliseconds.

If you pass a timeout with value 0, it will never check ever again anything, and all JSON headers and stats results will be kept in RAM until the end of the program, unless some file is missing, or some error occurs.

In every other case, using a minute, up to 10 minutes, as cache timeout, is rather suggested.

Compatibility

Beside own dependencies that might have different compatibility requirements, this module works in NodeJS 10 or higher.