firebase / firebase/superstatic
Replace update-notifier-cjs with a zero-dependency equivalent (removes 46 packages)
- Dominant language
- TypeScript
- Stars
- 1.1k
- Forks
- 88
- Avg merge
- 17h 43m
- Merged PRs (30d)
- 2
Description
`update-notifier-cjs` pulls 46 packages into superstatic's dependency tree to check
whether a newer version has been published. That is 46 packages to resolve, audit and
trust, in service of one request to the registry and a box drawn on stderr. It is also
a fork that exists only because upstream `update-notifier` went ESM-only, and its last
release was January 2025.
I would like to propose replacing it with `nano-update-notifier`, which implements the
same public API — same options, same `notifier.update` shape, same suppression rules —
on Node.js built-ins alone, with no runtime dependencies. It ships both ESM and CommonJS
entry points, so the existing `require` keeps working.
The change is two lines: the manifest entry, and
```diff
-const updateNotifier = require("update-notifier-cjs");
+const updateNotifier = require("nano-update-notifier");
```
in `src/bin/server.ts`.
## Measured
Against `nano-update-notifier@1.1.0` at superstatic `4bd82b9`, on Node 22.14.0 and
npm 10.9.2. Every row is a real run — `npm ci` on a clean checkout, then the two-line
change, then `npm install`:
| | |
| --- | --- |
| Dependency delta | **`added 1 package, and removed 46 packages`** — npm's own words. 536 installed entries down to 491 |
| `npm run build` | clean, exit 0 |
| `npm run lint` | 994 problems, 0 errors — identical to the same run before the change |
| `npm run test-unit` | 181 passing, 10 pending, 19 failing — identical to the run before the change, and the set of failing test titles diffs empty against it |
Those 46 entries are 39 distinct package names. Five of them — `camelcase`,
`graceful-fs`, `semver`, `strip-json-comments` and `type-fest` — are nested copies whose
name survives elsewhere in the tree, and `ini` goes from three paths at once. I lead
with 46 because that is what `npm install` prints; the 39 below is the list of names.
The 19 failures are pre-existing on my machine, all `trailing slash` cases, which look
like Windows path handling rather than anything related to this change. What matters is
that the swap does not move them.
The 39 names: `@pnpm/config.env-replace`, `@pnpm/network.ca-file`, `@pnpm/npm-conf`,
`ansi-align`, `boxen`, `ci-info`, `cli-boxes`, `config-chain`, `configstore`,
`crypto-random-string`, `deep-extend`, `dot-prop`, `escape-goat`, `global-dirs`,
`has-yarn`, `import-lazy`, `ini`, `is-ci`, `is-installed-globally`, `is-npm`, `is-obj`,
`is-yarn-global`, `isomorphic-fetch`, `minimist`, `node-fetch`, `proto-list`, `pupa`,
`rc`, `registry-auth-token`, `registry-url`, `semver-diff`, `tr46`, `unique-string`,
`update-notifier-cjs`, `webidl-conversions`, `whatwg-fetch`, `whatwg-url`,
`widest-line`, `xdg-basedir`.
## The rendered notification is not byte-identical, and here is exactly how
I rendered the notification through superstatic's own call — `updateCheckInterval` of
one week, `shouldNotifyInNpmScript: true` — under both libraries and diffed the output.
Eight lines on each side. Lines 2 through 7, the borders, the padding and both text
lines, are byte-identical. Lines 1 and 8 are the blank margin lines, and they differ:
- `update-notifier-cjs` renders through boxen 5, which emits a yellow-open escape
immediately followed by a yellow-close on those lines.
- `nano-update-notifier` replicates boxen 7, which emits nothing.
Each of those two lines is 10 bytes under `update-notifier-cjs` — the escape pair
`ESC[33m` `ESC[39m` with nothing between them — and 0 bytes here, so the whole output
differs by 20 bytes and nothing else. On the run I measured that was 601 bytes against
581. Both render as a blank line in any terminal, and stripping ANSI makes the two
byte-equal. I would rather state that than claim an equality I cannot support.
## How compatibility is held
Differential test suites run `update-notifier`, `boxen`, `wrap-ansi`, `semver` and
`string-width` as oracles: the full box option matrix, notification rendering with
colour enabled, ANSI-aware wrapping, and fuzzed version comparison. 300 tests, green on
Ubuntu, Windows and macOS across Node 18, 22 and 24. The package is published from a
GitHub Actions release through npm trusted publishing, with SLSA provenance attached.
## Not verified
`test-integration`, and any run on Linux or macOS — I measured on Windows.
## Two things worth raising
**Disclosure: I wrote `nano-update-notifier`.** That is why this is an issue rather than
a pull request. CONTRIBUTING asks for discussion before a larger contribution, and a
proposal to adopt my own package deserves that more than most. If this is not something
you want to take on, saying so costs you nothing and I will not push it.
I understand the Google CLA is needed before anything can merge, and I am happy to sign
it. CONTRIBUTING notes it is not required until after review, so I am raising the idea
first rather than signing speculatively.
Contributor guide
Research direction
Review the manifest entry and the existing require call in src/bin/server.ts, then compare nano-update-notifier's API with the current usage. Run npm ci followed by npm run build, npm run lint, and npm run test-unit; done means the dependency tree loses the reported packages and the existing build, lint, and test results do not regress.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- backend, tooling
- Issue type
- Refactor
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 65/100