Repository navigation
Nub 0.11.0 preloads TypeScript 7.1 content mappers, adds nub add --save-types, installs one copy of a package where pnpm does, and removes the canary channel. It also fixes a broad set of correctness bugs in the runtime, the package manager and nub run.
Important
Five changes can surface in an existing project:
- The canary channel is gone.
nub upgrade --canaryand--stableare unknown flags, andinstall.shandinstall.ps1no longer acceptcanary. An existing canary install keeps working, andnub upgrade --stablestill moves it to a release (#1102) - A lockfile missing a required entry is broken.
nub ciandnub install --frozen-lockfileexit 16 and name the entry, and a plainnub installrepairs it. Both exited 0 and left a tree that could not load (#1105) nub add <pkg>@<tag>saves a prerelease exact, as pnpm does. A stable tag still saves with^(#1096)- Some lockfiles change once. A local or URL package keeps its peers on its key, and a tree that held duplicate copies of a package collapses them on its next fresh resolve (#1093, #1089)
- The first install after upgrading relinks once, because the dependency scan's cache was reset (#1113)
Content mappers
TypeScript 7.1's content mappers type-check other file types, but TypeScript never runs them. Nub now preloads the ./register export of every package the tsconfig lists, with no --import and no nub.jsonc entry (#1082).
import config from "./config.yaml"; // loaded by motherload/registerextends and references are followed, the longest extension answers first, and an entry's options reach its register in CONTENT_MAPPER_OPTIONS.
Type packages on add
nub add --save-types <pkg> also saves the DefinitelyTyped package to devDependencies for each registry package whose installed version ships no types, picking the newest @types release on that package's major (#1110, fixes #1016).
nub add --save-types expressA package with no @types release, or only a deprecated stub, prints skipped @types/<name>: <reason>. An @types entry the project already lists is kept.
Package manager
| Area | What changed | Link |
|---|---|---|
| Duplicate copies | A package installs once where pnpm installs it once. The Nuxt starter went from 17 duplicate copies to 0, and workspace members no longer get two module objects for one package. | #1089 |
| Peers of local packages | A file:, URL or git package consumed with two sets of peers loads the right peer after a lockfile install. One entry served both consumers, with no error. |
#1093 |
| Edges to workspace members | A registry package whose peer a workspace member satisfies links to the member, as pnpm writes it. The install succeeded and require failed with Cannot find module. |
#1081 |
| Local packages from a pnpm lockfile | file: and link: packages read back from nub.lock or pnpm-lock.yaml get the graph a fresh resolve gives. A root peer pinned to a tarball URL no longer fails every resolve after the first with ERR_NUB_BLOCKED_EXOTIC_SUBDEP. |
#1072, #1109, fixes #1108 |
| Failed adds | A failed nub add or nub install <pkg> restores package.json, the lockfiles and the workspace yaml. The new dependency stayed in package.json. |
#1111 |
--fix-lockfile |
nub install --fix-lockfile rewrites the lockfile, keeping its pinned versions. It repairs a package-lock.json written with the dev-optional flags 0.10.0 fixed. |
#1091, refs #1087 |
bun.lock local paths |
A member's file: directory and a hoisted tarball install under nub ci and --frozen-lockfile, and a bun.lock Nub writes spells local packages as bun does, which bun install --frozen-lockfile accepts. |
#1112 |
| Filtered installs | nub install --prod, --dev and --no-optional download only the dependencies they link. Every package in the graph was downloaded into the store. |
#1121, fixes #1120 |
pnpm-workspace.yaml |
A # comment after a pattern or after packages:, and the flow form packages: ['a/*', 'b/*'], are read. Each found no workspace members. |
#1113 |
Repeated .npmrc keys |
The last script-shell, ignore-scripts or node-mirror:release wins, as in npm. The first won. |
#1113 |
packageManager paths |
A version that walks out of its package, such as pnpm@../npm/10.9.0, fails to resolve. It installed the other package into the store under the requested name. |
#1113 |
nub pm use |
nub pm use nub keeps catalog and nohoist from an object-form workspaces, and nub pm use pnpm keeps the other keys under workspaces. |
#1113 |
| Dependency scan | require('buffer/'), a directory with a main, a template-literal require and import x = require() resolve as Node resolves them, and .d.mts and .d.cts files are not scanned. |
#1113 |
Running files
| Area | What changed | Link |
|---|---|---|
| Node's permission model | nub --permission --allow-addons app.js starts, --permission in NODE_OPTIONS gets the same --allow-addons message as the flag, and the last of --permission and --no-permission decides, as in Node. The first two failed with ERR_ACCESS_DENIED on Nub's own runtime. |
#1113 |
| Flags after the entry | nub app.js --permission passes --permission to the program. It was read as Node's own flag. |
#1113 |
.env |
PASSWORD="foo\$bar" loads foo$bar, and a variable that refers back to itself, such as A=x$A, expands that reference to nothing. |
#1113 |
| Node version pins | engines.node: "20.11.0 || 22.1.0" matches those exact versions, a v in a range is read as node-semver reads it, and a # comment in .nvmrc or .node-version is read as nvm reads it. |
#1113 |
| tsx as a loader | --import tsx runs on Node 24.11.1, 25.0 and 25.1. It failed with ERR_METHOD_NOT_IMPLEMENTED. |
#1113 |
| Native addon | A panic in Nub's addon throws a catchable error. It aborted the process. | #1113 |
nub node install |
With Nub's node shim on PATH, it installs only the version asked for. |
#1113 |
| Home-folder projects | A stray package.json and node_modules in the home folder no longer hang every run under it on macOS. The pre-run dependency scan skips a project rooted at the home folder and gives up after 500 ms. |
#1117 |
| Windows scripts | Script bodies and lifecycle scripts keep backslashes in environment values, so os.homedir() reads C:\Users\… inside a script and Nub's preload is injected once. |
#1107 |
Runtime
| Area | What changed | Link |
|---|---|---|
| Node 27 language changes | Intl.Locale#variants is polyfilled and typed in @nubjs/types. Iterator.zip and Iterator.zipKeyed close every input on an early return or a failure. On Node 27, its native versions of these are used. A Test262 subset now runs against the polyfills. |
#1097 |
| Polyfill shapes | Promise.withResolvers, Iterator.from, URL.parse, the Uint8Array base64 methods and 23 others have no prototype and refuse new, like the builtins. Float16Array and URLPattern are non-enumerable, RegExp.escape escapes lone surrogates, and ErrorEvent before Node 25 reads its fields from prototype getters. |
#1113 |
| Replaced built-ins | Nub's runtime helpers keep working after application code replaces a global or a prototype method. | #1099 |
--experimental-web-worker |
With Node's own Worker global enabled, Nub keeps it and its worker scope instead of installing its polyfill. |
#1098 |
Worker |
nub --max-old-space-size=4096 app.mjs no longer makes the global Worker throw ERR_WORKER_INVALID_EXEC_ARGV, and a worker that throws null delivers its error event. |
#1106, #1113 |
A foreign registerHooks |
On Node 22.15 to 24.11, an --import that calls module.registerHooks, such as amaro/strip, no longer makes every CommonJS file throw ERR_INVALID_RETURN_PROPERTY_VALUE. |
#1101 |
Scripts and config
| Area | What changed | Link |
|---|---|---|
nub exec -r |
A shell-script bin runs in each member's directory. It ran in the invoking directory. | #1113 |
--sequential, --parallel |
A regex run outside any workspace runs that package's scripts, as pnpm 9, 10 and 11 do. | #1113 |
| Flags before the verb | --cwd=<dir>, --if-present and --reporter-hide-prefix are accepted there. They failed with node: bad option. |
#1113 |
PATH |
An entry that is not UTF-8 no longer leaves scripts with an empty PATH. |
#1113 |
nub config set |
Writes through a symlinked nub.jsonc instead of replacing the link. |
#1113 |
nub init |
Skips git init in a subfolder of a repository. |
#1113 |
nubx prompt |
Answering Never beside dlx.consent: "prompt" stays off. |
#1113 |
Install and upgrade
| Area | What changed | Link |
|---|---|---|
| Canary channel | Removed, with nub upgrade --canary and --stable. nub-version: canary in the setup-node action no longer installs. |
#1102 |
install.sh |
Detects musl through ldd on systems other than Alpine. |
#1113 |
setup-node action |
Reads .tool-versions and an absolute package.json as a node-version-file, and .nvmrc and .node-version as nvm reads them. |
#1113 |
Security
Nub's Rust network clients reject the compromised eMudhra certificate chains (#1019). JavaScript running under Node still relies on Node's own certificate store.
Docs, testing and internals
- The repository has a
CONTRIBUTING.md, aSECURITY.mdand a code of conduct (#1116, #1115). - The test suite runs on Node 26 (#1020), and the version-tier tests install the Node versions they skipped without (#1114).
- The integration tests find the
nubbinary through Cargo, which keeps test executables in a different directory from Rust 1.100 (#1113). - Seven slower pull-request workflows run on a
ci-fulllabel (#1104). - Releases build with the current stable Rust (
86c1817).
What's Changed
- pm: install one copy of a package where pnpm does by @colinhacks in #1089
- compile: resolve each --external from the module that imported it by @colinhacks in #1092
- lockfile: read local packages back from a pnpm lockfile as a fresh resolve stores them by @colinhacks in #1072
- release: retry release-asset reads while reconciling by @colinhacks in #1095
- pm: save a prerelease dist-tag exact on add by @colinhacks in #1096
- pm: give a registry package's edge to a workspace member a package to land on by @colinhacks in #1081
- lockfile: keep a local or URL package's peers on its key by @colinhacks in #1093
- test: migrate script units to erasable TypeScript and pinned tsrs checks by @jdalton in #1100
- runtime: preserve native Web Workers and avoid fallback Blob copies by @jdalton in #1098
- runtime: use captured built-ins in shared CJS helpers by @jdalton in #1099
- pm: accept --fix-lockfile on nub install by @colinhacks in #1091
- release: remove the nightly canary and the canary channel by @colinhacks in #1102
- runtime: align polyfills with Node 27 Alpha and add Test262 coverage by @jdalton in #1097
- runtime: keep CommonJS loading under a foreign registerHooks on the async tier by @colinhacks in #1101
- ci: move seven slower workflows behind a ci-full label by @colinhacks in #1104
- compile: name a store package by the package in regions and source maps by @colinhacks in #1103
- compile: give untraced workers the compiled worker scope by @colinhacks in #1106
- pm: treat a lockfile missing a required entry as broken by @colinhacks in #1105
- runtime: preload ./register for tsconfig contentMappers packages by @colinhacks in #1082
- run: start the Windows script shell with busybox -X by @colinhacks in #1107
- resolver: test a peer the root pins to a URL across lockfile reuse by @colinhacks in #1109
- pm: restore package.json and the lockfile when an add fails by @colinhacks in #1111
- fix(deps): distrust compromised eMudhra certificate chains by @jdalton in #1019
- pm: add --save-types to nub add by @abappi19 in #1110
- ci: run the test suite on Node 26 by @jdalton in #1020
- pm: read and write bun.lock local paths the way bun does by @colinhacks in #1112
- aube: give the security scanner tests a 300s budget by @colinhacks in #1119
- run: keep the pre-run phantom scan out of the home folder by @colinhacks in #1117
- ci: install the Node versions version_tiers skipped without by @colinhacks in #1114
- docs: add CONTRIBUTING.md and SECURITY.md by @abappi19 in #1116
- ci: target the image's Node major in the musl native-islands leg by @colinhacks in #1123
- Add Contributor Covenant Code of Conduct by @abappi19 in #1115
- runtime, cli, pm, compile: fix correctness bugs and remove dead code by @colinhacks in #1113
- pm: fetch only the selected dependencies on a filtered install by @colinhacks in #1121
New Contributors
Full Changelog: v0.10.0...v0.11.0
{ // ... "contentMappers": [ { "package": "motherload", "extensions": [".toml", ".yaml"] } ] }