From 35fad48e9467d0242acf4f08dd43b46e4a7891a6 Mon Sep 17 00:00:00 2001
From: emily-shen <69125074+emily-shen@users.noreply.github.com>
Date: Thu, 20 Aug 2026 21:42:27 +0100
Subject: [PATCH 1/3] delete changeset review CI job (#15287)
---
.github/workflows/changeset-review.yml | 92 --------------------------
1 file changed, 92 deletions(-)
delete mode 100644 .github/workflows/changeset-review.yml
diff --git a/.github/workflows/changeset-review.yml b/.github/workflows/changeset-review.yml
deleted file mode 100644
index ac539636f97..00000000000
--- a/.github/workflows/changeset-review.yml
+++ /dev/null
@@ -1,92 +0,0 @@
-name: Changeset Review
-
-on:
- pull_request:
- paths:
- - ".changeset/*.md"
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.ref }}
- cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
-
-permissions:
- contents: read
- pull-requests: write
- issues: write
- id-token: write
-
-jobs:
- review-changesets:
- runs-on: ubuntu-latest
- if: github.event.pull_request.head.repo.full_name == github.repository
- steps:
- - name: Checkout changesets
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- with:
- fetch-depth: 0
- persist-credentials: false
- sparse-checkout: |
- .changeset
- .github/opencode.json
-
- - name: Install OpenCode
- # pin OpenCode to 1.4.6 version as newer versions are causing ProviderInitError issues
- run: |
- npm install -g opencode-ai@1.4.6
- cp .github/opencode.json ./opencode.json
-
- - name: Get changed changeset files
- id: changed-changesets
- uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
- with:
- files: |
- .changeset/*.md
- files_ignore: |
- .changeset/README.md
- # Recover deleted files so the AI can read them (needed for Version Packages PRs)
- recover_deleted_files: ${{ github.event.pull_request.title == 'Version Packages' }}
-
- - name: Review Changesets with OpenCode
- id: opencode-review
- # Run for Version Packages PRs (which delete changesets) or regular PRs with new changesets
- if: github.event.pull_request.title == 'Version Packages' || steps.changed-changesets.outputs.added_files_count > 0
- env:
- CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_AI_GATEWAY_ACCOUNT_ID }}
- CLOUDFLARE_GATEWAY_ID: ${{ secrets.CF_AI_GATEWAY_NAME }}
- CLOUDFLARE_API_TOKEN: ${{ secrets.CF_AI_GATEWAY_TOKEN }}
- DELETED_FILES: ${{ steps.changed-changesets.outputs.deleted_files }}
- ADDED_FILES: ${{ steps.changed-changesets.outputs.added_files }}
- run: |
- opencode --model "cloudflare-ai-gateway/workers-ai/@cf/moonshotai/kimi-k2.6" run --print-logs \
- "Review the changeset files in this PR.
-
- For \"Version Packages\" PRs, review: ${DELETED_FILES}
- For regular PRs, review: ${ADDED_FILES}
-
- Read \`.changeset/README.md\` for guidelines, then validate:
- 1. **Version Type**: Accept the author's choice of patch/minor unless clearly incorrect
- 2. **Changelog Quality**: Meaningful descriptions (examples encouraged but not required for features)
- 3. **Markdown Headers**: No h1/h2/h3 headers (breaks changelog formatting)
- 4. **Analytics**: If the change collects more analytics, it should be a minor even though there is no user-visible change
- 5. **Dependabot**: Do not validate dependency update changesets for create-cloudflare
- 6. **Experimental features**: Changesets for experimental features should include note on how users can opt in.
-
- If all changesets pass, just output \"✅ All changesets look good\" - no need for a detailed checklist.
-
- Do not review other files, only the changesets. This is specifically a changeset review action.
-
- If there are issues, output \"⚠️ Issues found\" followed by the specific problems.
-
- Write your review to changeset-review.md."
-
- - name: Post review comment
- if: steps.opencode-review.outcome == 'success'
- uses: marocchino/sticky-pull-request-comment@d4d6b0936434b21bc8345ad45a440c5f7d2c40ff # v3.0.3
- with:
- header: changeset-review
- path: changeset-review.md
-
- - name: Skip notice
- if: github.event.pull_request.title != 'Version Packages' && steps.changed-changesets.outputs.added_files_count == 0
- run: |
- echo "No new changesets to review (only minor edits to pre-existing changesets detected)"
From 8958ecf8c258c439489305d95901e75cbe1cd4e0 Mon Sep 17 00:00:00 2001
From: Ben <4991309+NuroDev@users.noreply.github.com>
Date: Thu, 20 Aug 2026 22:20:52 +0100
Subject: [PATCH 2/3] chore: remove legacy issue triage workflow (#15286)
---
.github/workflows/triage-issue.yml | 259 -----------------------------
1 file changed, 259 deletions(-)
delete mode 100644 .github/workflows/triage-issue.yml
diff --git a/.github/workflows/triage-issue.yml b/.github/workflows/triage-issue.yml
deleted file mode 100644
index 10bcf761171..00000000000
--- a/.github/workflows/triage-issue.yml
+++ /dev/null
@@ -1,259 +0,0 @@
-name: Triage Issue
-
-on:
- issues:
- types: [opened]
- issue_comment:
- types: [created]
- workflow_dispatch:
- inputs:
- issue-number:
- description: "Issue number to triage"
- required: true
- type: number
-
-permissions:
- contents: read
- # Writes (comment + labels) are performed with GH_ACCESS_TOKEN (the
- # workers-devprod bot) so they are attributed to that identity, not
- # github-actions[bot]. Only read access is needed from the default token.
- issues: read
-
-# Cancel in-progress runs for the same issue
-concurrency:
- group: triage-${{ github.event.issue.number || inputs.issue-number }}
- cancel-in-progress: ${{ github.head_ref != 'changeset-release/main' }}
-
-jobs:
- triage:
- runs-on: ubuntu-latest
- # Always run for manual dispatch. For issue events, skip PRs and
- # bot-created issues. For comment events, skip PRs, bot comments, and the
- # triage bot's own report comment (identified by its marker) to avoid
- # infinite re-triage loops.
- if: >-
- github.event_name == 'workflow_dispatch' ||
- (github.event_name == 'issues' &&
- !github.event.issue.pull_request &&
- github.event.issue.user.type != 'Bot') ||
- (github.event_name == 'issue_comment' &&
- !github.event.issue.pull_request &&
- github.event.comment.user.type != 'Bot' &&
- !contains(github.event.comment.body, ''))
- timeout-minutes: 60
- steps:
- - name: Resolve issue number
- id: issue
- env:
- EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
- EVENT_NAME: ${{ github.event_name }}
- INPUT_ISSUE_NUMBER: ${{ inputs.issue-number }}
- run: |
- if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
- echo "number=${INPUT_ISSUE_NUMBER}" >> "$GITHUB_OUTPUT"
- else
- echo "number=${EVENT_ISSUE_NUMBER}" >> "$GITHUB_OUTPUT"
- fi
-
- - name: Checkout (sparse — just the skill and opencode config)
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- with:
- persist-credentials: false
- sparse-checkout: |
- .github/skills
- .github/opencode.json
-
- - name: Install OpenCode
- # Pin to a known-good version (matches the Bonk workflow). Newer
- # versions (e.g. 1.17.x) changed the default model to ones that are not
- # provisioned in our AI Gateway, which surfaced as "Invalid Anthropic
- # API Key" errors.
- run: |
- npm install -g opencode-ai@1.15.13
- cp .github/opencode.json ./opencode.json
-
- - name: Fetch issue data
- env:
- GH_TOKEN: ${{ github.token }}
- ISSUE: ${{ steps.issue.outputs.number }}
- REPO: ${{ github.repository }}
- run: |
- mkdir -p "data/${ISSUE}"
-
- gh issue view "$ISSUE" \
- --repo "$REPO" \
- --json number,title,body,comments,createdAt,updatedAt,labels,state,author \
- > "data/${ISSUE}/context.json"
-
- - name: Analyze issue with OpenCode
- env:
- CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_AI_GATEWAY_ACCOUNT_ID }}
- CLOUDFLARE_GATEWAY_ID: ${{ secrets.CF_AI_GATEWAY_NAME }}
- CLOUDFLARE_API_TOKEN: ${{ secrets.CF_AI_GATEWAY_TOKEN }}
- ISSUE: ${{ steps.issue.outputs.number }}
- REPO: ${{ github.repository }}
- run: |
- opencode \
- --model "cloudflare-ai-gateway/anthropic/claude-opus-4-8" \
- run \
- --print-logs \
- "Analyze GitHub issue ${REPO}#${ISSUE} using the skill at .github/skills/issue-review.md.
-
- The issue data has been pre-fetched to data/${ISSUE}/context.json.
- Read it with the read tool and follow the triage process.
-
- Create:
- - data/${ISSUE}/report.md (full markdown report)
- - data/${ISSUE}/summary.json (structured JSON summary)
- "
-
- - name: Upload report to dashboard
- env:
- CF_ACCESS_CLIENT_ID: ${{ secrets.CF1_ACCESS_CLIENT_ID }}
- CF_ACCESS_CLIENT_SECRET: ${{ secrets.CF1_ACCESS_CLIENT_SECRET }}
- DASHBOARD_URL: ${{ secrets.REPORTS_DASHBOARD_URL }}
- ISSUE: ${{ steps.issue.outputs.number }}
- REPO: ${{ github.repository }}
- run: |
- # Check files were created
- if [ ! -f "data/${ISSUE}/report.md" ]; then
- echo "::error::report.md was not generated"
- exit 1
- fi
- if [ ! -f "data/${ISSUE}/summary.json" ]; then
- echo "::error::summary.json was not generated"
- exit 1
- fi
-
- # Validate the summary is parseable JSON before doing anything with it.
- if ! jq empty "data/${ISSUE}/summary.json" 2>/dev/null; then
- echo "::error::summary.json is not valid JSON"
- exit 1
- fi
-
- # Build the dashboard payload from the structured summary + markdown report.
- # suggestedComment is kept as a "Yes"/"No" string for dashboard compatibility.
- PAYLOAD=$(jq \
- --arg githubUrl "https://github.com/${REPO}/issues/${ISSUE}" \
- --rawfile reportMarkdown "data/${ISSUE}/report.md" \
- '{
- title: .title,
- githubUrl: $githubUrl,
- recommendation: .recommendation,
- difficulty: .difficulty,
- reasoning: .reasoning,
- suggestedAction: .suggestedAction,
- suggestedComment: (if .hasSuggestedComment then "Yes" else "No" end),
- reportMarkdown: $reportMarkdown
- }' "data/${ISSUE}/summary.json")
-
- # POST to dashboard API
- HTTP_STATUS=$(curl -L --post302 -s -o response.json -w "%{http_code}" \
- -X POST "${DASHBOARD_URL}/api/report/${ISSUE}" \
- -H "Content-Type: application/json" \
- -H "CF-Access-Client-Id: ${CF_ACCESS_CLIENT_ID}" \
- -H "CF-Access-Client-Secret: ${CF_ACCESS_CLIENT_SECRET}" \
- -d "$PAYLOAD")
-
- echo "Dashboard API response: HTTP ${HTTP_STATUS}"
- cat response.json
-
- if [ "$HTTP_STATUS" != "200" ]; then
- echo "::error::Failed to upload report (HTTP ${HTTP_STATUS})"
- exit 1
- fi
-
- echo "Report uploaded for issue #${ISSUE}"
-
- - name: Build triage comment
- env:
- ISSUE: ${{ steps.issue.outputs.number }}
- run: |
- {
- echo ""
- echo "> [!NOTE]"
- echo "> This is an automated, advisory triage report generated by workers-devprod. It is not an official maintainer response — a maintainer will follow up."
- echo ""
- echo ""
- echo "🤖 Automated triage report
"
- echo ""
- cat "data/${ISSUE}/report.md"
- echo ""
- echo " "
- echo ""
- echo ""
- echo "Structured summary (JSON)
"
- echo ""
- echo '```json'
- cat "data/${ISSUE}/summary.json"
- echo ""
- echo '```'
- echo ""
- echo " "
- } > "data/${ISSUE}/comment.md"
-
- # marocchino/sticky-pull-request-comment only supports PRs (it resolves
- # the number as a PullRequest), so for issues we implement a "sticky"
- # upsert with gh: find our previous comment by its marker and edit it,
- # otherwise create a new one. gh is already used throughout this workflow.
- - name: Post triage comment
- env:
- GH_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
- ISSUE: ${{ steps.issue.outputs.number }}
- REPO: ${{ github.repository }}
- run: |
- MARKER=""
- BODY_FILE="data/${ISSUE}/comment.md"
-
- COMMENT_ID=$(gh api --paginate "/repos/${REPO}/issues/${ISSUE}/comments" \
- --jq "map(select(.body | contains(\"${MARKER}\"))) | .[0].id // empty")
-
- if [ -n "$COMMENT_ID" ]; then
- jq -n --rawfile body "$BODY_FILE" '{body: $body}' \
- | gh api --method PATCH "/repos/${REPO}/issues/comments/${COMMENT_ID}" --input - > /dev/null
- echo "Updated existing triage comment ${COMMENT_ID}"
- else
- gh issue comment "$ISSUE" --repo "$REPO" --body-file "$BODY_FILE"
- echo "Created new triage comment"
- fi
-
- - name: Apply suggested labels
- env:
- GH_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
- ISSUE: ${{ steps.issue.outputs.number }}
- REPO: ${{ github.repository }}
- run: |
- SUMMARY_PATH="data/${ISSUE}/summary.json"
- if [ ! -f "$SUMMARY_PATH" ]; then
- echo "No summary.json; skipping label application"
- exit 0
- fi
-
- # suggestedLabels is a JSON array; emit one label per line.
- jq -r '.suggestedLabels // [] | .[]' "$SUMMARY_PATH" > suggested-labels.txt
- if [ ! -s suggested-labels.txt ]; then
- echo "No suggested labels"
- exit 0
- fi
-
- # Only apply labels that actually exist in the repo.
- gh label list --repo "$REPO" --limit 500 --json name --jq '.[].name' > repo-labels.txt
-
- ARGS=()
- while IFS= read -r label; do
- if [ -z "$label" ]; then
- continue
- fi
- if grep -Fxq "$label" repo-labels.txt; then
- ARGS+=(--add-label "$label")
- else
- echo "Skipping unknown label: ${label}"
- fi
- done < suggested-labels.txt
-
- if [ ${#ARGS[@]} -eq 0 ]; then
- echo "No valid labels to apply"
- exit 0
- fi
-
- gh issue edit "$ISSUE" --repo "$REPO" "${ARGS[@]}"
From daefb3cc0f0b884b8ce82b22ed9b67a9c43919be Mon Sep 17 00:00:00 2001
From: Edmund Hung
Date: Thu, 20 Aug 2026 22:55:37 +0100
Subject: [PATCH 3/3] [autoconfig] Add cf configuration target (#15246)
Co-authored-by: Dario Piotrowicz
---
.changeset/fresh-dogs-configure.md | 8 +
packages/autoconfig/package.json | 1 +
packages/autoconfig/scripts/deps.ts | 2 +
packages/autoconfig/src/context.ts | 2 +
.../src/details/framework-detection.ts | 5 +-
packages/autoconfig/src/details/index.ts | 78 +++--
packages/autoconfig/src/frameworks/analog.ts | 11 +-
packages/autoconfig/src/frameworks/angular.ts | 19 +-
packages/autoconfig/src/frameworks/astro.ts | 15 +-
.../src/frameworks/framework-class.ts | 30 +-
packages/autoconfig/src/frameworks/next.ts | 2 +-
packages/autoconfig/src/frameworks/no-op.ts | 2 +-
packages/autoconfig/src/frameworks/nuxt.ts | 11 +-
packages/autoconfig/src/frameworks/qwik.ts | 13 +-
.../autoconfig/src/frameworks/react-router.ts | 5 +-
.../autoconfig/src/frameworks/solid-start.ts | 11 +-
packages/autoconfig/src/frameworks/static.ts | 8 +-
.../autoconfig/src/frameworks/sveltekit.ts | 11 +-
.../autoconfig/src/frameworks/tanstack.ts | 5 +-
packages/autoconfig/src/frameworks/vike.ts | 5 +-
packages/autoconfig/src/frameworks/vite.ts | 14 +-
packages/autoconfig/src/frameworks/waku.ts | 13 +-
packages/autoconfig/src/index.ts | 2 +
packages/autoconfig/src/run.ts | 330 +++++++++++++++---
packages/autoconfig/src/types.ts | 15 +-
.../display-auto-config-details.test.ts | 2 +-
.../get-details-for-auto-config.test.ts | 27 +-
.../tests/frameworks/angular.test.ts | 56 +--
.../tests/frameworks/react-router.test.ts | 9 +-
.../validate-framework-version.test.ts | 2 +-
.../autoconfig/tests/frameworks/vike.test.ts | 7 +-
.../autoconfig/tests/frameworks/vite.test.ts | 25 +-
packages/autoconfig/tests/run-summary.test.ts | 96 ++++-
packages/autoconfig/tests/run.test.ts | 244 +++++++++++++
.../src/__tests__/autoconfig/index.test.ts | 7 +-
.../src/__tests__/autoconfig/run.test.ts | 86 +++--
.../src/__tests__/deploy/core.test.ts | 6 +-
packages/wrangler/src/__tests__/setup.test.ts | 3 +-
packages/wrangler/src/autoconfig/index.ts | 6 +-
packages/wrangler/src/setup.ts | 2 +-
pnpm-lock.yaml | 3 +
41 files changed, 922 insertions(+), 277 deletions(-)
create mode 100644 .changeset/fresh-dogs-configure.md
create mode 100644 packages/autoconfig/tests/run.test.ts
diff --git a/.changeset/fresh-dogs-configure.md b/.changeset/fresh-dogs-configure.md
new file mode 100644
index 00000000000..5b3d0a9264e
--- /dev/null
+++ b/.changeset/fresh-dogs-configure.md
@@ -0,0 +1,8 @@
+---
+"@cloudflare/autoconfig": minor
+"wrangler": patch
+---
+
+Prepare autoconfig for multiple configuration targets
+
+Add target-specific configuration output while preserving Wrangler's existing setup and deployment behavior.
diff --git a/packages/autoconfig/package.json b/packages/autoconfig/package.json
index a34b2972819..520c50cf11e 100644
--- a/packages/autoconfig/package.json
+++ b/packages/autoconfig/package.json
@@ -30,6 +30,7 @@
},
"dependencies": {
"@cloudflare/cli-shared-helpers": "workspace:*",
+ "@cloudflare/config": "workspace:*",
"@cloudflare/workers-utils": "workspace:*"
},
"devDependencies": {
diff --git a/packages/autoconfig/scripts/deps.ts b/packages/autoconfig/scripts/deps.ts
index 6d7361e5358..01728ca8c86 100644
--- a/packages/autoconfig/scripts/deps.ts
+++ b/packages/autoconfig/scripts/deps.ts
@@ -8,5 +8,7 @@ export const EXTERNAL_DEPENDENCIES = [
// Published workspace packages that consumers must install alongside autoconfig.
// They are kept external to share a single copy with wrangler and other SDK tools.
"@cloudflare/cli-shared-helpers",
+ // Its public types are exposed by autoconfig and must resolve for consumers.
+ "@cloudflare/config",
"@cloudflare/workers-utils",
];
diff --git a/packages/autoconfig/src/context.ts b/packages/autoconfig/src/context.ts
index 8c70cd987ed..e7301a8a731 100644
--- a/packages/autoconfig/src/context.ts
+++ b/packages/autoconfig/src/context.ts
@@ -15,6 +15,8 @@ export interface AutoConfigLogger {
error(...args: unknown[]): void;
}
+export type AutoConfigTarget = "cf" | "wrangler";
+
/**
* Dialog interface for interactive prompts.
* Callers provide their own implementation (e.g., using `prompts`, `inquirer`, or a custom UI).
diff --git a/packages/autoconfig/src/details/framework-detection.ts b/packages/autoconfig/src/details/framework-detection.ts
index 9835f23a9c9..2e3ba94af4e 100644
--- a/packages/autoconfig/src/details/framework-detection.ts
+++ b/packages/autoconfig/src/details/framework-detection.ts
@@ -32,8 +32,8 @@ import type { Settings } from "@netlify/build-info";
* @param projectPath Path to the project root
* @param wranglerConfig Optional parsed wrangler config for the project
* @returns An object containing:
- * - `detectedFramework`: The matched framework together with its build
- * command and output directory.
+ * - `detectedFramework`: The matched framework, its build and development
+ * commands, and its output directory.
* - `packageManager`: The package manager detected in the project.
* - `isWorkspaceRoot`: `true` when the project path is the root of a
* monorepo workspace (only present when relevant).
@@ -220,6 +220,7 @@ type DetectedFramework = {
name: string;
id: string;
};
+ devCommand?: string | undefined;
buildCommand?: string | undefined;
dist?: string;
};
diff --git a/packages/autoconfig/src/details/index.ts b/packages/autoconfig/src/details/index.ts
index 3ba589d68ad..6c255653397 100644
--- a/packages/autoconfig/src/details/index.ts
+++ b/packages/autoconfig/src/details/index.ts
@@ -1,5 +1,5 @@
import assert from "node:assert";
-import { statSync } from "node:fs";
+import { existsSync, statSync } from "node:fs";
import { readdir, stat } from "node:fs/promises";
import { join, relative, resolve } from "node:path";
import { brandColor } from "@cloudflare/cli-shared-helpers/colors";
@@ -17,7 +17,7 @@ import {
staticFramework,
} from "../frameworks/all-frameworks";
import { detectFramework } from "./framework-detection";
-import type { AutoConfigContext } from "../context";
+import type { AutoConfigContext, AutoConfigTarget } from "../context";
import type {
AutoConfigDetails,
AutoConfigDetailsForNonConfiguredProject,
@@ -25,6 +25,8 @@ import type {
import type { PackageManager } from "@cloudflare/workers-utils";
import type { Config, PackageJSON } from "@cloudflare/workers-utils";
+const CLOUDFLARE_CONFIG_FILE = "cloudflare.config.ts";
+
/**
* Asserts that the current project being targeted for autoconfig is not already configured.
*
@@ -70,18 +72,12 @@ async function findAssetsDir(from: string): Promise {
return undefined;
}
-type DetectedFramework = {
- framework: {
- name: string;
- id: string;
- };
- buildCommand?: string | undefined;
- dist?: string;
-};
-
/**
* Detects project details needed for autoconfig: framework, package manager,
- * output directory, worker name, and whether the project is already configured.
+ * output directory, worker name, commands, and whether the project is already configured.
+ * By default, the project is considered configured when `cloudflare.config.ts`
+ * exists. Passing `target: "wrangler"` opts into Wrangler configuration
+ * detection instead.
*
* @param options - Detection options including project path, wrangler config, and context.
* @returns The detected project details.
@@ -89,12 +85,15 @@ type DetectedFramework = {
export async function getDetailsForAutoConfig({
projectPath = process.cwd(),
wranglerConfig,
+ target = "cf",
context,
}: {
/** The path to the project, defaults to cwd. */
projectPath?: string;
/** The parsed wrangler configuration for the project (if any). */
wranglerConfig?: Config;
+ /** The configuration target, defaults to cf. */
+ target?: AutoConfigTarget;
/** The autoconfig context providing logger, dialogs, and other dependencies. */
context: AutoConfigContext;
}): Promise {
@@ -103,6 +102,19 @@ export async function getDetailsForAutoConfig({
logger.debug(`Running autoconfig detection in ${projectPath}...`);
if (
+ target === "cf" &&
+ existsSync(resolve(projectPath, CLOUDFLARE_CONFIG_FILE))
+ ) {
+ return {
+ configured: true,
+ projectPath,
+ workerName: getWorkerName(undefined, projectPath),
+ packageManager: NpmPackageManager,
+ };
+ }
+
+ if (
+ target === "wrangler" &&
// If a real Wrangler config has been found the project is already configured for Workers
wranglerConfig?.configPath &&
// Unless `pages_build_output_dir` is set, since that indicates that the project is a Pages one instead
@@ -134,7 +146,7 @@ export async function getDetailsForAutoConfig({
logger.debug("No package.json found when running autoconfig");
}
- const configured = framework.isConfigured(projectPath) ?? false;
+ const configured = framework.isConfigured(projectPath, { target });
const outputDir =
detectedFramework?.dist ?? (await findAssetsDir(projectPath));
@@ -144,14 +156,11 @@ export async function getDetailsForAutoConfig({
framework,
packageJson,
packageManager,
- ...(detectedFramework
- ? {
- buildCommand: getProjectBuildCommand(
- detectedFramework,
- packageManager
- ),
- }
- : {}),
+ devCommand: getProjectCommand(detectedFramework.devCommand, packageManager),
+ buildCommand: getProjectCommand(
+ detectedFramework.buildCommand,
+ packageManager
+ ),
workerName: getWorkerName(packageJson?.name, projectPath),
};
@@ -185,34 +194,33 @@ export async function getDetailsForAutoConfig({
}
/**
- * Given a detected framework this function gets a `build` command for the target project that can be run in the terminal
- * (such as `npm run build` or `npx astro build`). If no build command is detected `undefined` is returned instead.
+ * Converts a detected project command into one that can be run in the terminal
+ * (such as `npm run build` or `npx astro dev`). If no command is detected
+ * `undefined` is returned instead.
*
- * @param detectedFramework The detected framework (or settings) for the project
+ * @param command The detected project command
* @param packageManager The package manager to use for command prefixes
- * @returns A runnable command for the build process if detected, undefined otherwise
+ * @returns A runnable project command if detected, undefined otherwise
*/
-function getProjectBuildCommand(
- detectedFramework: DetectedFramework,
+function getProjectCommand(
+ command: string | undefined,
packageManager: PackageManager
): string | undefined {
- if (!detectedFramework.buildCommand) {
+ if (!command) {
return undefined;
}
const { type, dlx, npx } = packageManager;
for (const packageManagerCommandPrefix of [type, dlx.join(" "), npx]) {
- if (
- detectedFramework.buildCommand.startsWith(packageManagerCommandPrefix)
- ) {
- // The build command already is something like `npm run build` or similar
- return detectedFramework.buildCommand;
+ if (command.startsWith(packageManagerCommandPrefix)) {
+ // The command already includes a package-manager prefix.
+ return command;
}
}
- // The command is something like `astro build` so we need to prefix it with `npx` and equivalents
- return `${npx} ${detectedFramework.buildCommand}`;
+ // Framework executables such as `astro build` need the appropriate package-manager prefix.
+ return `${npx} ${command}`;
}
/**
diff --git a/packages/autoconfig/src/frameworks/analog.ts b/packages/autoconfig/src/frameworks/analog.ts
index c7932bd35c2..ef55cd72b2b 100644
--- a/packages/autoconfig/src/frameworks/analog.ts
+++ b/packages/autoconfig/src/frameworks/analog.ts
@@ -24,13 +24,14 @@ export class Analog extends Framework {
}
return {
- wranglerConfig: {
- main: "./dist/analog/server/index.mjs",
- assets: {
- binding: "ASSETS",
- directory: "./dist/analog/public",
+ buildTool: "wrangler",
+ workerConfig: {
+ entrypoint: "./dist/analog/server/index.mjs",
+ env: {
+ ASSETS: { type: "assets" },
},
},
+ buildConfig: { assetsDirectory: "./dist/analog/public" },
};
}
}
diff --git a/packages/autoconfig/src/frameworks/angular.ts b/packages/autoconfig/src/frameworks/angular.ts
index fdebfb1a01a..82082672013 100644
--- a/packages/autoconfig/src/frameworks/angular.ts
+++ b/packages/autoconfig/src/frameworks/angular.ts
@@ -34,23 +34,22 @@ export class Angular extends Framework {
await installAdditionalDependencies(packageManager, isWorkspaceRoot);
}
return {
- wranglerConfig: {
- main: "./dist/server/server.mjs",
- assets: {
- binding: "ASSETS",
- directory: `${outputDir}browser`,
+ buildTool: "wrangler",
+ workerConfig: {
+ entrypoint: "./dist/server/server.mjs",
+ env: {
+ ASSETS: { type: "assets" },
},
},
+ buildConfig: { assetsDirectory: `${outputDir}browser` },
};
} else {
this.configurationDescription =
"Configuring Angular SPA project (assets only)";
return {
- wranglerConfig: {
- assets: {
- directory: outputDir,
- },
- },
+ buildTool: "wrangler",
+ workerConfig: {},
+ buildConfig: { assetsDirectory: outputDir },
};
}
}
diff --git a/packages/autoconfig/src/frameworks/astro.ts b/packages/autoconfig/src/frameworks/astro.ts
index 0c04ce98e98..9a705574b3d 100644
--- a/packages/autoconfig/src/frameworks/astro.ts
+++ b/packages/autoconfig/src/frameworks/astro.ts
@@ -66,20 +66,21 @@ export class Astro extends Framework {
if (semiver(astroVersion, "6.0.0") < 0) {
// Before version 6 Astro required a wrangler config file
return {
- wranglerConfig: {
- main: `${outputDir}/_worker.js/index.js`,
- compatibility_flags: ["global_fetch_strictly_public"],
- assets: {
- binding: "ASSETS",
- directory: outputDir,
+ buildTool: "wrangler",
+ workerConfig: {
+ entrypoint: `${outputDir}/_worker.js/index.js`,
+ compatibilityFlags: ["global_fetch_strictly_public"],
+ env: {
+ ASSETS: { type: "assets" },
},
},
+ buildConfig: { assetsDirectory: outputDir },
};
}
// From version 6 Astro doesn't need a wrangler config file but generates a redirected config on build
return {
- wranglerConfig: null,
+ workerConfig: null,
};
}
diff --git a/packages/autoconfig/src/frameworks/framework-class.ts b/packages/autoconfig/src/frameworks/framework-class.ts
index 93f51529e88..4069e075e08 100644
--- a/packages/autoconfig/src/frameworks/framework-class.ts
+++ b/packages/autoconfig/src/frameworks/framework-class.ts
@@ -3,9 +3,9 @@ import semiver from "semiver";
import { AutoConfigFrameworkConfigurationError } from "../errors";
import { getInstalledPackageVersion } from "./utils/packages";
import type { AutoConfigFrameworkPackageInfo, FrameworkInfo } from ".";
-import type { AutoConfigContext } from "../context";
+import type { AutoConfigContext, AutoConfigTarget } from "../context";
+import type { WorkerConfigInput } from "@cloudflare/config";
import type { PackageManager } from "@cloudflare/workers-utils";
-import type { RawConfig } from "@cloudflare/workers-utils";
export abstract class Framework {
readonly id: FrameworkInfo["id"];
@@ -25,7 +25,14 @@ export abstract class Framework {
this.name = frameworkInfo.name;
}
- isConfigured(_projectPath: string): boolean {
+ isConfigured(
+ _projectPath: string,
+ {
+ target: _target = "cf",
+ }: {
+ target?: AutoConfigTarget;
+ } = {}
+ ): boolean {
return false;
}
@@ -90,6 +97,7 @@ export abstract class Framework {
}
export type ConfigurationOptions = {
+ target: AutoConfigTarget;
outputDir: string;
projectPath: string;
workerName: string;
@@ -100,14 +108,22 @@ export type ConfigurationOptions = {
};
export type PackageJsonScriptsOverrides = {
- preview?: string; // default is `npm run build && wrangler dev`
- deploy?: string; // default is `npm run build && wrangler deploy`
+ preview?: string; // legacy Wrangler preview command, default is `npm run build && wrangler dev`
+ deploy?: string; // legacy Wrangler deploy command, default is `npm run build && wrangler deploy`
typegen?: string; // default is `wrangler types`
};
+export type BuildConfig = {
+ assetsDirectory?: string;
+};
+
export type ConfigurationResults = {
- /** The wrangler configuration that the framework's `configure()` hook should generate. `null` if autoconfig should not create the wrangler file (in case an external tool already does that) */
- wranglerConfig: RawConfig | null;
+ /** The tool that cf should delegate build and development commands to. */
+ buildTool?: "vite" | "wrangler";
+ /** Worker configuration generated by the framework. `null` if an external tool generates it. */
+ workerConfig: Partial | null;
+ /** Build configuration that complements the Worker configuration. */
+ buildConfig?: BuildConfig;
// Scripts to override in the package.json. Most frameworks should not need to do this, as their default detected build command will be sufficient
packageJsonScriptsOverrides?: PackageJsonScriptsOverrides;
// Build command to override the standard one (`npm run build` or framework's build command)
diff --git a/packages/autoconfig/src/frameworks/next.ts b/packages/autoconfig/src/frameworks/next.ts
index 70af2173cb1..fb7a8a10d4e 100644
--- a/packages/autoconfig/src/frameworks/next.ts
+++ b/packages/autoconfig/src/frameworks/next.ts
@@ -32,7 +32,7 @@ export class NextJs extends Framework {
return {
// `@opennextjs/cloudflare migrate` creates the wrangler config file
- wranglerConfig: {},
+ workerConfig: {},
packageJsonScriptsOverrides: {
preview: "opennextjs-cloudflare build && opennextjs-cloudflare preview",
deploy: "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
diff --git a/packages/autoconfig/src/frameworks/no-op.ts b/packages/autoconfig/src/frameworks/no-op.ts
index 4746451b3c6..25155a9c8dd 100644
--- a/packages/autoconfig/src/frameworks/no-op.ts
+++ b/packages/autoconfig/src/frameworks/no-op.ts
@@ -4,7 +4,7 @@ import type { ConfigurationResults } from "./framework-class";
export class NoOpFramework extends Framework {
async configure(): Promise {
return {
- wranglerConfig: {},
+ workerConfig: {},
};
}
}
diff --git a/packages/autoconfig/src/frameworks/nuxt.ts b/packages/autoconfig/src/frameworks/nuxt.ts
index aa536529ad4..3d9d63b765e 100644
--- a/packages/autoconfig/src/frameworks/nuxt.ts
+++ b/packages/autoconfig/src/frameworks/nuxt.ts
@@ -75,16 +75,17 @@ export class Nuxt extends Framework {
}
return {
- wranglerConfig: {
- main: "./.output/server/index.mjs",
- assets: {
- binding: "ASSETS",
- directory: "./.output/public/",
+ buildTool: "wrangler",
+ workerConfig: {
+ entrypoint: "./.output/server/index.mjs",
+ env: {
+ ASSETS: { type: "assets" },
},
observability: {
enabled: true,
},
},
+ buildConfig: { assetsDirectory: "./.output/public/" },
};
}
diff --git a/packages/autoconfig/src/frameworks/qwik.ts b/packages/autoconfig/src/frameworks/qwik.ts
index bcc07802cae..88d0dd90de6 100644
--- a/packages/autoconfig/src/frameworks/qwik.ts
+++ b/packages/autoconfig/src/frameworks/qwik.ts
@@ -40,14 +40,15 @@ export class Qwik extends Framework {
addBindingsProxy(projectPath);
}
return {
- wranglerConfig: {
- main: "./dist/_worker.js",
- compatibility_flags: ["global_fetch_strictly_public"],
- assets: {
- binding: "ASSET",
- directory: "./dist",
+ buildTool: "wrangler",
+ workerConfig: {
+ entrypoint: "./dist/_worker.js",
+ compatibilityFlags: ["global_fetch_strictly_public"],
+ env: {
+ ASSET: { type: "assets" },
},
},
+ buildConfig: { assetsDirectory: "./dist" },
packageJsonScriptsOverrides: {
preview: `${packageManager.type} run build && wrangler dev`,
deploy: `${packageManager.type} run build && wrangler deploy`,
diff --git a/packages/autoconfig/src/frameworks/react-router.ts b/packages/autoconfig/src/frameworks/react-router.ts
index a4cddf5059b..eae05a72eb8 100644
--- a/packages/autoconfig/src/frameworks/react-router.ts
+++ b/packages/autoconfig/src/frameworks/react-router.ts
@@ -514,8 +514,9 @@ export class ReactRouter extends Framework {
}
return {
- wranglerConfig: {
- main: "./workers/app.ts",
+ buildTool: "vite",
+ workerConfig: {
+ entrypoint: "./workers/app.ts",
},
};
}
diff --git a/packages/autoconfig/src/frameworks/solid-start.ts b/packages/autoconfig/src/frameworks/solid-start.ts
index 064106b7e32..679c9f1ed04 100644
--- a/packages/autoconfig/src/frameworks/solid-start.ts
+++ b/packages/autoconfig/src/frameworks/solid-start.ts
@@ -30,13 +30,14 @@ export class SolidStart extends Framework {
}
return {
- wranglerConfig: {
- main: "./.output/server/index.mjs",
- assets: {
- binding: "ASSETS",
- directory: "./.output/public",
+ buildTool: "wrangler",
+ workerConfig: {
+ entrypoint: "./.output/server/index.mjs",
+ env: {
+ ASSETS: { type: "assets" },
},
},
+ buildConfig: { assetsDirectory: "./.output/public" },
};
}
}
diff --git a/packages/autoconfig/src/frameworks/static.ts b/packages/autoconfig/src/frameworks/static.ts
index 0d1d7963797..2a106f960bd 100644
--- a/packages/autoconfig/src/frameworks/static.ts
+++ b/packages/autoconfig/src/frameworks/static.ts
@@ -7,11 +7,9 @@ import type {
export class Static extends Framework {
configure({ outputDir }: ConfigurationOptions): ConfigurationResults {
return {
- wranglerConfig: {
- assets: {
- directory: outputDir,
- },
- },
+ buildTool: "wrangler",
+ workerConfig: {},
+ buildConfig: { assetsDirectory: outputDir },
};
}
}
diff --git a/packages/autoconfig/src/frameworks/sveltekit.ts b/packages/autoconfig/src/frameworks/sveltekit.ts
index d37eeda483a..636434c9862 100644
--- a/packages/autoconfig/src/frameworks/sveltekit.ts
+++ b/packages/autoconfig/src/frameworks/sveltekit.ts
@@ -44,13 +44,14 @@ export class SvelteKit extends Framework {
});
}
return {
- wranglerConfig: {
- main: ".svelte-kit/cloudflare/_worker.js",
- assets: {
- binding: "ASSETS",
- directory: ".svelte-kit/cloudflare",
+ buildTool: "wrangler",
+ workerConfig: {
+ entrypoint: ".svelte-kit/cloudflare/_worker.js",
+ env: {
+ ASSETS: { type: "assets" },
},
},
+ buildConfig: { assetsDirectory: ".svelte-kit/cloudflare" },
};
}
diff --git a/packages/autoconfig/src/frameworks/tanstack.ts b/packages/autoconfig/src/frameworks/tanstack.ts
index 5b8f2baa43d..f783c2f40df 100644
--- a/packages/autoconfig/src/frameworks/tanstack.ts
+++ b/packages/autoconfig/src/frameworks/tanstack.ts
@@ -24,8 +24,9 @@ export class TanstackStart extends Framework {
}
return {
- wranglerConfig: {
- main: "@tanstack/react-start/server-entry",
+ buildTool: "vite",
+ workerConfig: {
+ entrypoint: "@tanstack/react-start/server-entry",
},
};
}
diff --git a/packages/autoconfig/src/frameworks/vike.ts b/packages/autoconfig/src/frameworks/vike.ts
index eccb0bcaeaf..8845011cbb3 100644
--- a/packages/autoconfig/src/frameworks/vike.ts
+++ b/packages/autoconfig/src/frameworks/vike.ts
@@ -60,8 +60,9 @@ export class Vike extends Framework {
}
return {
- wranglerConfig: {
- main: "virtual:photon:cloudflare:server-entry",
+ buildTool: "vite",
+ workerConfig: {
+ entrypoint: "virtual:photon:cloudflare:server-entry",
},
packageJsonScriptsOverrides: {
preview: "vike build && vike preview",
diff --git a/packages/autoconfig/src/frameworks/vite.ts b/packages/autoconfig/src/frameworks/vite.ts
index a8d7a834ff8..f427c7f9be2 100644
--- a/packages/autoconfig/src/frameworks/vite.ts
+++ b/packages/autoconfig/src/frameworks/vite.ts
@@ -8,13 +8,20 @@ import {
transformViteConfig,
} from "./utils/vite-config";
import { installCloudflareVitePlugin } from "./utils/vite-plugin";
+import type { AutoConfigTarget } from "../context";
import type {
ConfigurationOptions,
ConfigurationResults,
} from "./framework-class";
export class Vite extends Framework {
- isConfigured(projectPath: string): boolean {
+ isConfigured(
+ projectPath: string,
+ { target = "cf" }: { target?: AutoConfigTarget } = {}
+ ): boolean {
+ if (target !== "wrangler") {
+ return false;
+ }
if (!hasViteConfig(projectPath)) {
return false;
}
@@ -42,9 +49,10 @@ export class Vite extends Framework {
}
return {
- wranglerConfig: {
+ buildTool: "vite",
+ workerConfig: {
assets: {
- not_found_handling: "single-page-application",
+ notFoundHandling: "single-page-application",
},
},
};
diff --git a/packages/autoconfig/src/frameworks/waku.ts b/packages/autoconfig/src/frameworks/waku.ts
index 08b5a241db4..9325265ddec 100644
--- a/packages/autoconfig/src/frameworks/waku.ts
+++ b/packages/autoconfig/src/frameworks/waku.ts
@@ -45,14 +45,17 @@ export class Waku extends Framework {
}
return {
- wranglerConfig: {
- main: "./src/waku.server",
+ buildTool: "wrangler",
+ workerConfig: {
+ entrypoint: "./src/waku.server",
assets: {
- binding: "ASSETS",
- directory: "./dist/public",
- html_handling: "drop-trailing-slash",
+ htmlHandling: "drop-trailing-slash",
+ },
+ env: {
+ ASSETS: { type: "assets" },
},
},
+ buildConfig: { assetsDirectory: "./dist/public" },
};
}
}
diff --git a/packages/autoconfig/src/index.ts b/packages/autoconfig/src/index.ts
index a2f9df17f52..d925f29d321 100644
--- a/packages/autoconfig/src/index.ts
+++ b/packages/autoconfig/src/index.ts
@@ -1,5 +1,6 @@
export type {
AutoConfigContext,
+ AutoConfigTarget,
AutoConfigLogger,
AutoConfigDialogs,
} from "./context";
@@ -9,6 +10,7 @@ export { runAutoConfig, buildOperationsSummary } from "./run";
export { Framework } from "./frameworks/framework-class";
export type {
+ BuildConfig,
ConfigurationOptions,
ConfigurationResults,
PackageJsonScriptsOverrides,
diff --git a/packages/autoconfig/src/run.ts b/packages/autoconfig/src/run.ts
index 803bb70e716..31ab8328d0d 100644
--- a/packages/autoconfig/src/run.ts
+++ b/packages/autoconfig/src/run.ts
@@ -6,7 +6,11 @@ import {
maybeAppendWranglerToGitIgnoreLikeFile,
maybeAppendWranglerToGitIgnore,
} from "@cloudflare/cli-shared-helpers/gitignore";
-import { installWrangler } from "@cloudflare/cli-shared-helpers/packages";
+import {
+ installPackages,
+ installWrangler,
+} from "@cloudflare/cli-shared-helpers/packages";
+import { convertToWranglerConfig, InputWorkerSchema } from "@cloudflare/config";
import {
DEFAULT_COMPAT_DATE,
FatalError,
@@ -26,18 +30,23 @@ import {
import { getFrameworkPackageInfo } from "./frameworks/all-frameworks";
import { Static } from "./frameworks/static";
import { usesTypescript } from "./uses-typescript";
-import type { AutoConfigContext } from "./context";
+import type { AutoConfigContext, AutoConfigTarget } from "./context";
+import type {
+ BuildConfig,
+ ConfigurationResults,
+} from "./frameworks/framework-class";
import type {
AutoConfigDetails,
AutoConfigDetailsForNonConfiguredProject,
AutoConfigOptions,
AutoConfigSummary,
} from "./types";
+import type { WorkerConfigInput } from "@cloudflare/config";
import type { PackageJSON, RawConfig } from "@cloudflare/workers-utils";
/**
* Runs the full autoconfig flow: displays detected settings, confirms with the user,
- * validates the framework version, runs framework configuration, writes wrangler config,
+ * validates the framework version, runs framework configuration, writes configuration,
* updates package.json scripts, and optionally runs the build command.
*
* @param autoConfigDetails - The detected project details from `getDetailsForAutoConfig()`.
@@ -49,13 +58,14 @@ export async function runAutoConfig(
autoConfigOptions: AutoConfigOptions
): Promise {
const { context } = autoConfigOptions;
+ const target = autoConfigOptions.target ?? "cf";
const { logger } = context;
const dryRun = autoConfigOptions.dryRun === true;
const runBuild = !dryRun && (autoConfigOptions.runBuild ?? true);
const skipConfirmations =
dryRun || autoConfigOptions.skipConfirmations === true;
- const enableWranglerInstallation =
- autoConfigOptions.enableWranglerInstallation ?? true;
+ const enableTargetCliInstallation =
+ autoConfigOptions.enableTargetCliInstallation ?? true;
assertNonConfigured(autoConfigDetails);
@@ -95,17 +105,15 @@ export async function runAutoConfig(
const compatibilityDate = DEFAULT_COMPAT_DATE;
- const wranglerConfig: RawConfig = {
- $schema: "node_modules/wrangler/config-schema.json",
+ const defaultWorkerConfig: WorkerConfigInput = {
name: autoConfigDetails.workerName,
- compatibility_date: compatibilityDate,
+ compatibilityDate,
observability: {
enabled: true,
},
- } satisfies RawConfig;
+ };
const { packageManager } = autoConfigDetails;
-
const isWorkspaceRoot = autoConfigDetails.isWorkspaceRoot ?? false;
const frameworkPackageInfo = getFrameworkPackageInfo(
@@ -121,6 +129,7 @@ export async function runAutoConfig(
const dryRunConfigurationResults =
await autoConfigDetails.framework.configure({
+ target,
outputDir: autoConfigDetails.outputDir,
projectPath: autoConfigDetails.projectPath,
workerName: autoConfigDetails.workerName,
@@ -129,28 +138,41 @@ export async function runAutoConfig(
packageManager,
context,
});
+ const dryRunWorkerConfig = mergeWorkerConfig(
+ defaultWorkerConfig,
+ dryRunConfigurationResults.workerConfig
+ );
+ if (
+ target === "cf" &&
+ dryRunConfigurationResults.buildTool === "wrangler" &&
+ dryRunConfigurationResults.buildConfig &&
+ existsSync(resolve(autoConfigDetails.projectPath, "wrangler.config.ts"))
+ ) {
+ throw new FatalError(
+ "Cannot generate wrangler.config.ts because the file already exists. Remove or rename the existing file, then run autoconfig again.",
+ { telemetryMessage: "autoconfig wrangler config conflict" }
+ );
+ }
const { npx } = packageManager;
const autoConfigSummary = await buildOperationsSummary(
{ ...autoConfigDetails, outputDir: autoConfigDetails.outputDir },
- dryRunConfigurationResults.wranglerConfig === null
- ? null
- : ensureNodejsCompatIsEnabled({
- ...wranglerConfig,
- ...dryRunConfigurationResults.wranglerConfig,
- }),
+ dryRunWorkerConfig,
+ dryRunConfigurationResults,
{
build:
dryRunConfigurationResults.buildCommandOverride ??
autoConfigDetails.buildCommand,
deploy:
dryRunConfigurationResults.deployCommandOverride ??
- `${npx} wrangler deploy`,
+ `${npx} ${target} deploy`,
version:
- dryRunConfigurationResults?.versionCommandOverride ??
- `${npx} wrangler versions upload`,
+ dryRunConfigurationResults.versionCommandOverride ??
+ `${npx} ${target} versions upload`,
},
+ enableTargetCliInstallation,
+ target,
context,
dryRunConfigurationResults.packageJsonScriptsOverrides
);
@@ -179,11 +201,27 @@ export async function runAutoConfig(
`Running autoconfig with:\n${JSON.stringify(autoConfigDetails, null, 2)}...`
);
- if (autoConfigSummary.wranglerInstall && enableWranglerInstallation) {
+ if (autoConfigDetails.packageJson && enableTargetCliInstallation) {
+ if (target === "cf") {
+ await installPackages(packageManager.type, ["cf@latest"], {
+ dev: true,
+ isWorkspaceRoot,
+ });
+ } else {
+ await installWrangler(packageManager.type, isWorkspaceRoot);
+ }
+ }
+
+ if (
+ autoConfigDetails.packageJson &&
+ target === "cf" &&
+ dryRunConfigurationResults.buildTool === "wrangler"
+ ) {
await installWrangler(packageManager.type, isWorkspaceRoot);
}
const configurationResults = await autoConfigDetails.framework.configure({
+ target,
outputDir: autoConfigDetails.outputDir,
projectPath: autoConfigDetails.projectPath,
workerName: autoConfigDetails.workerName,
@@ -192,6 +230,10 @@ export async function runAutoConfig(
packageManager,
context,
});
+ const workerConfig = mergeWorkerConfig(
+ defaultWorkerConfig,
+ configurationResults.workerConfig
+ );
if (autoConfigDetails.packageJson) {
const packageJsonPath = resolve(
@@ -218,13 +260,31 @@ export async function runAutoConfig(
);
}
- if (configurationResults.wranglerConfig !== null) {
- // `saveWranglerJsonc()` reconciles the Node.js compatibility flags itself,
- // once it has merged this with any config already on disk.
- await saveWranglerJsonc(autoConfigDetails.projectPath, {
- ...wranglerConfig,
- ...configurationResults.wranglerConfig,
- });
+ if (target === "wrangler") {
+ const wranglerConfig = getWranglerConfig(
+ workerConfig,
+ configurationResults
+ );
+ if (wranglerConfig !== null) {
+ // `saveWranglerJsonc()` reconciles the Node.js compatibility flags itself,
+ // once it has merged this with any config already on disk.
+ await saveWranglerJsonc(autoConfigDetails.projectPath, wranglerConfig);
+ }
+ }
+
+ if (target === "cf") {
+ if (workerConfig !== null) {
+ await saveCloudflareConfig(autoConfigDetails.projectPath, workerConfig);
+ }
+ if (
+ configurationResults.buildTool === "wrangler" &&
+ configurationResults.buildConfig
+ ) {
+ await saveWranglerConfigTs(
+ autoConfigDetails.projectPath,
+ configurationResults.buildConfig
+ );
+ }
}
maybeAppendWranglerToGitIgnore(autoConfigDetails.projectPath);
@@ -250,6 +310,58 @@ export async function runAutoConfig(
return autoConfigSummary;
}
+/**
+ * Applies the common Worker defaults to framework-provided configuration.
+ *
+ * @param defaultWorkerConfig The common Worker configuration defaults
+ * @param workerConfig The framework-provided Worker configuration
+ * @returns The merged Worker configuration, or `null` when an external tool owns it
+ */
+function mergeWorkerConfig(
+ defaultWorkerConfig: WorkerConfigInput,
+ workerConfig: Partial | null
+): WorkerConfigInput | null {
+ return workerConfig === null
+ ? null
+ : { ...defaultWorkerConfig, ...workerConfig };
+}
+
+/**
+ * Converts framework configuration results into the legacy Wrangler format.
+ *
+ * @param workerConfig The resolved Worker configuration
+ * @param configurationResults The framework configuration results
+ * @returns The Wrangler configuration, or `null` when an external tool owns it
+ */
+function getWranglerConfig(
+ workerConfig: WorkerConfigInput | null,
+ configurationResults: ConfigurationResults
+): RawConfig | null {
+ if (workerConfig === null) {
+ return null;
+ }
+
+ const parsedWorkerConfig = InputWorkerSchema.parse({
+ type: "worker",
+ ...workerConfig,
+ });
+ const convertedWranglerConfig = convertToWranglerConfig(parsedWorkerConfig);
+ const wranglerConfig = ensureNodejsCompatIsEnabled({
+ $schema: "node_modules/wrangler/config-schema.json",
+ ...convertedWranglerConfig,
+ ...(configurationResults.buildConfig?.assetsDirectory
+ ? {
+ assets: {
+ ...convertedWranglerConfig.assets,
+ directory: configurationResults.buildConfig.assetsDirectory,
+ },
+ }
+ : {}),
+ });
+
+ return wranglerConfig;
+}
+
/**
* Given a wrangler config object this function makes sure that Node.js compatibility is enabled.
*
@@ -317,14 +429,79 @@ export async function saveWranglerJsonc(
);
}
+/**
+ * Writes the Worker configuration used by `cf`.
+ *
+ * @param projectPath The project directory
+ * @param workerConfig The Worker configuration to write
+ */
+async function saveCloudflareConfig(
+ projectPath: string,
+ workerConfig: WorkerConfigInput
+): Promise {
+ await writeFile(
+ resolve(projectPath, "cloudflare.config.ts"),
+ renderCloudflareConfig(workerConfig)
+ );
+}
+
+/**
+ * Writes the Wrangler build-tool configuration used by `cf`.
+ *
+ * @param projectPath The project directory
+ * @param buildConfig The build-tool configuration to write
+ */
+async function saveWranglerConfigTs(
+ projectPath: string,
+ buildConfig: BuildConfig
+): Promise {
+ await writeFile(
+ resolve(projectPath, "wrangler.config.ts"),
+ renderWranglerConfigTs(buildConfig)
+ );
+}
+
+/**
+ * Renders a Worker configuration as a `cloudflare.config.ts` module.
+ *
+ * @param workerConfig The Worker configuration to render
+ * @returns The configuration module source
+ */
+function renderCloudflareConfig(workerConfig: WorkerConfigInput): string {
+ return `import { defineWorker } from "cf/config";\n\nexport default defineWorker(${JSON.stringify(workerConfig, null, 2)});\n`;
+}
+
+/**
+ * Renders build-tool configuration as a `wrangler.config.ts` module.
+ *
+ * @param buildConfig The build-tool configuration to render
+ * @returns The configuration module source
+ */
+function renderWranglerConfigTs(buildConfig: BuildConfig): string {
+ return `import { defineWranglerConfig } from "wrangler/experimental-config";\n\nexport default defineWranglerConfig(${JSON.stringify(buildConfig, null, 2)});\n`;
+}
+
+/**
+ * Indents rendered file content for display in the operation summary.
+ *
+ * @param content The file content to indent
+ * @returns The indented content
+ */
+function indentFileContent(content: string): string {
+ return " " + content.trimEnd().replace(/\n/g, "\n ");
+}
+
/**
* Builds a summary of all operations that autoconfig will (or did) perform,
- * including package installation, package.json script updates, wrangler config
+ * including package installation, package.json script updates, configuration
* creation, and framework-specific configuration.
*
* @param autoConfigDetails - The detected project details.
- * @param wranglerConfigToWrite - The wrangler config object to write, or `null` if not applicable.
+ * @param workerConfig - The resolved Worker configuration.
+ * @param configurationResults - The framework configuration results.
* @param projectCommands - The build, deploy, and version commands for the project.
+ * @param enableTargetCliInstallation - Whether to install the selected target CLI package.
+ * @param target - The configuration target.
* @param context - The autoconfig context providing logger and other dependencies.
* @param packageJsonScriptsOverrides - Optional overrides for package.json script entries.
* @returns A summary object describing all planned operations.
@@ -333,26 +510,33 @@ export async function buildOperationsSummary(
autoConfigDetails: AutoConfigDetailsForNonConfiguredProject & {
outputDir: NonNullable;
},
- wranglerConfigToWrite: RawConfig | null,
+ workerConfig: WorkerConfigInput | null,
+ configurationResults: ConfigurationResults,
projectCommands: {
build?: string;
deploy: string;
version?: string;
},
+ enableTargetCliInstallation: boolean,
+ target: AutoConfigTarget,
context: AutoConfigContext,
packageJsonScriptsOverrides?: PackageJsonScriptsOverrides
): Promise {
const { logger } = context;
logger.log("");
+ const wranglerConfig =
+ target === "wrangler"
+ ? getWranglerConfig(workerConfig, configurationResults)
+ : null;
const summary: AutoConfigSummary = {
- wranglerInstall: false,
scripts: {},
- ...(wranglerConfigToWrite !== null
- ? {
- wranglerConfig: wranglerConfigToWrite,
- }
- : {}),
+ ...(target === "wrangler"
+ ? { wranglerConfig: wranglerConfig ?? undefined }
+ : {
+ workerConfig: workerConfig ?? undefined,
+ buildConfig: configurationResults.buildConfig,
+ }),
outputDir: autoConfigDetails.outputDir,
frameworkId: autoConfigDetails.framework.id,
buildCommand: projectCommands.build,
@@ -360,30 +544,49 @@ export async function buildOperationsSummary(
versionCommand: projectCommands.version,
};
+ const packagesToInstall = new Set();
if (autoConfigDetails.packageJson) {
- // If there is a package.json file we will want to install wrangler
- summary.wranglerInstall = true;
+ if (enableTargetCliInstallation) {
+ packagesToInstall.add(target);
+ }
+ if (configurationResults.buildTool === "vite") {
+ packagesToInstall.add("@cloudflare/vite-plugin");
+ } else if (
+ target === "cf" &&
+ configurationResults.buildTool === "wrangler"
+ ) {
+ packagesToInstall.add("wrangler");
+ }
+ }
+ if (packagesToInstall.size > 0) {
logger.log("📦 Install packages:");
- logger.log(` - wrangler (devDependency)`);
+ for (const packageName of packagesToInstall) {
+ logger.log(` - ${packageName} (devDependency)`);
+ }
logger.log("");
+ }
+ if (autoConfigDetails.packageJson) {
+ const scriptOverrides =
+ target === "wrangler" ? packageJsonScriptsOverrides : undefined;
+ const buildCommandPrefix = autoConfigDetails.buildCommand
+ ? `${autoConfigDetails.buildCommand} && `
+ : "";
summary.scripts = {
deploy:
- packageJsonScriptsOverrides?.deploy ??
- (autoConfigDetails.buildCommand
- ? `${autoConfigDetails.buildCommand} && wrangler deploy`
- : `wrangler deploy`),
+ scriptOverrides?.deploy ??
+ `${buildCommandPrefix}${target} deploy${
+ target === "cf" && autoConfigDetails.buildCommand ? " --no-build" : ""
+ }`,
preview:
- packageJsonScriptsOverrides?.preview ??
- (autoConfigDetails.buildCommand
- ? `${autoConfigDetails.buildCommand} && wrangler dev`
- : `wrangler dev`),
+ scriptOverrides?.preview ??
+ `${target === "wrangler" ? buildCommandPrefix : ""}${target} dev`,
};
const containsServerSideCode =
// If there is an entrypoint then we know that there is server side code
- !!wranglerConfigToWrite?.main;
+ !!workerConfig?.entrypoint;
if (
// If there is no server side code, then there is no need to add the cf-typegen script
@@ -392,7 +595,7 @@ export async function buildOperationsSummary(
!("cf-typegen" in (autoConfigDetails.packageJson.scripts ?? {}))
) {
summary.scripts["cf-typegen"] =
- packageJsonScriptsOverrides?.typegen ?? "wrangler types";
+ scriptOverrides?.typegen ?? `${target} types`;
}
logger.log("📝 Update package.json scripts:");
@@ -402,7 +605,27 @@ export async function buildOperationsSummary(
logger.log("");
}
- if (wranglerConfigToWrite) {
+ if (target === "cf" && workerConfig) {
+ logger.log("📄 Create cloudflare.config.ts:");
+ logger.log(indentFileContent(renderCloudflareConfig(workerConfig)));
+ logger.log("");
+ }
+
+ if (
+ target === "cf" &&
+ configurationResults.buildTool === "wrangler" &&
+ configurationResults.buildConfig
+ ) {
+ logger.log("📄 Create wrangler.config.ts:");
+ logger.log(
+ indentFileContent(
+ renderWranglerConfigTs(configurationResults.buildConfig)
+ )
+ );
+ logger.log("");
+ }
+
+ if (target === "wrangler" && wranglerConfig) {
const wranglerConfigPath = resolve(
autoConfigDetails.projectPath,
"wrangler.jsonc"
@@ -412,8 +635,7 @@ export async function buildOperationsSummary(
configExists ? "📄 Update wrangler.jsonc:" : "📄 Create wrangler.jsonc:"
);
logger.log(
- " " +
- JSON.stringify(wranglerConfigToWrite, null, 2).replace(/\n/g, "\n ")
+ " " + JSON.stringify(wranglerConfig, null, 2).replace(/\n/g, "\n ")
);
logger.log("");
}
@@ -421,7 +643,9 @@ export async function buildOperationsSummary(
if (
autoConfigDetails.framework &&
!(autoConfigDetails.framework instanceof Static) &&
- !autoConfigDetails.framework.isConfigured(autoConfigDetails.projectPath)
+ !autoConfigDetails.framework.isConfigured(autoConfigDetails.projectPath, {
+ target,
+ })
) {
summary.frameworkConfiguration =
autoConfigDetails.framework.configurationDescription ??
diff --git a/packages/autoconfig/src/types.ts b/packages/autoconfig/src/types.ts
index 3cd97d09e3d..686cf4c10e6 100644
--- a/packages/autoconfig/src/types.ts
+++ b/packages/autoconfig/src/types.ts
@@ -1,5 +1,7 @@
-import type { AutoConfigContext } from "./context";
+import type { AutoConfigContext, AutoConfigTarget } from "./context";
import type { Framework } from "./frameworks/framework-class";
+import type { BuildConfig } from "./frameworks/framework-class";
+import type { WorkerConfigInput } from "@cloudflare/config";
import type { PackageManager } from "@cloudflare/workers-utils";
import type { PackageJSON, RawConfig } from "@cloudflare/workers-utils";
@@ -17,6 +19,8 @@ type AutoConfigDetailsBase = {
configured: boolean;
/** Details about the detected framework. It can be a JS framework or 'Static' if no actual JS framework is used. */
framework: Framework;
+ /** The dev command used to run the project locally (if any) */
+ devCommand?: string;
/** The build command used to build the project (if any) */
buildCommand?: string;
/** The output directory (if no framework is used, points to the raw asset files) */
@@ -45,6 +49,8 @@ export type AutoConfigDetails =
| AutoConfigDetailsForNonConfiguredProject;
export type AutoConfigOptions = {
+ /** The configuration target, defaults to cf. */
+ target?: AutoConfigTarget;
/** The autoconfig context providing logger, dialogs, and other dependencies. */
context: AutoConfigContext;
/** Whether to run autoconfig without actually applying any filesystem modification (default: false) */
@@ -62,14 +68,15 @@ export type AutoConfigOptions = {
*/
skipConfirmations?: boolean;
/**
- * Whether to install Wrangler during autoconfig
+ * Whether to install the selected target CLI during autoconfig.
*/
- enableWranglerInstallation?: boolean;
+ enableTargetCliInstallation?: boolean;
};
export type AutoConfigSummary = {
scripts: Record;
- wranglerInstall: boolean;
+ workerConfig?: WorkerConfigInput;
+ buildConfig?: BuildConfig;
wranglerConfig?: RawConfig;
frameworkConfiguration?: string;
outputDir: string;
diff --git a/packages/autoconfig/tests/details/display-auto-config-details.test.ts b/packages/autoconfig/tests/details/display-auto-config-details.test.ts
index 14dbff19a74..25183b31ce3 100644
--- a/packages/autoconfig/tests/details/display-auto-config-details.test.ts
+++ b/packages/autoconfig/tests/details/display-auto-config-details.test.ts
@@ -50,7 +50,7 @@ describe("autoconfig details - displayAutoConfigDetails()", () => {
isConfigured: () => false,
configure: () =>
({
- wranglerConfig: {},
+ workerConfig: {},
}) satisfies ReturnType,
} as unknown as Framework,
buildCommand: "astro build",
diff --git a/packages/autoconfig/tests/details/get-details-for-auto-config.test.ts b/packages/autoconfig/tests/details/get-details-for-auto-config.test.ts
index 9d1190f6276..4dbeae3acdc 100644
--- a/packages/autoconfig/tests/details/get-details-for-auto-config.test.ts
+++ b/packages/autoconfig/tests/details/get-details-for-auto-config.test.ts
@@ -20,17 +20,41 @@ describe("autoconfig details - getDetailsForAutoConfig()", () => {
vi.unstubAllGlobals();
});
- it("should set configured: true if a configPath exists", async ({
+ it("should set configured: true if a configPath exists during legacy Wrangler detection", async ({
expect,
}) => {
await expect(
details.getDetailsForAutoConfig({
wranglerConfig: { configPath: "/tmp" } as Config,
+ target: "wrangler",
context,
})
).resolves.toMatchObject({ configured: true });
});
+ it("should migrate an existing Wrangler project by default", async ({
+ expect,
+ }) => {
+ await writeFile("index.html", "Hello World
");
+
+ await expect(
+ details.getDetailsForAutoConfig({
+ wranglerConfig: { configPath: "/tmp" } as Config,
+ context,
+ })
+ ).resolves.toMatchObject({ configured: false });
+ });
+
+ it("should default to cloudflare.config.ts configuration detection", async ({
+ expect,
+ }) => {
+ await writeFile("cloudflare.config.ts", "export default {};");
+
+ await expect(
+ details.getDetailsForAutoConfig({ context })
+ ).resolves.toMatchObject({ configured: true });
+ });
+
// Check that Astro is detected. We don't want to duplicate the tests of @netlify/build-info
// by exhaustively checking every possible combination
it.for(["npm", "pnpm"] as const)(
@@ -59,6 +83,7 @@ describe("autoconfig details - getDetailsForAutoConfig()", () => {
details.getDetailsForAutoConfig({ context })
).resolves.toMatchObject({
buildCommand: pm === "pnpm" ? "pnpm astro build" : "npx astro build",
+ devCommand: pm === "pnpm" ? "pnpm astro dev" : "npx astro dev",
configured: false,
outputDir: "dist",
packageJson: {
diff --git a/packages/autoconfig/tests/frameworks/angular.test.ts b/packages/autoconfig/tests/frameworks/angular.test.ts
index b5aa1cfda38..db1b275e18e 100644
--- a/packages/autoconfig/tests/frameworks/angular.test.ts
+++ b/packages/autoconfig/tests/frameworks/angular.test.ts
@@ -10,6 +10,7 @@ import type { AutoConfigFrameworkPackageInfo } from "../../src/frameworks";
const context = createMockContext();
const BASE_OPTIONS = {
+ target: "cf" as const,
projectPath: process.cwd(),
workerName: "my-angular-app",
outputDir: "dist/my-angular-app/",
@@ -72,16 +73,13 @@ describe("Angular framework configure()", () => {
await mkdir(resolve("src"), { recursive: true });
});
- it("returns assets-only wranglerConfig", async ({ expect }) => {
+ it("returns assets-only configuration", async ({ expect }) => {
const framework = new Angular({ id: "angular", name: "Angular" });
const result = await framework.configure(BASE_OPTIONS);
- expect(result.wranglerConfig).toEqual({
- assets: {
- directory: "dist/my-angular-app/",
- },
- });
- expect(result.wranglerConfig).not.toHaveProperty("main");
+ expect(result.workerConfig).toEqual({});
+ expect(result.buildConfig?.assetsDirectory).toBe("dist/my-angular-app/");
+ expect(result.workerConfig).not.toHaveProperty("entrypoint");
});
it("sets configurationDescription for SPA", async ({ expect }) => {
@@ -134,9 +132,8 @@ describe("Angular framework configure()", () => {
dryRun: true,
});
- expect(result.wranglerConfig).toEqual({
- assets: { directory: "dist/my-angular-app/" },
- });
+ expect(result.workerConfig).toEqual({});
+ expect(result.buildConfig?.assetsDirectory).toBe("dist/my-angular-app/");
expect(installSpy).not.toHaveBeenCalled();
});
});
@@ -169,16 +166,15 @@ describe("Angular framework configure()", () => {
await mkdir(resolve("src"), { recursive: true });
});
- it("returns assets-only wranglerConfig when ssr is false", async ({
+ it("returns assets-only configuration when ssr is false", async ({
expect,
}) => {
const framework = new Angular({ id: "angular", name: "Angular" });
const result = await framework.configure(BASE_OPTIONS);
- expect(result.wranglerConfig).toEqual({
- assets: { directory: "dist/my-angular-app/" },
- });
- expect(result.wranglerConfig).not.toHaveProperty("main");
+ expect(result.workerConfig).toEqual({});
+ expect(result.buildConfig?.assetsDirectory).toBe("dist/my-angular-app/");
+ expect(result.workerConfig).not.toHaveProperty("entrypoint");
});
it("sets SPA configurationDescription when ssr is false", async ({
@@ -221,7 +217,7 @@ describe("Angular framework configure()", () => {
await mkdir(resolve("src"), { recursive: true });
});
- it("returns SSR wranglerConfig without crashing", async ({ expect }) => {
+ it("returns SSR configuration without crashing", async ({ expect }) => {
await mockAngularCoreVersion("21.0.0");
const framework = new Angular({ id: "angular", name: "Angular" });
framework.validateFrameworkVersion(
@@ -231,13 +227,15 @@ describe("Angular framework configure()", () => {
);
const result = await framework.configure(BASE_OPTIONS);
- expect(result.wranglerConfig).toEqual({
- main: "./dist/server/server.mjs",
- assets: {
- binding: "ASSETS",
- directory: "dist/my-angular-app/browser",
+ expect(result.workerConfig).toEqual({
+ entrypoint: "./dist/server/server.mjs",
+ env: {
+ ASSETS: { type: "assets" },
},
});
+ expect(result.buildConfig?.assetsDirectory).toBe(
+ "dist/my-angular-app/browser"
+ );
});
it("sets experimentalPlatform in angular.json when ssr was true (Angular <22)", async ({
@@ -316,7 +314,7 @@ describe("Angular framework configure()", () => {
await mkdir(resolve("src"), { recursive: true });
});
- it("returns SSR wranglerConfig with main and assets", async ({
+ it("returns SSR configuration with an entrypoint and assets", async ({
expect,
}) => {
await mockAngularCoreVersion("21.0.0");
@@ -328,13 +326,15 @@ describe("Angular framework configure()", () => {
);
const result = await framework.configure(BASE_OPTIONS);
- expect(result.wranglerConfig).toEqual({
- main: "./dist/server/server.mjs",
- assets: {
- binding: "ASSETS",
- directory: "dist/my-angular-app/browser",
+ expect(result.workerConfig).toEqual({
+ entrypoint: "./dist/server/server.mjs",
+ env: {
+ ASSETS: { type: "assets" },
},
});
+ expect(result.buildConfig?.assetsDirectory).toBe(
+ "dist/my-angular-app/browser"
+ );
});
it("sets SSR configurationDescription", async ({ expect }) => {
@@ -436,7 +436,7 @@ describe("Angular framework configure()", () => {
});
// Config is still returned
- expect(result.wranglerConfig).toHaveProperty("main");
+ expect(result.workerConfig).toHaveProperty("entrypoint");
// But side effects are skipped
expect(existsSync(resolve("src/server.ts"))).toBe(false);
expect(installSpy).not.toHaveBeenCalled();
diff --git a/packages/autoconfig/tests/frameworks/react-router.test.ts b/packages/autoconfig/tests/frameworks/react-router.test.ts
index 64717277b94..7f96ab764fb 100644
--- a/packages/autoconfig/tests/frameworks/react-router.test.ts
+++ b/packages/autoconfig/tests/frameworks/react-router.test.ts
@@ -33,6 +33,7 @@ const context = createMockContext();
function getBaseOptions() {
return {
+ target: "cf" as const,
projectPath: process.cwd(),
outputDir: "build/",
workerName: "my-react-router-app",
@@ -422,8 +423,8 @@ describe("React Router framework configure()", () => {
dryRun: true,
});
- expect(result.wranglerConfig).toEqual({
- main: "./workers/app.ts",
+ expect(result.workerConfig).toEqual({
+ entrypoint: "./workers/app.ts",
});
expect(existsSync(resolve("workers/app.ts"))).toBe(false);
expect(existsSync(resolve("app/entry.server.tsx"))).toBe(false);
@@ -444,8 +445,8 @@ describe("React Router framework configure()", () => {
const framework = createFramework("7.16.0");
const result = await framework.configure(getBaseOptions());
- expect(result.wranglerConfig).toEqual({
- main: "./workers/app.ts",
+ expect(result.workerConfig).toEqual({
+ entrypoint: "./workers/app.ts",
});
});
});
diff --git a/packages/autoconfig/tests/frameworks/validate-framework-version.test.ts b/packages/autoconfig/tests/frameworks/validate-framework-version.test.ts
index 440aec9d23f..1bc851e533f 100644
--- a/packages/autoconfig/tests/frameworks/validate-framework-version.test.ts
+++ b/packages/autoconfig/tests/frameworks/validate-framework-version.test.ts
@@ -15,7 +15,7 @@ vi.mock("../../src/frameworks/utils/packages");
/** Minimal concrete subclass so we can instantiate the abstract Framework */
class TestFramework extends Framework {
configure(_options: ConfigurationOptions): ConfigurationResults {
- return { wranglerConfig: null };
+ return { workerConfig: null };
}
}
diff --git a/packages/autoconfig/tests/frameworks/vike.test.ts b/packages/autoconfig/tests/frameworks/vike.test.ts
index 2cdaf3f62ce..18f1c25c203 100644
--- a/packages/autoconfig/tests/frameworks/vike.test.ts
+++ b/packages/autoconfig/tests/frameworks/vike.test.ts
@@ -19,6 +19,7 @@ const context = createMockContext();
function getBaseOptions() {
return {
+ target: "cf" as const,
projectPath: process.cwd(),
workerName: "my-vike-app",
outputDir: "",
@@ -285,12 +286,12 @@ export default {
);
});
- it("returns correct wranglerConfig", async ({ expect }) => {
+ it("returns the Worker config", async ({ expect }) => {
const framework = new Vike({ id: "vike", name: "Vike" });
const result = await framework.configure(getBaseOptions());
- expect(result.wranglerConfig).toEqual({
- main: "virtual:photon:cloudflare:server-entry",
+ expect(result.workerConfig).toEqual({
+ entrypoint: "virtual:photon:cloudflare:server-entry",
});
});
diff --git a/packages/autoconfig/tests/frameworks/vite.test.ts b/packages/autoconfig/tests/frameworks/vite.test.ts
index 68757ca5ca2..3b074f6ecf3 100644
--- a/packages/autoconfig/tests/frameworks/vite.test.ts
+++ b/packages/autoconfig/tests/frameworks/vite.test.ts
@@ -10,6 +10,7 @@ import { createMockContext } from "../helpers/mock-context";
const context = createMockContext();
const BASE_OPTIONS = {
+ target: "cf" as const,
projectPath: ".",
workerName: "my-vite-app",
outputDir: "dist",
@@ -31,6 +32,21 @@ describe("Vite framework", () => {
const framework = new Vite({ id: "vite", name: "Vite" });
expect(framework.isConfigured(".")).toBe(false);
});
+
+ it("only treats the Cloudflare plugin as configured in legacy Wrangler mode", async ({
+ expect,
+ }) => {
+ await writeFile(
+ "vite.config.ts",
+ `import { cloudflare } from "@cloudflare/vite-plugin";
+ import { defineConfig } from "vite";
+ export default defineConfig({ plugins: [cloudflare()] });`
+ );
+ const framework = new Vite({ id: "vite", name: "Vite" });
+
+ expect(framework.isConfigured(".")).toBe(false);
+ expect(framework.isConfigured(".", { target: "wrangler" })).toBe(true);
+ });
});
describe("configure()", () => {
@@ -47,11 +63,12 @@ describe("Vite framework", () => {
);
expect(content).toContain("plugins: [cloudflare()]");
- expect(result.wranglerConfig).toEqual({
+ expect(result.workerConfig).toEqual({
assets: {
- not_found_handling: "single-page-application",
+ notFoundHandling: "single-page-application",
},
});
+ expect(result.buildTool).toBe("vite");
});
it("uses .ts extension when the project has a tsconfig.json", async ({
@@ -101,9 +118,9 @@ export default defineConfig({
expect(existsSync("vite.config.ts")).toBe(false);
expect(existsSync("vite.config.js")).toBe(false);
- expect(result.wranglerConfig).toEqual({
+ expect(result.workerConfig).toEqual({
assets: {
- not_found_handling: "single-page-application",
+ notFoundHandling: "single-page-application",
},
});
});
diff --git a/packages/autoconfig/tests/run-summary.test.ts b/packages/autoconfig/tests/run-summary.test.ts
index 8df4ca3b2e9..d6008f87e47 100644
--- a/packages/autoconfig/tests/run-summary.test.ts
+++ b/packages/autoconfig/tests/run-summary.test.ts
@@ -6,12 +6,11 @@ import { Astro } from "../src/frameworks/astro";
import { Static } from "../src/frameworks/static";
import { buildOperationsSummary } from "../src/run";
import { createMockContext } from "./helpers/mock-context";
-import type { RawConfig } from "@cloudflare/workers-utils";
+import type { WorkerConfigInput } from "@cloudflare/config";
-const testRawConfig: RawConfig = {
- $schema: "node_modules/wrangler/config-schema.json",
+const testWorkerConfig: WorkerConfigInput = {
name: "worker-name",
- compatibility_date: "2025-01-01",
+ compatibilityDate: "2026-08-04",
observability: {
enabled: true,
},
@@ -34,12 +33,15 @@ describe("autoconfig run - buildOperationsSummary()", () => {
framework: new Static({ id: "static", name: "Static" }),
packageManager: NpmPackageManager,
},
- testRawConfig,
+ testWorkerConfig,
+ { workerConfig: testWorkerConfig },
{
build: "npm run build",
deploy: "npx wrangler deploy",
version: "npx wrangler versions upload",
},
+ false,
+ "wrangler",
context
);
@@ -49,7 +51,7 @@ describe("autoconfig run - buildOperationsSummary()", () => {
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "worker-name",
- "compatibility_date": "2025-01-01",
+ "compatibility_date": "2026-08-04",
"observability": {
"enabled": true
}
@@ -67,13 +69,12 @@ describe("autoconfig run - buildOperationsSummary()", () => {
"versionCommand": "npx wrangler versions upload",
"wranglerConfig": {
"$schema": "node_modules/wrangler/config-schema.json",
- "compatibility_date": "2025-01-01",
+ "compatibility_date": "2026-08-04",
"name": "worker-name",
"observability": {
"enabled": true,
},
},
- "wranglerInstall": false,
}
`);
});
@@ -94,12 +95,15 @@ describe("autoconfig run - buildOperationsSummary()", () => {
framework: new Static({ id: "static", name: "Static" }),
packageManager: NpmPackageManager,
},
- testRawConfig,
+ testWorkerConfig,
+ { workerConfig: testWorkerConfig },
{
build: "npm run build",
deploy: "npx wrangler deploy",
version: "npx wrangler versions upload",
},
+ true,
+ "wrangler",
context
);
@@ -123,13 +127,12 @@ describe("autoconfig run - buildOperationsSummary()", () => {
"versionCommand": "npx wrangler versions upload",
"wranglerConfig": {
"$schema": "node_modules/wrangler/config-schema.json",
- "compatibility_date": "2025-01-01",
+ "compatibility_date": "2026-08-04",
"name": "worker-name",
"observability": {
"enabled": true,
},
},
- "wranglerInstall": true,
}
`);
});
@@ -152,12 +155,15 @@ describe("autoconfig run - buildOperationsSummary()", () => {
framework: new Static({ id: "static", name: "Static" }),
packageManager: NpmPackageManager,
},
- testRawConfig,
+ testWorkerConfig,
+ { workerConfig: testWorkerConfig },
{
build: "npm run build",
deploy: "npx wrangler deploy",
version: "npx wrangler versions upload",
},
+ true,
+ "wrangler",
context
);
@@ -181,17 +187,69 @@ describe("autoconfig run - buildOperationsSummary()", () => {
"versionCommand": "npx wrangler versions upload",
"wranglerConfig": {
"$schema": "node_modules/wrangler/config-schema.json",
- "compatibility_date": "2025-01-01",
+ "compatibility_date": "2026-08-04",
"name": "worker-name",
"observability": {
"enabled": true,
},
},
- "wranglerInstall": true,
}
`);
});
+ test("uses cf scripts and previews package installation and generated config files", async ({
+ expect,
+ }) => {
+ const buildConfig = { assetsDirectory: "dist" };
+ const summary = await buildOperationsSummary(
+ {
+ workerName: "worker-name",
+ projectPath: "",
+ packageJson: { name: "my-project" },
+ configured: false,
+ outputDir: "dist",
+ buildCommand: "npm run build",
+ framework: new Static({ id: "static", name: "Static" }),
+ packageManager: NpmPackageManager,
+ },
+ testWorkerConfig,
+ {
+ buildTool: "wrangler",
+ workerConfig: testWorkerConfig,
+ buildConfig,
+ },
+ {
+ build: "npm run build",
+ deploy: "cf deploy",
+ },
+ true,
+ "cf",
+ context,
+ {
+ deploy: "wrangler deploy",
+ preview: "wrangler dev",
+ }
+ );
+
+ expect(summary.scripts).toEqual({
+ deploy: "npm run build && cf deploy --no-build",
+ preview: "cf dev",
+ });
+ expect(std.out).toContain(
+ dedent`
+ 📦 Install packages:
+ - cf (devDependency)
+ - wrangler (devDependency)
+ `
+ );
+ expect(std.out).toContain(' import { defineWorker } from "cf/config";');
+ expect(std.out).toContain(" export default defineWorker({");
+ expect(std.out).toContain(
+ ' import { defineWranglerConfig } from "wrangler/experimental-config";'
+ );
+ expect(std.out).toContain(" export default defineWranglerConfig({");
+ });
+
test("shows that when needed a framework specific configuration will be run", async ({
expect,
}) => {
@@ -204,11 +262,14 @@ describe("autoconfig run - buildOperationsSummary()", () => {
outputDir: "dist",
packageManager: NpmPackageManager,
},
- testRawConfig,
+ testWorkerConfig,
+ { workerConfig: testWorkerConfig },
{
build: "npm run build",
deploy: "npx wrangler deploy",
},
+ false,
+ "wrangler",
context
);
@@ -235,11 +296,14 @@ describe("autoconfig run - buildOperationsSummary()", () => {
outputDir: "public",
packageManager: NpmPackageManager,
},
- testRawConfig,
+ testWorkerConfig,
+ { workerConfig: testWorkerConfig },
{
build: "npm run build",
deploy: "npx wrangler deploy",
},
+ false,
+ "wrangler",
context
);
diff --git a/packages/autoconfig/tests/run.test.ts b/packages/autoconfig/tests/run.test.ts
new file mode 100644
index 00000000000..df1a3b74166
--- /dev/null
+++ b/packages/autoconfig/tests/run.test.ts
@@ -0,0 +1,244 @@
+import { existsSync, readFileSync } from "node:fs";
+import * as cliPackages from "@cloudflare/cli-shared-helpers/packages";
+import { NpmPackageManager } from "@cloudflare/workers-utils";
+import {
+ mockConsoleMethods,
+ runInTempDir,
+ seed,
+} from "@cloudflare/workers-utils/test-helpers";
+import { describe, it, vi } from "vitest";
+import { Framework } from "../src/frameworks/framework-class";
+import { Static } from "../src/frameworks/static";
+import { runAutoConfig } from "../src/run";
+import { createMockContext } from "./helpers/mock-context";
+import type { ConfigurationResults } from "../src/frameworks/framework-class";
+
+class ExternalWorkerConfigFramework extends Framework {
+ configure(): ConfigurationResults {
+ return {
+ buildTool: "wrangler",
+ workerConfig: null,
+ buildConfig: { assetsDirectory: "dist" },
+ };
+ }
+}
+
+class ViteBuildToolFramework extends Framework {
+ configure(): ConfigurationResults {
+ return {
+ buildTool: "vite",
+ workerConfig: { entrypoint: "src/index.ts" },
+ };
+ }
+}
+
+describe("runAutoConfig()", () => {
+ runInTempDir();
+ mockConsoleMethods();
+
+ it("creates new configuration and cf scripts by default", async ({
+ expect,
+ }) => {
+ const installWrangler = vi
+ .spyOn(cliPackages, "installWrangler")
+ .mockResolvedValue();
+ const packageJson = {
+ name: "my-static-app",
+ scripts: { build: "generate && vite build" },
+ };
+ await seed({
+ "package.json": JSON.stringify(packageJson),
+ "public/index.html": "Hello World
",
+ });
+
+ const summary = await runAutoConfig(
+ {
+ configured: false,
+ projectPath: process.cwd(),
+ workerName: "my-static-app",
+ framework: new Static({ id: "static", name: "Static" }),
+ buildCommand: "npm run build",
+ outputDir: "public",
+ packageJson,
+ packageManager: NpmPackageManager,
+ },
+ {
+ context: createMockContext(),
+ skipConfirmations: true,
+ runBuild: false,
+ enableTargetCliInstallation: false,
+ }
+ );
+
+ expect(summary.workerConfig).toMatchObject({
+ name: "my-static-app",
+ observability: { enabled: true },
+ });
+ expect(summary.buildConfig).toEqual({ assetsDirectory: "public" });
+ expect(summary.deployCommand).toBe("npx cf deploy");
+ expect(summary.versionCommand).toBe("npx cf versions upload");
+ expect(readFileSync("cloudflare.config.ts", "utf8")).toContain(
+ 'import { defineWorker } from "cf/config";\n\nexport default defineWorker({\n "name": "my-static-app"'
+ );
+ expect(readFileSync("wrangler.config.ts", "utf8")).toContain(
+ 'import { defineWranglerConfig } from "wrangler/experimental-config";\n\nexport default defineWranglerConfig({\n "assetsDirectory": "public"'
+ );
+ expect(existsSync("wrangler.jsonc")).toBe(false);
+ expect(installWrangler).toHaveBeenCalledWith("npm", false);
+ expect(JSON.parse(readFileSync("package.json", "utf8"))).toMatchObject({
+ scripts: {
+ build: "generate && vite build",
+ deploy: "npm run build && cf deploy --no-build",
+ preview: "cf dev",
+ },
+ });
+ });
+
+ it("installs cf and Wrangler for cf projects", async ({ expect }) => {
+ const installPackages = vi
+ .spyOn(cliPackages, "installPackages")
+ .mockResolvedValue();
+ const installWrangler = vi
+ .spyOn(cliPackages, "installWrangler")
+ .mockResolvedValue();
+ const packageJson = { name: "my-static-app" };
+ await seed({
+ "package.json": JSON.stringify(packageJson),
+ "public/index.html": "Hello World
",
+ });
+
+ await runAutoConfig(
+ {
+ configured: false,
+ projectPath: process.cwd(),
+ workerName: "my-static-app",
+ framework: new Static({ id: "static", name: "Static" }),
+ outputDir: "public",
+ packageJson,
+ packageManager: NpmPackageManager,
+ },
+ {
+ context: createMockContext(),
+ skipConfirmations: true,
+ runBuild: false,
+ }
+ );
+
+ expect(installPackages).toHaveBeenCalledWith("npm", ["cf@latest"], {
+ dev: true,
+ isWorkspaceRoot: false,
+ });
+ expect(installWrangler).toHaveBeenCalledWith("npm", false);
+ });
+
+ it("does not install Wrangler when cf delegates to Vite", async ({
+ expect,
+ }) => {
+ const installPackages = vi
+ .spyOn(cliPackages, "installPackages")
+ .mockResolvedValue();
+ const installWrangler = vi
+ .spyOn(cliPackages, "installWrangler")
+ .mockResolvedValue();
+ const packageJson = { name: "my-vite-app" };
+ await seed({
+ "package.json": JSON.stringify(packageJson),
+ "dist/index.html": "Hello World
",
+ "tsconfig.json": "{}",
+ });
+
+ await runAutoConfig(
+ {
+ configured: false,
+ projectPath: process.cwd(),
+ workerName: "my-vite-app",
+ framework: new ViteBuildToolFramework({
+ id: "static",
+ name: "Static",
+ }),
+ outputDir: "dist",
+ packageJson,
+ packageManager: NpmPackageManager,
+ },
+ {
+ context: createMockContext(),
+ skipConfirmations: true,
+ runBuild: false,
+ }
+ );
+
+ expect(installPackages).toHaveBeenCalledWith("npm", ["cf@latest"], {
+ dev: true,
+ isWorkspaceRoot: false,
+ });
+ expect(installWrangler).not.toHaveBeenCalled();
+ expect(JSON.parse(readFileSync("package.json", "utf8"))).toMatchObject({
+ scripts: {
+ "cf-typegen": "cf types",
+ },
+ });
+ });
+
+ it("writes build configuration when an external tool owns the Worker configuration", async ({
+ expect,
+ }) => {
+ await runAutoConfig(
+ {
+ configured: false,
+ projectPath: process.cwd(),
+ workerName: "external-config-app",
+ framework: new ExternalWorkerConfigFramework({
+ id: "static",
+ name: "Static",
+ }),
+ outputDir: "dist",
+ packageManager: NpmPackageManager,
+ },
+ {
+ context: createMockContext(),
+ skipConfirmations: true,
+ runBuild: false,
+ }
+ );
+
+ expect(existsSync("cloudflare.config.ts")).toBe(false);
+ expect(readFileSync("wrangler.config.ts", "utf8")).toContain(
+ '"assetsDirectory": "dist"'
+ );
+ });
+
+ it("fails rather than overwriting existing Wrangler build configuration", async ({
+ expect,
+ }) => {
+ const existingBuildConfig = "export default { minify: true };\n";
+ await seed({
+ "wrangler.config.ts": existingBuildConfig,
+ });
+
+ await expect(
+ runAutoConfig(
+ {
+ configured: false,
+ projectPath: process.cwd(),
+ workerName: "external-config-app",
+ framework: new ExternalWorkerConfigFramework({
+ id: "static",
+ name: "Static",
+ }),
+ outputDir: "dist",
+ packageManager: NpmPackageManager,
+ },
+ {
+ context: createMockContext(),
+ skipConfirmations: true,
+ runBuild: false,
+ }
+ )
+ ).rejects.toThrow(
+ "Cannot generate wrangler.config.ts because the file already exists"
+ );
+ expect(readFileSync("wrangler.config.ts", "utf8")).toBe(
+ existingBuildConfig
+ );
+ });
+});
diff --git a/packages/wrangler/src/__tests__/autoconfig/index.test.ts b/packages/wrangler/src/__tests__/autoconfig/index.test.ts
index 36fe3753053..774fcb3ad9d 100644
--- a/packages/wrangler/src/__tests__/autoconfig/index.test.ts
+++ b/packages/wrangler/src/__tests__/autoconfig/index.test.ts
@@ -47,7 +47,6 @@ const mockDetails = {
/** Minimal mock satisfying {@link AutoConfigSummary}. */
const mockSummary = {
scripts: {},
- wranglerInstall: false,
outputDir: "dist",
} as unknown as AutoConfigSummary;
@@ -84,6 +83,7 @@ describe("autoconfig wrappers", () => {
expect(getDetailsForAutoConfig).toHaveBeenCalledOnce();
expect(getDetailsForAutoConfig).toHaveBeenCalledWith({
wranglerConfig: mockConfig,
+ target: "wrangler",
context: mockContext,
});
expect(result).toBe(mockDetails);
@@ -196,7 +196,10 @@ describe("autoconfig wrappers", () => {
const result = await runAutoConfigLogic(mockDetails, options);
expect(runAutoConfig).toHaveBeenCalledOnce();
- expect(runAutoConfig).toHaveBeenCalledWith(mockDetails, options);
+ expect(runAutoConfig).toHaveBeenCalledWith(mockDetails, {
+ ...options,
+ target: "wrangler",
+ });
expect(result).toBe(mockSummary);
});
diff --git a/packages/wrangler/src/__tests__/autoconfig/run.test.ts b/packages/wrangler/src/__tests__/autoconfig/run.test.ts
index 1644533e1ae..87dd6a52f03 100644
--- a/packages/wrangler/src/__tests__/autoconfig/run.test.ts
+++ b/packages/wrangler/src/__tests__/autoconfig/run.test.ts
@@ -44,9 +44,8 @@ import type { MockInstance } from "vitest";
class MockStaticFramework extends Framework {
configure({ outputDir }: ConfigurationOptions): ConfigurationResults {
return {
- wranglerConfig: {
- assets: { directory: outputDir },
- },
+ workerConfig: {},
+ buildConfig: { assetsDirectory: outputDir },
};
}
}
@@ -58,7 +57,7 @@ class MockStaticFramework extends Framework {
*/
class MockAstroFramework extends Framework {
async configure(): Promise {
- return { wranglerConfig: { assets: { directory: "dist" } } };
+ return { workerConfig: {}, buildConfig: { assetsDirectory: "dist" } };
}
}
@@ -214,7 +213,7 @@ describe("autoconfig (deploy)", () => {
framework: {
id: "cloudflare-pages",
name: "Cloudflare Pages",
- configure: async () => ({ wranglerConfig: {} }),
+ configure: async () => ({ workerConfig: {} }),
isConfigured: () => false,
} as unknown as Framework,
outputDir: "public",
@@ -270,9 +269,8 @@ describe("autoconfig (deploy)", () => {
const configureSpy = vi.fn(
async ({ outputDir }) =>
({
- wranglerConfig: {
- assets: { directory: outputDir },
- },
+ workerConfig: {},
+ buildConfig: { assetsDirectory: outputDir },
}) satisfies ReturnType
);
await autoconfig.runAutoConfig(
@@ -298,7 +296,11 @@ describe("autoconfig (deploy)", () => {
},
packageManager: NpmPackageManager,
},
- { context, enableWranglerInstallation: false }
+ {
+ target: "wrangler",
+ context,
+ enableTargetCliInstallation: false,
+ }
);
expect(std.out.replaceAll(DEFAULT_COMPAT_DATE, ""))
@@ -311,9 +313,6 @@ describe("autoconfig (deploy)", () => {
- Output Directory: dist
- 📦 Install packages:
- - wrangler (devDependency)
-
📝 Update package.json scripts:
- "deploy": "echo 'built' > build.txt && wrangler deploy"
- "preview": "echo 'built' > build.txt && wrangler dev"
@@ -368,9 +367,7 @@ describe("autoconfig (deploy)", () => {
"
`);
- // Wrangler installation was disabled (enableWranglerInstallation: false) to avoid
- // running the real installer in tests. The "📦 Install packages:" output in the
- // snapshot above confirms the intent is recorded in the autoconfig summary.
+ // CLI installation was disabled to avoid running the real installer in tests.
expect(installSpy).not.toHaveBeenCalled();
// The framework's configuration command should have been run
@@ -407,7 +404,7 @@ describe("autoconfig (deploy)", () => {
framework: new MockStaticFramework({ id: "static", name: "Static" }),
packageManager: NpmPackageManager,
},
- { context }
+ { target: "wrangler", context }
);
expect(readFileSync(".gitignore")).toMatchInlineSnapshot(`
@@ -444,7 +441,7 @@ describe("autoconfig (deploy)", () => {
framework: new MockStaticFramework({ id: "static", name: "Static" }),
packageManager: NpmPackageManager,
},
- { context }
+ { target: "wrangler", context }
);
// When gitignore pre-existed with trailing newline, one empty line is added as separator
@@ -493,7 +490,7 @@ describe("autoconfig (deploy)", () => {
outputDir: "dist",
packageManager: NpmPackageManager,
},
- { context }
+ { target: "wrangler", context }
);
expect(std.out.replaceAll(DEFAULT_COMPAT_DATE, ""))
@@ -568,7 +565,7 @@ describe("autoconfig (deploy)", () => {
framework: new MockStaticFramework({ id: "static", name: "Static" }),
packageManager: NpmPackageManager,
},
- { context }
+ { target: "wrangler", context }
);
expect(readFileSync(".assetsignore")).toMatchInlineSnapshot(`
@@ -604,7 +601,7 @@ describe("autoconfig (deploy)", () => {
framework: new MockStaticFramework({ id: "static", name: "Static" }),
packageManager: NpmPackageManager,
},
- { context }
+ { target: "wrangler", context }
);
expect(readFileSync(".assetsignore")).toMatchInlineSnapshot(`
@@ -641,7 +638,7 @@ describe("autoconfig (deploy)", () => {
outputDir: "",
packageManager: NpmPackageManager,
},
- { context }
+ { target: "wrangler", context }
)
).rejects.toThrowErrorMatchingInlineSnapshot(
`[AssertionError: The Output Directory is unexpectedly missing]`
@@ -664,14 +661,14 @@ describe("autoconfig (deploy)", () => {
framework: {
id: "cloudflare-pages",
name: "Cloudflare Pages",
- configure: async () => ({ wranglerConfig: {} }),
+ configure: async () => ({ workerConfig: {} }),
isConfigured: () => false,
} as unknown as Framework,
workerName: "my-worker",
outputDir: "dist",
packageManager: NpmPackageManager,
},
- { context }
+ { target: "wrangler", context }
)
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: The target project seems to be using Cloudflare Pages. Automatically migrating from a Pages project to Workers is not yet supported.]`
@@ -694,14 +691,14 @@ describe("autoconfig (deploy)", () => {
framework: {
id: "hono",
name: "Hono",
- configure: async () => ({ wranglerConfig: {} }),
+ configure: async () => ({ workerConfig: {} }),
isConfigured: () => false,
} as unknown as Framework,
workerName: "my-worker",
outputDir: "dist",
packageManager: NpmPackageManager,
},
- { context }
+ { target: "wrangler", context }
)
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: The detected framework ("Hono") cannot be automatically configured.]`
@@ -738,16 +735,14 @@ describe("autoconfig (deploy)", () => {
id: "static",
name: "Static",
configure: async () => ({
- wranglerConfig: {
- // No compatibility_flags specified
- assets: { directory: "dist" },
- },
+ workerConfig: {},
+ buildConfig: { assetsDirectory: "dist" },
}),
isConfigured: () => false,
} as unknown as Framework,
packageManager: NpmPackageManager,
},
- { context }
+ { target: "wrangler", context }
);
const wranglerConfig = JSON.parse(readFileSync("wrangler.jsonc"));
@@ -777,16 +772,16 @@ describe("autoconfig (deploy)", () => {
id: "static",
name: "Static",
configure: async () => ({
- wranglerConfig: {
- compatibility_flags: ["global_fetch_strictly_public"],
- assets: { directory: "dist" },
+ workerConfig: {
+ compatibilityFlags: ["global_fetch_strictly_public"],
},
+ buildConfig: { assetsDirectory: "dist" },
}),
isConfigured: () => false,
} as unknown as Framework,
packageManager: NpmPackageManager,
},
- { context }
+ { target: "wrangler", context }
);
const wranglerConfig = JSON.parse(readFileSync("wrangler.jsonc"));
@@ -820,16 +815,16 @@ describe("autoconfig (deploy)", () => {
id: "static",
name: "Static",
configure: async () => ({
- wranglerConfig: {
- compatibility_flags: ["nodejs_compat"],
- assets: { directory: "dist" },
+ workerConfig: {
+ compatibilityFlags: ["nodejs_compat"],
},
+ buildConfig: { assetsDirectory: "dist" },
}),
isConfigured: () => false,
} as unknown as Framework,
packageManager: NpmPackageManager,
},
- { context }
+ { target: "wrangler", context }
);
const wranglerConfig = JSON.parse(readFileSync("wrangler.jsonc"));
@@ -858,16 +853,16 @@ describe("autoconfig (deploy)", () => {
id: "static",
name: "Nodejs Als Framework",
configure: async () => ({
- wranglerConfig: {
- compatibility_flags: ["nodejs_als", "some_other_flag"],
- assets: { directory: "dist" },
+ workerConfig: {
+ compatibilityFlags: ["nodejs_als", "some_other_flag"],
},
+ buildConfig: { assetsDirectory: "dist" },
}),
isConfigured: () => false,
} as unknown as Framework,
packageManager: NpmPackageManager,
},
- { context }
+ { target: "wrangler", context }
);
const wranglerConfig = JSON.parse(readFileSync("wrangler.jsonc"));
@@ -900,7 +895,10 @@ describe("autoconfig (deploy)", () => {
});
vi.spyOn(framework, "configure").mockImplementation(async () => {
callOrder.push("configure");
- return { wranglerConfig: { assets: { directory: "dist" } } };
+ return {
+ workerConfig: {},
+ buildConfig: { assetsDirectory: "dist" },
+ };
});
await autoconfig.runAutoConfig(
@@ -912,7 +910,7 @@ describe("autoconfig (deploy)", () => {
framework,
packageManager: NpmPackageManager,
},
- { context }
+ { target: "wrangler", context }
);
// configure is called twice: once as a dry-run (to build the summary) and
diff --git a/packages/wrangler/src/__tests__/deploy/core.test.ts b/packages/wrangler/src/__tests__/deploy/core.test.ts
index 75c5a6c9326..a6bc9f6fbe5 100644
--- a/packages/wrangler/src/__tests__/deploy/core.test.ts
+++ b/packages/wrangler/src/__tests__/deploy/core.test.ts
@@ -622,7 +622,7 @@ describe("deploy", () => {
framework: {
id: "cloudflare-pages",
name: "Cloudflare Pages",
- configure: async () => ({ wranglerConfig: {} }),
+ configure: async () => ({ workerConfig: {} }),
isConfigured: () => false,
} as unknown as Framework,
outputDir: "public",
@@ -662,7 +662,7 @@ describe("deploy", () => {
framework: {
id: "cloudflare-pages",
name: "Cloudflare Pages",
- configure: async () => ({ wranglerConfig: {} }),
+ configure: async () => ({ workerConfig: {} }),
isConfigured: () => false,
} as unknown as Framework,
outputDir: "public",
@@ -1940,7 +1940,6 @@ describe("deploy", () => {
scripts: {
build: "npm run build-my-static-site",
},
- wranglerInstall: true,
wranglerConfig,
outputDir: "public",
};
@@ -1976,7 +1975,6 @@ describe("deploy", () => {
"compatibility_date": "2025-12-02",
"name": "my-site",
},
- "wranglerInstall": true,
}
`);
});
diff --git a/packages/wrangler/src/__tests__/setup.test.ts b/packages/wrangler/src/__tests__/setup.test.ts
index 3e9d94b699e..c90df866d14 100644
--- a/packages/wrangler/src/__tests__/setup.test.ts
+++ b/packages/wrangler/src/__tests__/setup.test.ts
@@ -166,7 +166,7 @@ describe("wrangler setup", () => {
assert(autoconfigOutputEntry);
if (autoconfigOutputEntry.summary?.wranglerConfig) {
- // Let's normalize the wrangler config values that are
+ // Let's normalize the Wrangler config values that are
// randomly generated or change over time
autoconfigOutputEntry.summary.wranglerConfig.name = "test-name";
autoconfigOutputEntry.summary.wranglerConfig.compatibility_date =
@@ -194,7 +194,6 @@ describe("wrangler setup", () => {
"enabled": true,
},
},
- "wranglerInstall": true,
}
`);
});
diff --git a/packages/wrangler/src/autoconfig/index.ts b/packages/wrangler/src/autoconfig/index.ts
index 71696f46574..e6d9a74c830 100644
--- a/packages/wrangler/src/autoconfig/index.ts
+++ b/packages/wrangler/src/autoconfig/index.ts
@@ -52,6 +52,7 @@ export async function runAutoConfigDetection({
try {
const details = await getDetailsForAutoConfig({
wranglerConfig,
+ target: "wrangler",
context,
});
@@ -114,7 +115,10 @@ export async function runAutoConfigLogic(
);
try {
- const summary = await runAutoConfig(details, options);
+ const summary = await runAutoConfig(details, {
+ ...options,
+ target: "wrangler",
+ });
sendMetricsEvent(
"autoconfig_configuration_completed",
diff --git a/packages/wrangler/src/setup.ts b/packages/wrangler/src/setup.ts
index 2446df0020c..4861d00bbaf 100644
--- a/packages/wrangler/src/setup.ts
+++ b/packages/wrangler/src/setup.ts
@@ -93,7 +93,7 @@ export const setupCommand = createCommand({
runBuild: args.build,
skipConfirmations: args.yes,
dryRun: !!args.dryRun,
- enableWranglerInstallation: args.installWrangler,
+ enableTargetCliInstallation: args.installWrangler,
});
} catch (error) {
sendAutoConfigProcessEndedMetricsEvent({
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 05514c02029..7723213403c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1692,6 +1692,9 @@ importers:
'@cloudflare/cli-shared-helpers':
specifier: workspace:*
version: link:../cli
+ '@cloudflare/config':
+ specifier: workspace:*
+ version: link:../config
'@cloudflare/workers-utils':
specifier: workspace:*
version: link:../workers-utils