extract Pages Functions compiler into a standalone package#14785
extract Pages Functions compiler into a standalone package#14785dario-piotrowicz wants to merge 4 commits into
Conversation
🦋 Changeset detectedLatest commit: bd5f45c The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
|
✅ All changesets look good |
@cloudflare/autoconfig
@cloudflare/config
create-cloudflare
@cloudflare/deploy-helpers
@cloudflare/kv-asset-handler
miniflare
@cloudflare/pages-functions
@cloudflare/pages-shared
@cloudflare/unenv-preset
@cloudflare/vite-plugin
@cloudflare/vitest-pool-workers
@cloudflare/workers-auth
@cloudflare/workers-editor-shared
@cloudflare/workers-utils
wrangler
commit: |
This comment was marked as resolved.
This comment was marked as resolved.
addd36d to
37ffd72
Compare
| * Carries a `code` from {@link PagesFunctionsErrorCode} so callers can | ||
| * distinguish different failure modes without parsing the message string. | ||
| */ | ||
| export class PagesFunctionsError extends Error { |
There was a problem hiding this comment.
The package defines PagesFunctionsError (with a code from PagesFunctionsErrorCode, a const object + union type (enum-like)) and PagesFunctionsBuildError (a subclass). All classifiable errors carry an error code so Wrangler can map them to the original FatalError/UserError/FunctionsBuildError classes with the original per-error telemetry labels.
see packages/wrangler/src/pages/buildFunctions.ts
37ffd72 to
6b7720b
Compare
There was a problem hiding this comment.
This file was moved, with some modifications to packages/pages-functions/src/routing/filepath-routing.ts
There was a problem hiding this comment.
This file comes from packages/wrangler/src/pages/functions/filepath-routing.ts with some small modifications (mainly the introduction of PagesFunctionsErrors)
There was a problem hiding this comment.
This file is copied from packages/wrangler/src/pages/paths.ts but with getBasePath() and readableRelative() removed (since they are wrangler specific)
There was a problem hiding this comment.
Maybe we should move this code to workers-utils? 🤔
There was a problem hiding this comment.
Pretty much the exact same as packages/wrangler/src/pages/functions/identifiers.ts (which is pretty much being removed in this PR) just with some JSDoc comments added
There was a problem hiding this comment.
Replaced by packages/pages-functions/src/routing/identifiers.ts (this just re-exports the file's exports)
There was a problem hiding this comment.
The code comes from packages/wrangler/src/pages/functions/routes-validation.ts with some small changes.
There was a problem hiding this comment.
The code in this file comes from packages/wrangler/src/pages/functions/routes.ts with some small modifications (in particular the use of PagesFunctionsErrors)
There was a problem hiding this comment.
The code from this file was moved to packages/pages-functions/src/routing/routes.ts, the what remains here is a wrapper around writeRoutesModule that converts PagesFunctionsErrors into Wrangler UserErrors
| import { existsSync } from "node:fs"; | ||
| import { mkdir, writeFile } from "node:fs/promises"; | ||
| import { dirname, resolve } from "node:path"; | ||
| import { parseArgs } from "node:util"; |
There was a problem hiding this comment.
Note: for simplicity this uses parseArgs directly from node, I think this is ok for such a utility, if someone disagrees we can use yars to be more consistent with wrangler
There was a problem hiding this comment.
This file is pretty much unchanged, some of its imports have been changed from local Wrangler files to files from the new pages-functions package.
Some related changes (i.e. wrapping and converting PagesFunctionsError to Wrangler Error classes) have also been applied.
There was a problem hiding this comment.
As shown by github this is a simple file move with some minor changes
There was a problem hiding this comment.
As shown by github this is a simple file move with some minor changes
There was a problem hiding this comment.
As shown by github this is a simple file move with some minor changes
There was a problem hiding this comment.
Most of the tests here have been moved to packages/pages-functions/src/__tests__/routes-validation.test.ts only the wrangler-specific tests remain here
There was a problem hiding this comment.
These tests come from packages/wrangler/src/__tests__/pages/routes-validation.test.ts
There was a problem hiding this comment.
As shown by github this is a simple file move with some minor changes
6646a77 to
17b1caa
Compare
|
Codeowners approval required for this PR:
Show detailed file reviewers
|
0ae4985 to
35bc26f
Compare
| // Write _routes.json if requested or by default alongside the output | ||
| const routesOutputPath = | ||
| values["routes-output"] || resolve(outdir, "_routes.json"); | ||
| await mkdir(dirname(routesOutputPath), { recursive: true }); | ||
| await writeFile( | ||
| routesOutputPath, | ||
| JSON.stringify(result.routesJSON, null, 2) | ||
| ); | ||
|
|
||
| console.log(`Compiled Worker successfully to ${outdir}/index.js`); | ||
| console.log( | ||
| ` Routes: ${result.filepathRoutingConfig.routes.length} route(s) found` | ||
| ); | ||
| if (result.modules.length > 0) { | ||
| console.log(` Modules: ${result.modules.length} additional module(s)`); | ||
| } | ||
| console.log(` Routes JSON written to ${routesOutputPath}`); |
There was a problem hiding this comment.
🟡 Compiled worker from the CLI omits imported WASM/text/binary files, so it cannot be deployed
The command-line build writes only the worker script and its routes file (writeFile at packages/pages-functions/src/cli.ts:79) but never writes the collected extra module files, so any functions project that imports a .wasm, .txt, .html, .sql, or .bin file produces an output folder whose worker references files that do not exist.
Impact: A user who compiles functions that import WASM/text/binary assets gets a broken output that fails to deploy, even though the CLI prints "Compiled Worker successfully".
Why the module files are missing from the output
During bundling, createModuleCollectorPlugin (packages/pages-functions/src/build.ts:326-360) intercepts these imports, hashes their contents, records them in collectedModules, and returns external: true (packages/pages-functions/src/build.ts:312-315). This leaves a bare import like from "12345678-module.wasm" in the emitted index.js (asserted by the test at packages/pages-functions/src/__tests__/build.test.ts:199-200) but does NOT write the file to disk — the content lives only in the returned result.modules[].content array (packages/pages-functions/src/build.ts:307-311).
The programmatic API expects its caller to persist result.modules, but the CLI (packages/pages-functions/src/cli.ts:65-91) only writes _routes.json and logs result.modules.length; it never writes each module's content next to index.js. Consequently the emitted worker imports module files that are absent from outdir, and a subsequent wrangler deploy cannot resolve them.
Prompt for agents
In packages/pages-functions/src/cli.ts, after calling buildPagesFunctions, the CLI writes _routes.json but never persists the collected non-JS modules. The build step (packages/pages-functions/src/build.ts) marks imported .wasm/.txt/.html/.sql/.bin files as external and returns their bytes in result.modules (each { name, content, type }), leaving bare imports (e.g. from "<hash>-module.wasm") in the emitted index.js. Because those files are never written to outdir, the compiled worker references modules that do not exist on disk, so wrangler deploy will fail. Fix by iterating result.modules in the CLI and writing each module's content to outdir using its name (join(outdir, module.name)) before printing the success message. Ensure directories are created as needed.
Was this helpful? React with 👍 or 👎 to provide feedback.
New package
@cloudflare/pages-functionsatpackages/pages-functions/that extracts the Pages Functions compilation logic from Wrangler into a standalone, published package with both a programmatic API and CLI.What it does: Takes a
functions/directory and compiles it into a deployable Cloudflare Worker in a targetdist/directory.What stays in Wrangler:
_worker.jsadvanced mode, Pages Plugins, Pages deployment/upload, config parsing, watch mode, local dev middleware, telemetry, and authentication.Public API
CLI
Note
Across the PR you can see various comments like:
These re-exports just here to try to minimizes the diff size and preserves all existing Wrangler-internal import paths.
I will remove these in a followup PR.
A picture of a cute animal (not mandatory, but encouraged)