Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/polish-vite-plugin-installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": patch
---

Polish Cloudflare Vite plugin installation during autoconfig

Projects using Vite 6.0.x were rejected by auto-configuration because the minimum supported version was set to 6.1.0 (the `@cloudflare/vite-plugin` peer dependency). The minimum version check is now 6.0.0, and when a project has Vite in the [6.0.0, 6.1.0) range, auto-configuration will automatically upgrade it to the latest 6.x before installing `@cloudflare/vite-plugin`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
import * as cliPackages from "@cloudflare/cli/packages";
import { beforeEach, describe, it, vi } from "vitest";
import { getInstalledPackageVersion } from "../../../../autoconfig/frameworks/utils/packages";
import { installCloudflareVitePlugin } from "../../../../autoconfig/frameworks/utils/vite-plugin";
import type { MockInstance } from "vitest";

vi.mock("../../../../autoconfig/frameworks/utils/packages", () => ({
getInstalledPackageVersion: vi.fn(),
}));

describe("installCloudflareVitePlugin", () => {
let installSpy: MockInstance;

beforeEach(() => {
installSpy = vi
.spyOn(cliPackages, "installPackages")
.mockImplementation(async () => {});
});

describe("when Vite is not installed/detected", () => {
beforeEach(() => {
vi.mocked(getInstalledPackageVersion).mockReturnValue(undefined);
});

it("installs only @cloudflare/vite-plugin", async ({ expect }) => {
await installCloudflareVitePlugin({
packageManager: "npm",
projectPath: "/test/project",
isWorkspaceRoot: false,
});

expect(installSpy).toHaveBeenCalledTimes(1);
expect(installSpy).toHaveBeenCalledWith(
"npm",
["@cloudflare/vite-plugin"],
expect.objectContaining({ dev: true })
);
});

it("does not attempt to upgrade Vite", async ({ expect }) => {
await installCloudflareVitePlugin({
packageManager: "npm",
projectPath: "/test/project",
isWorkspaceRoot: false,
});

expect(installSpy).not.toHaveBeenCalledWith(
expect.anything(),
["vite@^6.1.0"],
expect.anything()
);
});
});

describe("when Vite version is in [6.0.0, 6.1.0) range", () => {
it("upgrades Vite before installing the plugin for version 6.0.0", async ({
expect,
}) => {
vi.mocked(getInstalledPackageVersion).mockReturnValue("6.0.0");

await installCloudflareVitePlugin({
packageManager: "npm",
projectPath: "/test/project",
isWorkspaceRoot: false,
});

expect(installSpy).toHaveBeenCalledTimes(2);
expect(installSpy).toHaveBeenNthCalledWith(
1,
"npm",
["vite@^6.1.0"],
expect.objectContaining({ dev: true })
);
expect(installSpy).toHaveBeenNthCalledWith(
2,
"npm",
["@cloudflare/vite-plugin"],
expect.objectContaining({ dev: true })
);
});

it("upgrades Vite before installing the plugin for version 6.0.5", async ({
expect,
}) => {
vi.mocked(getInstalledPackageVersion).mockReturnValue("6.0.5");

await installCloudflareVitePlugin({
packageManager: "npm",
projectPath: "/test/project",
isWorkspaceRoot: false,
});

expect(installSpy).toHaveBeenCalledTimes(2);
expect(installSpy).toHaveBeenNthCalledWith(
1,
"npm",
["vite@^6.1.0"],
expect.objectContaining({ dev: true })
);
expect(installSpy).toHaveBeenNthCalledWith(
2,
"npm",
["@cloudflare/vite-plugin"],
expect.objectContaining({ dev: true })
);
});
});

describe("when Vite version is >= 6.1.0", () => {
it("does not upgrade Vite for version 6.1.0", async ({ expect }) => {
vi.mocked(getInstalledPackageVersion).mockReturnValue("6.1.0");

await installCloudflareVitePlugin({
packageManager: "npm",
projectPath: "/test/project",
isWorkspaceRoot: false,
});

expect(installSpy).toHaveBeenCalledTimes(1);
expect(installSpy).toHaveBeenCalledWith(
"npm",
["@cloudflare/vite-plugin"],
expect.objectContaining({ dev: true })
);
});

it("does not upgrade Vite for version 6.2.0", async ({ expect }) => {
vi.mocked(getInstalledPackageVersion).mockReturnValue("6.2.0");

await installCloudflareVitePlugin({
packageManager: "npm",
projectPath: "/test/project",
isWorkspaceRoot: false,
});

expect(installSpy).toHaveBeenCalledTimes(1);
expect(installSpy).not.toHaveBeenCalledWith(
expect.anything(),
["vite@^6.1.0"],
expect.anything()
);
});

it("does not upgrade Vite for version 7.0.0", async ({ expect }) => {
vi.mocked(getInstalledPackageVersion).mockReturnValue("7.0.0");

await installCloudflareVitePlugin({
packageManager: "npm",
projectPath: "/test/project",
isWorkspaceRoot: false,
});

expect(installSpy).toHaveBeenCalledTimes(1);
expect(installSpy).not.toHaveBeenCalledWith(
expect.anything(),
["vite@^6.1.0"],
expect.anything()
);
});
});

describe("when Vite version is < 6.0.0", () => {
it("does not upgrade Vite for version 5.4.0", async ({ expect }) => {
vi.mocked(getInstalledPackageVersion).mockReturnValue("5.4.0");

await installCloudflareVitePlugin({
packageManager: "npm",
projectPath: "/test/project",
isWorkspaceRoot: false,
});

expect(installSpy).toHaveBeenCalledTimes(1);
expect(installSpy).not.toHaveBeenCalledWith(
expect.anything(),
["vite@^6.1.0"],
expect.anything()
);
});

it("does not upgrade Vite for version 4.0.0", async ({ expect }) => {
vi.mocked(getInstalledPackageVersion).mockReturnValue("4.0.0");

await installCloudflareVitePlugin({
packageManager: "npm",
projectPath: "/test/project",
isWorkspaceRoot: false,
});

expect(installSpy).toHaveBeenCalledTimes(1);
expect(installSpy).toHaveBeenCalledWith(
"npm",
["@cloudflare/vite-plugin"],
expect.objectContaining({ dev: true })
);
});
});

describe("parameter forwarding", () => {
beforeEach(() => {
vi.mocked(getInstalledPackageVersion).mockReturnValue(undefined);
});

it("forwards isWorkspaceRoot to installPackages", async ({ expect }) => {
await installCloudflareVitePlugin({
packageManager: "npm",
projectPath: "/test/project",
isWorkspaceRoot: true,
});

expect(installSpy).toHaveBeenCalledWith(
expect.anything(),
expect.anything(),
expect.objectContaining({ isWorkspaceRoot: true })
);
});

it("forwards isWorkspaceRoot when upgrading Vite", async ({ expect }) => {
vi.mocked(getInstalledPackageVersion).mockReturnValue("6.0.0");

await installCloudflareVitePlugin({
packageManager: "npm",
projectPath: "/test/project",
isWorkspaceRoot: true,
});

// Both the Vite upgrade and plugin install should have isWorkspaceRoot: true
expect(installSpy).toHaveBeenNthCalledWith(
1,
expect.anything(),
["vite@^6.1.0"],
expect.objectContaining({ isWorkspaceRoot: true })
);
expect(installSpy).toHaveBeenNthCalledWith(
2,
expect.anything(),
["@cloudflare/vite-plugin"],
expect.objectContaining({ isWorkspaceRoot: true })
);
});

it("forwards packageManager to installPackages", async ({ expect }) => {
await installCloudflareVitePlugin({
packageManager: "pnpm",
projectPath: "/test/project",
isWorkspaceRoot: false,
});

expect(installSpy).toHaveBeenCalledWith(
"pnpm",
expect.anything(),
expect.anything()
);
});

it("forwards different package managers correctly", async ({ expect }) => {
for (const pm of ["npm", "yarn", "pnpm", "bun"] as const) {
installSpy.mockClear();

await installCloudflareVitePlugin({
packageManager: pm,
projectPath: "/test/project",
isWorkspaceRoot: false,
});

expect(installSpy).toHaveBeenCalledWith(
pm,
expect.anything(),
expect.anything()
);
}
});

it("passes projectPath to getInstalledPackageVersion", async ({
expect,
}) => {
await installCloudflareVitePlugin({
packageManager: "npm",
projectPath: "/custom/path",
isWorkspaceRoot: false,
});

expect(getInstalledPackageVersion).toHaveBeenCalledWith(
"vite",
"/custom/path"
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ export const allKnownFrameworks = [
name: "vite",
// Vite 6 introduced the Environment API which @cloudflare/vite-plugin requires
// See: https://vite.dev/blog/announcing-vite6#experimental-environment-api
// (6.1.0 is the minimum version supported by the vite plugin:
// https://github.com/cloudflare/workers-sdk/blob/b9b7e9d9fe/packages/vite-plugin-cloudflare/package.json#L80
// we anyways allow for `6.0.x` versions since we bump them to `^6.1.0` in the autoconfig process)
minimumVersion: "6.0.0",
Comment thread
dario-piotrowicz marked this conversation as resolved.
maximumKnownMajorVersion: "8",
},
Expand Down
10 changes: 4 additions & 6 deletions packages/wrangler/src/autoconfig/frameworks/react-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import dedent from "ts-dedent";
import { logger } from "../../logger";
import { Framework } from "./framework-class";
import { transformViteConfig } from "./utils/vite-config";
import { installCloudflareVitePlugin } from "./utils/vite-plugin";
import type {
ConfigurationOptions,
ConfigurationResults,
Expand Down Expand Up @@ -148,12 +149,9 @@ export class ReactRouter extends Framework {
}: ConfigurationOptions): Promise<ConfigurationResults> {
const viteEnvironmentKey = configPropertyName(this.frameworkVersion);
if (!dryRun) {
await installPackages(packageManager.type, ["@cloudflare/vite-plugin"], {
dev: true,
startText: "Installing the Cloudflare Vite plugin",
doneText: `${brandColor(`installed`)} ${dim(
"@cloudflare/vite-plugin"
)}`,
await installCloudflareVitePlugin({
packageManager: packageManager.type,
projectPath,
isWorkspaceRoot,
});

Expand Down
12 changes: 4 additions & 8 deletions packages/wrangler/src/autoconfig/frameworks/tanstack.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { brandColor, dim } from "@cloudflare/cli/colors";
import { installPackages } from "@cloudflare/cli/packages";
import { Framework } from "./framework-class";
import { transformViteConfig } from "./utils/vite-config";
import { installCloudflareVitePlugin } from "./utils/vite-plugin";
import type {
ConfigurationOptions,
ConfigurationResults,
Expand All @@ -15,13 +14,10 @@ export class TanstackStart extends Framework {
isWorkspaceRoot,
}: ConfigurationOptions): Promise<ConfigurationResults> {
if (!dryRun) {
await installPackages(packageManager.type, ["@cloudflare/vite-plugin"], {
dev: true,
startText: "Installing the Cloudflare Vite plugin",
doneText: `${brandColor(`installed`)} ${dim(
"@cloudflare/vite-plugin"
)}`,
await installCloudflareVitePlugin({
packageManager: packageManager.type,
isWorkspaceRoot,
projectPath,
});

transformViteConfig(projectPath, { viteEnvironmentName: "ssr" });
Expand Down
Loading
Loading