fix(build): let the published package use Deno's own Deno global - #3607
Conversation
`deno run -A npm:veryfront dev` aborted before binding a port with "Cannot read properties of null (reading 'fd')", so the whole CLI was unusable on the runtime our installation docs list as supported. dnt emits `_dnt.shims.js` as an unconditional re-export of `@deno/shim-deno`, so every framework module that touches `Deno.*` got the Node reimplementation even when Deno itself was executing the package. Those reimplementations are not runnable under Deno: `Deno.listen` builds a node:net server and immediately reads `server._handle.fd`, which is null on Deno's node compatibility layer. `isPortAvailable` calls it first, so `dev`, `start`, and every other port-binding command died there. Patch the generated shim, next to the existing `process.argv[1]` fix, so it prefers `globalThis.Deno` when the host runtime supplies one and falls back to `@deno/shim-deno` for Node and Bun. The first-party extension packages get the same treatment; they carry an identical shim file.
📝 WalkthroughWalkthroughThe change adds ChangesDNT shim patching
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant NpmBuild as npm build flow
participant ShimPatcher as patchDntDenoShim
participant GeneratedShim as _dnt.shims.js
participant Runtime as Native Deno global
participant Fallback as `@deno/shim-deno`
NpmBuild->>ShimPatcher: patch generated shim
ShimPatcher->>GeneratedShim: replace unconditional export
GeneratedShim->>Runtime: use native Deno when available
GeneratedShim->>Fallback: use fallback otherwise
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bfb24177e4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
AGENTS.md requires describe()/it() from #veryfront/testing/bdd.ts and assertions from #veryfront/testing/assert.ts. Converts the whole file, not just the cases added by this PR, so it does not end up split across two harnesses. Five sibling tests in scripts/build/ already import the same specifiers under scripts/test.deno.json, which maps #veryfront/ to ../src/.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/build/build-npm-extension-packages.ts`:
- Line 93: Update the patchDntDenoShim call in the extension package build to
pass the required option, ensuring missing generated _dnt.shims.js output causes
the build to fail closed. Match the existing required-shim usage in
build-npm-dnt.ts.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 18f807c6-cefe-45b5-8c03-5bfb3b9e3be5
📒 Files selected for processing (4)
scripts/build/build-npm-dnt.tsscripts/build/build-npm-extension-packages.tsscripts/build/dnt-polyfill.test.tsscripts/build/dnt-polyfill.ts
kwakayama
left a comment
There was a problem hiding this comment.
No actionable findings found.
Evidence: scripts/build/dnt-polyfill.ts:11-19 preserves the Node/Bun shim fallback while selecting the native Deno namespace only for a real Deno runtime. The replacement is applied to the root artifact with a required shape guard at scripts/build/build-npm-dnt.ts:230-244, and to extension artifacts at scripts/build/build-npm-extension-packages.ts:91-93. Focused tests cover native selection, fallback, idempotence, and generated-shim drift at scripts/build/dnt-polyfill.test.ts:112-197.
| Rubric | Score |
|---|---|
| Correctness | 40/40 |
| Tests | 19/20 |
| Reliability/security | 15/15 |
| Maintainability | 14/15 |
| Scope/docs | 10/10 |
| Total | 98/100 |
Review-Gate:
Reviewer: Codex
Reviewed-SHA: d715f8d
Score: 98/100
Actionable-Findings: 0
Verdict: APPROVE
Symptom
The CLI was entirely non-functional under Deno, even though
https://veryfront.com/docs/code/getting-started/installation documents
deno add npm:veryfrontas a supported install path.The same project ran fine under Node. Not a regression — 0.1.1228 was also
broken under Deno, with a different message.
Root cause
The boundary reported
unknown-errorand dropped the original stack. Loggingthe raw throwable in the published package gives the real one:
dnt emits
npm/esm/_dnt.shims.jsas an unconditional re-export:So every framework module that touches
Deno.*got the Nodereimplementation — including when Deno itself was executing the package. The
shim's
Deno.listenbuilds anode:netserver and immediately readsserver._handle.fd:That assumption does not hold on Deno's node compatibility layer, where
_handleis null.isPortAvailableis the first thingdevdoes, so theprocess died before the server bound. Any port-binding command (
dev,start, …) hit the same wall.Fix
Patch the generated shim in
postBuild, right beside the existingprocess.argv[1]fix, so it defers to the host runtime's ownDenoand keeps@deno/shim-denoas the fallback for Node and Bun:The first-party extension packages build through dnt with the same
shims: { deno: true }config and carry an identical shim file, so they getthe same patch.
patchDntDenoShimfails closed: if dnt's output shape ever changes, the rootbuild throws rather than silently shipping the broken shim again.
Verification against the published repro
Negative control, published 0.1.1229 —
deno run -A npm:veryfront@0.1.1229 dev --port 3795in averyfront initproject outside the monorepo:Same project, same command, with
node_modules/veryfrontreplaced by thisbranch's
deno task build:npmoutput:--verboseconfirms it now walks all the way through route discovery andbinds the port instead of aborting after "Using local filesystem (no proxy
mode)".
Tests
scripts/build/dnt-polyfill.test.ts(already indeno task test:scripts).The tests evaluate the shim module for real, with
@deno/shim-denoswappedfor a local stub, so they assert which
Denothe module actually hands backrather than matching on source text:
unpatched DNT shims shadow the real Deno global (the bug being fixed)—pins the pre-fix behaviour; fails if the patch is ever dropped
patchDntDenoShim makes the published shims prefer the real Deno globalpatchDntDenoShim keeps the shim fallback for runtimes without DenoConfirmed red before the fix (
does not provide an export named 'patchDntDenoShim'), green after.Scope
Build-script only; no
src/or docs changes, so nothing needs to be checkedon the live docs site for this PR.
Summary by CodeRabbit
Bug Fixes
Tests