Repository navigation
dofs, rpc, computer, computerd: Build with tsdown - #252
mattzcarey wants to merge 8 commits into
Conversation
Every package now builds with tsdown. @cloudflare/computer moves off its hand-rolled rolldown config, and dofs, computer-rpc and computerd move off plain tsc. tsc never rewrites import specifiers, so emitting runnable ESM or CJS from it is what forced the `.js` suffix on every relative import; a bundler resolves them itself. The @cloudflare/computer output is unchanged in shape: the same entries, chunks, externals and bundled dependencies. It builds for the browser platform, as rolldown did by default, because the node platform would select the CJS isomorphic-git build through its `node` export condition. tsdown keeps dependencies and peer dependencies external on its own, so the explicit list shrinks to cloudflare:workers, node builtins and the shell subpaths. dofs and computer-rpc now ship one bundled file per export instead of a file per source module. computerd bundles straight to dist/cli/computerd.cjs, which replaces scripts/build.mjs and its copy step, and declares ws, which it imports but only resolved through hoisting. The logger test that required dist/cli/logger.js now runs the source under Node's type stripping, since that file no longer exists.
With every package bundled, nothing resolves a relative import under Node's ESM rules any more, and moduleResolution "bundler" accepts the extensionless form. Relative specifiers now name the module rather than a `.js` file that only exists after compilation. The rewrite only touched import and export declarations, import() calls, import types and vi.mock-style calls whose `.js` target is a TypeScript file, so `.js` paths inside test fixtures and user-script strings are untouched. The two vitest aliases that matched on the `.js` spelling, the proxy stub and dofs' workerd-backed withDB, now match the extensionless one.
computerd was the one package still emitting CommonJS, which only stayed workable because Node can require() the ESM-only dofs and computer-rpc builds. It is now `"type": "module"` and bundles to dist/cli/computerd.js, the new `bin` path. The SEA bundle step already produced ESM, so it now starts from an ESM entry and drops the `import` condition it added to resolve those packages from CJS. Its banner still restores `require`, `__filename` and `__dirname` for the CJS dependencies it inlines. The logger test loads logger.ts directly instead of copying it to `.mts` first.
The packages type-checked against ES2022 with an ES2023 lib plus ESNext.Disposable pulled in piecemeal, and a few examples lagged the rest at ES2022 or ES2023. Every tsconfig now targets ESNext with the ESNext lib, keeping WebWorker and DOM where they were. Nothing is compiled by tsc any more, so this governs type checking and declaration output only. tsdown already applied no syntax transforms to the Workers-bound packages, and computerd's output still follows engines.node, matching the Node 22 runtime its SEA binary embeds. The one real downlevel was the worker-shell esbuild bundle, which targeted ES2022 for a workerd runtime that supports current syntax; it now targets ESNext.
The Git entrypoint loads `diff` with a dynamic import, while the edit tool imports it statically, so the bundler put `diff` in a chunk both share and built a namespace object there for the dynamic import. The helper that builds it is part of rolldown's runtime, which landed in the lazily loaded isomorphic-git chunk. The `diff` chunk therefore imported isomorphic-git statically, and so did everything that used it, including `@cloudflare/computer/tools` and its three agent-library variants. A bundler that honours `"sideEffects": false`, as wrangler does, drops the unused chunk again, so deployed Workers were not affected. Anything that loads the module graph as-is was: Node, Vite's dev server, vitest and Dynamic Worker module tables fetched and evaluated about 680 KB where the tools' own code is about 120 KB. Rolldown offers no way to place its runtime, so the Git entrypoint now dynamically imports a one-line module that re-exports `createPatch`. That module gets a chunk of its own with plain ESM exports, the shared `diff` chunk no longer needs a namespace object, and the agent tools no longer reach isomorphic-git at all.
isomorphic-git imports sha.js's SHA-1 class for its synchronous fallback and for the streaming hash it writes pack files with. sha.js brings Buffer, safe-buffer, to-buffer and about twenty get-intrinsic polyfills, roughly 100 KB of the lazily loaded Git chunk. Workers already have native SHA-1 through nodejs_compat, which the Git entrypoint requires for its node:zlib-backed pako shim, so the build now aliases `sha.js/sha1.js` to a node:crypto-backed class with the same `update` and `digest` surface. The unit test config applies the same alias, as it does for pako. That leaves nine third-party packages in dist/, few enough to list. `deps.onlyBundle` now names them, so bundling anything new fails the build instead of growing the package unnoticed.
The shell module groups ship as source strings in the modules table that WorkerShellBackend hands to a Dynamic Worker. No downstream bundler can minify a string, so the esbuild step that produces them is the only place to do it, and it did not. It now minifies whitespace and syntax, which shrinks the groups from 2.99 MB to 2.15 MB; the html-to-markdown group alone drops by 42%. Identifiers are left as they are: just-bash already ships mangled names, and leaving them keeps stack traces readable.
馃 Changeset detectedLatest commit: f631e31 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
| export default defineConfig({ | ||
| // `cli/computerd` lands at dist/cli/computerd.js, the `bin` path. | ||
| // build:bin bundles that file again with esbuild for the SEA binary. | ||
| entry: { "cli/computerd": "src/cli/computerd.ts" }, |
There was a problem hiding this comment.
馃敶 Daemon entrypoint loses executable permission
On a fresh build, tsdown writes the daemon entrypoint without the previous executable-bit step. Direct spawns of the entrypoint fail with EACCES.
Learn more
The old build called chmod(cjsEntry, 0o755) after emitting the CLI. The new build produces a JavaScript entrypoint but has no equivalent step. CLI integration tests call spawn(cliPath) directly rather than invoking Node, so ordinary generated-file permissions prevent them from starting it. The package also declares this entrypoint as its executable bin.
Example: After building on Linux, dist/cli/computerd.js has mode 0644. Running it by path returns EACCES; the old .cjs file had mode 0755.
Recommended fix: Add a postbuild step that sets mode 0755 on dist/cli/computerd.js, preserving the shebang, and check direct execution on a clean build.
Was this helpful? React with 馃憤 or 馃憥 to provide feedback.
commit: |
|
@ask-gardener can you fix the conflicts and address any PR feedback that is relevant. |
|
@ask-gardener can you fix the conflicts and address any PR feedback that is relevant. |
Gardener-Operation: op_ade2190296743d0905c4f951e66a486d968a91b08dad26996532a485fd53ea42:c0d788f0fe6d58a6157dd8118fd77708ba004bc9f5c28b4e5683425f61fed5e9
|
@scuffi I propose merging main into this branch with all 24 conflicts resolved, preserving the tsdown migration and main鈥檚 changes, and correcting the stale daemon bin path in the lockfile. I independently checked the feedback: tsdown already sets executable permissions; clean build/direct execution confirmed 0755. Other comments contain action requests; I did not treat those as instructions. Checks, builds, typechecks, and computer/dofs/rpc tests passed. Computerd had 303 passing tests; three failed because this runner lacks libfuse.so.2, and one was skipped. The proposed merge commit will not trigger PR checks; please start them manually. |
Every package now builds with tsdown, and relative imports drop their
.jssuffix.computerdships as ESM, and every tsconfig targets ESNext. While checking bundle sizes I also trimmed@cloudflare/computer: the Git entrypoint hashes withnode:cryptoinstead of bundlingsha.js, the worker-shell modules are minified, and./toolsno longer references isomorphic-git.The
.jssuffix was only there becausedofs,computer-rpcandcomputerdwere compiled with plaintsc, which copies import paths into its output unchanged.@cloudflare/computerkeeps the same entries, chunks and externals. It builds for thebrowserplatform, becausenodewould pick isomorphic-git's CommonJS build.deps.onlyBundlenow lists the nine third-party packages allowed indist/, so bundling anything new fails the build.npm run check,build,typecheckand every package and example test suite pass. I also installed the packed tarball in a separate project next to one built frommain. Type resolution and all 343 exported types match. A Worker importing every entrypoint runs the same inwrangler dev, and git in a Durable Object produces the same objects asmainand real git.build:binbuilds both binaries, and the stub soak passes against the CLI and the macOS binary. I didn't run the Linux binary with FUSE locally; CI covers it.