Nub now applies a packageExtensions compatibility database to every install, repairing packages whose published code imports dependencies their own manifest never declares.
Important
Two package.json root fields changed, and one of them now errors. The top-level build allowlist is renamed allowBuilds → allowScripts, matching the map npm 12 reads from the same slot (npm/rfcs#868); a project still carrying a top-level allowBuilds is refused with ERR_NUB_ALLOW_BUILDS_RENAMED rather than warned, because honoring neither key would silently drop the map's explicit false denials. pnpm's own allowBuilds in pnpm-workspace.yaml or under package.json#pnpm is untouched. Separately, auditConfig, allowUnusedPatches and allowNonAppliedPatches are no longer read from the package.json root — no package manager reads any of the three there, and nub audit --ignore <id> already covers the audit case.
Dependency compatibility database
A package whose published code imports something its manifest never declares resolves under npm's flat node_modules — the upward directory walk finds a copy something else installed — and fails under an isolated layout. packageExtensions repairs the manifest at resolve time.
| Change | What it does | PR |
|---|---|---|
| Ecosystem catalogs applied | The vendored Yarn database plus pnpm's additions, 161 entries, were gated on the embedder being standalone aube, so Nub applied none of them. nub install && node -e 'require("reactcss")' failed with Cannot find module 'react'; it now resolves. |
#905 |
| Derived database bundled | Adds the machine-derived database published as @nubjs/extensions, produced by running Nub's phantom detector over the 10,000 most-downloaded packages. It is a strict superset of Yarn's. Of the 654 entries Yarn lacks, 25 add a hard dependencies edge and the rest are optional peers that install nothing and only repair strict layouts. |
#907 |
| Lockfile reuse on drift | A packageExtensions edit discarded the lockfile but still handed the old graph to the resolver as a reuse hint, so the edit rewrote the checksum, installed nothing and reported "Already up to date". The hint is now withheld on real drift. |
#906 |
Both layers are declined together by ignore-compatibility-db=true. Neither is read by the lockfile packageExtensionsChecksum, so a database refresh cannot drift a lockfile or abort a frozen install.
The nub export condition
Nub is a registered WinterTC runtime key, so a package can carry a nub branch in its exports map the way it carries bun or deno ones. Every CLI-augmented run now passes --conditions=nub to Node, alongside whatever the project declares in nub.jsonc or a tsconfig customConditions. Conditions are a set, so a package with no nub key resolves exactly as it does on plain Node.
Compat mode is unaffected: --node and NODE_COMPAT both skip the option builder entirely, so a compat run keeps Node's own condition set. The standalone @nubjs/loader also leaves the condition set alone, because its contract is that a file resolves identically under it, under tsx, and under plain Node. (#913)
Package manager
| Area | What changed | PR |
|---|---|---|
| pnpmfile | preResolution runs on every install and receives pnpm's lockfile shape |
#837 |
| npm lockfile | A link: directory dependency emits its link pair |
#848 |
| npm workspaces | Importer detection fixed, and afterAllResolved gets pnpm's lockfile shape |
#855 |
| Manifests | Duplicate package manifest fields are accepted rather than rejected | #718 |
| Manifests | package.json line endings and the EOF newline are preserved on write |
#583 |
| Lifecycle | Dependency lifecycle builds run in dependency order | #727 |
| Store | Remix 3 projects get a project-local store | #849 |
| Environment | Installs degrade gracefully inside coding-agent sandboxes | #854 |
Runtime
| Area | What changed | PR |
|---|---|---|
| Worker threads | --js-defer-import-eval is injected from the load hook instead of argv, and the argv-only flag signal now survives the worker-thread boundary — a Next.js 16 and Turbopack build died on the previous shape |
#856, #830 |
| Standalone loader | The CommonJS cache is preserved under standalone loader imports | #892 |
| Transpiler | Inspected source is reused for JavaScript lowering | #897 |
| Windows | Script-environment casing fix | #830 |
Startup
- The launcher probes the payload map instead of scanning it per directory (#903).
- A warm start stats the extracted tree in parallel (
611524e).
Internals
- The vendored engine syncs upstream aube v2.2.9, and
nub-climoves to usage-rs (#879). - The phantom detector that derives the extensions database no longer reports a package's own
baseUrlimports as phantoms (#895), walks legacy deep-path entry points for packages without an exports map (#891), fetches metadata from the abbreviated packument (#888), and records the file each phantom reference was found in (#910). - Dependencies deduped and the registry primer compacted (#851).
- Documentation copy pass across the docs site (#850).
- The docs runner section splits into top-level
nub runandnubxpages, with the four old URLs redirecting (#909). - The
nub agent docsslug test derives its page list from the docs tree, so a docs move no longer drags the Rust matrix onto a docs-only pull request (#911). - The
setup-nubGitHub Action documentation covers installing from the release archive and the shim input (38b1509).
What's Changed
- compile: cut compiled-artifact warm start roughly in half by @colinhacks in #846
- pnpmfile: run preResolution on every install and give it pnpm's lockfile shape by @colinhacks in #837
- compile: gate the --smol probe cache once per pass by @colinhacks in #853
- docs: de-slop pass over the docs site by @colinhacks in #850
- build: dedupe dependencies and compact the registry primer by @colinhacks in #851
- npm lockfile: emit the link pair for a
link:directory dependency by @colinhacks in #848 - pm: degrade gracefully inside coding-agent sandboxes by @colinhacks in #854
- compile: pre-v0.9 fixes and flags, plus the Windows script-env casing fix by @colinhacks in #830
- compile: drop a single-argument format! in the warn label by @colinhacks in #857
- runtime: turn on --js-defer-import-eval from the load hook instead of argv by @colinhacks in #856
- compile: add --hide-console for Windows GUI apps by @colinhacks in #858
- compile: scope --allow-dynamic-import with a glob by @colinhacks in #859
- compile: key the Node flag cache per binary instead of one flat map by @colinhacks in #862
- pm: fix npm workspace importer detection, and give afterAllResolved pnpm's lockfile shape by @colinhacks in #855
- Fix lat.md errors in anticipation of 0.13 by @1st1 in #805
- compile: add --icu to trim locales from the embedded Node by @colinhacks in #864
- compile: an error tier for the readout, and four defects the first embed build showed by @colinhacks in #860
- compile: run a pure-JavaScript artifact straight from the executable by @colinhacks in #866
- compile: make an extracted app's layout reachable from the code inside it by @colinhacks in #865
- pm: rename the neutral build allowlist to allowScripts by @colinhacks in #863
- ci: publish the macOS release binary the PR round-trip already builds by @colinhacks in #867
- pm: give Remix 3 projects a project-local store by @colinhacks in #849
- compile: accept a warm app cache by recorded length instead of by bytes by @colinhacks in #868
- pm: drop the three nub-only root install fields by @colinhacks in #871
- compile: let an inline payload past the synthesized manifest, and read V3 records by @colinhacks in #872
- compile: sign darwin-x64 output with a deterministic identifier by @colinhacks in #873
- compile: point the addon-mismatch advice at nub install's platform flags by @colinhacks in #874
- ci: give two dead rust-cache keys a writer and path-gate the docs-only builds by @colinhacks in #876
- ci: key concurrency groups on the event name so a push cannot cancel the nightly by @colinhacks in #877
- compile: bracket the summary block with an intro and a success line by @colinhacks in #880
- compile: split the output size by measured components by @colinhacks in #882
- release: build the canary nightly instead of on every push to main by @colinhacks in #881
- compile: drop
overheadfrom the output size row by @colinhacks in #883 - compile: skip eager builtin loads a payload never needs by @colinhacks in #878
- compile: cut the artifact's startup work before it reaches the app by @colinhacks in #884
- compile: build the default embed shape as a Node single-executable application by @colinhacks in #887
- nub-phantom: fetch metadata from the abbreviated packument, not /latest by @colinhacks in #888
- compile: keep an unconditional module.exports assignment CommonJS by @colinhacks in #889
- nub-phantom: walk legacy deep-path entry points for packages without an exports map by @colinhacks in #891
- compile: run a single-executable artifact before publishing it, and narrow the fork decline by @colinhacks in #890
- compile: flush the extracted app cache concurrently on first run by @colinhacks in #893
- aube: sync upstream v2.2.9 and move nub-cli to usage-rs by @colinhacks in #879
- docs: compile page + v0.9 announcement post by @colinhacks in #826
- fix: preserve CommonJS cache under standalone loader imports by @colinhacks in #892
- Accept duplicate package manifest fields by @colinhacks in #718
- compile: stop declining every source map from the containers that can carry one by @colinhacks in #894
- fix(pm): order dependency lifecycle builds by @colinhacks in #727
- build(sfw): bump to 1.15.1 and pin the musl and win-arm64 assets by @jdalton in #577
- fix(manifest): preserve package.json indent, line endings, and EOF newline by @afonsojramos in #583
- runtime: reuse inspected source for JavaScript lowering by @colinhacks in #897
- compile: retry the publish rename past the self-probe's Windows lock by @colinhacks in #898
- compile: run static workers inside the single-executable container by @colinhacks in #901
- compile: fix the module-cycle deadlock and add a CommonJS output shape by @colinhacks in #902
- nub-phantom: do not report a package's own baseUrl imports as phantoms by @colinhacks in #895
- compile: point an unresolved native addon at --unbundled by @colinhacks in #904
- launcher: probe the payload map instead of scanning it per directory by @colinhacks in #903
- pm: apply the bundled compatibility database under nub by @colinhacks in #905
- pm: withhold lockfile reuse when packageExtensions drift by @colinhacks in #906
- pm: bundle the phantom-derived packageExtensions database by @colinhacks in #907
- nub-phantom-scan: record the file each phantom reference was found in by @colinhacks in #910
- agent: derive the baked-docs test from the tree; key the bake on docs content by @colinhacks in #911
- docs: split the runner section into top-level run and nubx pages by @colinhacks in #909
- runtime: set the
nubexport condition on augmented runs by @colinhacks in #913
New Contributors
Full Changelog: v0.8.3...v0.9.0