runtime: set the nub export condition on augmented runs - #913
Conversation
Nub is registered as a WinterTC runtime key, so a package can carry a `nub` branch in its `exports` map the way it carries `bun` or `deno` ones. Every augmented run now passes `--conditions=nub` to Node, next to 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. Both `--node` and `NODE_COMPAT` skip the function that builds these options, so a compat run keeps Node's own condition set; the new test asserts that on the same fixture as its control. Two other resolvers take the condition for the same reason. The compile bundler resolves `exports` at bundle time, so a compiled binary would otherwise ship a different file than the one an uncompiled run loads. The bare-preload resolver pre-resolves a specifier the child Node would resolve for itself, with the runtime key already on its argv.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
🟢 Approval recommended
The change is narrowly scoped, composes cleanly with existing condition plumbing, and is backed by a targeted regression test covering augmented vs compat behavior.
Pull request overview
Adds Nub’s WinterTC runtime key as an exports/imports condition for augmented execution paths, ensuring packages can ship a nub branch that is selected under Nub augmentation while leaving compat (--node / NODE_COMPAT) behavior unchanged.
Changes:
- Inject
--conditions=nubinto augmented Node invocations and ensure the set composes with project-declared conditions. - Teach the compile bundler and bare-preload resolver to resolve with the
nubcondition so build-time resolution matches run-time resolution. - Add a regression test covering augmented vs
--nodebehavior and composition with user-declared conditions; document the feature in runtime resolution docs.
File summaries
| File | Description |
|---|---|
crates/nub-cli/src/cli.rs |
Defines NUB_CONDITION and appends --conditions=nub for augmented runs; includes the condition when resolving bare preload specifiers ahead of child Node. |
crates/nub-cli/src/compile/bundle.rs |
Ensures bundling-time exports resolution includes the nub condition (and composes with user conditions) so compiled output matches augmented runtime selection. |
crates/nub-cli/tests/project_runtime_config.rs |
Adds an integration-style fixture asserting nub-condition selection on augmented runs, fallback to default under --node, and composition with nub.jsonc-declared conditions. |
site/content/docs/runtime/resolution.mdx |
Documents the new “Nub runtime key” behavior and clarifies that compat mode does not include the nub condition. |
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Important
Three public-contract discrepancies need resolution before merge.
Reviewed changes I reviewed the complete four-file diff and traced the affected launch, preload-resolution, compile-resolution, compat-mode, and standalone-loader paths.
- Runtime condition injection — Augmented CLI launches now add
--conditions=nub, deduplicated with project and tsconfig conditions, while compat callers remain gated. - Ahead-of-time resolution — The bare-preload resolver and compile bundler include the same condition when they resolve before Node.
- Coverage and documentation — A focused integration test covers CLI augmented,
--node, and configured-condition composition, and the runtime resolution docs introduce the public package export contract.
GPT Sol | 𝕏
…bundler The condition rides runs the CLI augments. The standalone `@nubjs/loader` installs the same transform hooks but deliberately leaves Node's condition set alone, because its contract is that a file resolves identically under it, under tsx, and under plain Node. The comments and docs said "every augmented run", which read as covering the loader too. The docs also claimed the key is registered with WinterTC. The registry entry is proposed, not landed, so the page now states what nub does and describes the name as following the runtime-keys convention. Adds the bundler test the first commit was missing. Nothing pinned that the key itself reaches the compile resolver -- the sibling test covers a custom condition being additive, not this one -- and a miss there ships a binary resolving the `default` branch while the same program run uncompiled loads the other one, with no error either way. An `exports` condition named `nub` keeps getting read as the prohibited `"nub"` config field, so the brand-boundary rule now says why it is not.
There was a problem hiding this comment.
Important
The new commit corrects the implementation comments and docs, but the PR description still publishes the two superseded claims.
Reviewed changes I reviewed the changes since the prior Pullfrog review, including the narrowed public contract, the brand-boundary guidance, and the new bundler regression coverage.
- Scoped the condition contract — Clarified that only CLI-augmented runs set
nub, while the standalone loader preserves Node's condition set. - Corrected the registry status — Replaced the registration claim in code and docs with accurate WinterTC-convention language and a separate proposal.
- Recorded the design boundary — Distinguished an
exportsruntime-dispatch condition from the prohibited Nub config namespace. - Covered ahead-of-time resolution — Added an exact positive-and-negative bundler test proving the implicit condition selects the
nubbranch.
⚠️ PR description still advertises the superseded contract
The description still says Nub is registered in WinterTC and that every augmented run receives the condition. Those claims now contradict the corrected code and docs, including the deliberate standalone-loader exclusion.
Technical details
# Align the PR description with the revised contract
## Affected sites
- PR description, paragraph 1 — claims the `nub` key is already registered
- PR description, paragraph 2 — claims every augmented run sets the condition
## Required outcome
- Describe registration as a separate proposal rather than completed work.
- Scope condition injection to CLI-augmented runs and preserve the standalone-loader exception.GPT Sol | 𝕏
|
Shipped in v0.9.0: https://github.com/nubjs/nub/releases/tag/v0.9.0 |

Nub sets a
nubexport condition on the runs its CLI augments, so a package can carry anubbranch alongsidebunanddenoones. The name follows the WinterTC runtime-keys convention; the registry entry is proposed separately in WinterTC55/runtime-keys#39Conditions are a set, so a package with no
nubkey resolves as it does on plain Node. Compat mode is unaffected — all five call sites were already gated. The standalone@nubjs/loaderdeliberately leaves Node's conditions alone, so a file resolves the same under it as under tsx.The compile bundler and the bare-preload resolver take the condition too, since both resolve ahead of the child Node.
Removing the condition turns the run-path test red on
{"nub":"default"}; swapping the key out of the resolver turns the bundler test red.