Skip to content

Dispose Miniflare when Vite plugin closes #9490

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
5 changes: 5 additions & 0 deletions .changeset/shaky-socks-raise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudflare/vite-plugin": patch
---

fix: vite-plugin now disposes its miniflare instance when closing down
15 changes: 10 additions & 5 deletions packages/vite-plugin-cloudflare/playground/vitest-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import {
preview,
Rollup,
} from "vite";
import { beforeAll, beforeEach, inject } from "vitest";
import { afterAll, beforeAll, beforeEach, inject } from "vitest";
import type * as http from "node:http";
import type { Browser, Page } from "playwright-chromium";
import type {
ConfigEnv,
InlineConfig,
Logger,
PluginOption,
PreviewServer,
ResolvedConfig,
UserConfig,
ViteDevServer,
Expand All @@ -28,7 +29,7 @@ export const workspaceRoot = path.resolve(__dirname, "../");
export const isBuild = !!process.env.VITE_TEST_BUILD;
export const isWindows = process.platform === "win32";

let server: ViteDevServer | http.Server;
let server: ViteDevServer | http.Server | PreviewServer;

/**
* Vite Dev Server when testing serve
Expand Down Expand Up @@ -157,7 +158,7 @@ beforeAll(async (s) => {
viteTestUrl = mod.viteTestUrl ?? viteTestUrl;
}
} else {
await startDefaultServe();
server = await startDefaultServe();
}
}
} catch (e) {
Expand All @@ -166,10 +167,13 @@ beforeAll(async (s) => {
// If the page remains open, a command like `await page.click(...)` produces
// a timeout with an exception that hides the real error in the console.
await page.close();
await server?.close();
throw e;
}

afterAll(async () => {
await server.close();
});

return async () => {
resetServerLogs();

Expand Down Expand Up @@ -249,7 +253,7 @@ export async function loadConfig(configEnv: ConfigEnv) {
}

export async function startDefaultServe(): Promise<
ViteDevServer | http.Server
ViteDevServer | http.Server | PreviewServer
> {
setupConsoleWarnCollector(serverLogs.warns);

Expand Down Expand Up @@ -299,6 +303,7 @@ export async function startDefaultServe(): Promise<
if (previewServer.config.base === "/") {
viteTestUrl = viteTestUrl.replace(/\/$/, "");
}
server = previewServer;
await page.goto(viteTestUrl);
}
return server;
Expand Down
40 changes: 31 additions & 9 deletions packages/vite-plugin-cloudflare/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@ export function cloudflare(pluginConfig: PluginConfig = {}): vite.Plugin[] {
// This is set when the client environment is built to determine if the entry Worker should include assets
let hasClientBuild = false;

// This is needed so that we can tell the difference between the Vite http server closing and restarting.
let previousServer: unknown;
let restartingServer = false;
function updateRestartingServerFlag(viteDevServer: unknown) {
restartingServer =
previousServer !== undefined && viteDevServer !== previousServer;
previousServer = viteDevServer;
}

return [
{
name: "vite-plugin-cloudflare",
Expand Down Expand Up @@ -332,7 +341,20 @@ export function cloudflare(pluginConfig: PluginConfig = {}): vite.Plugin[] {
return [];
}
},
buildEnd() {
if (!restartingServer) {
miniflare?.dispose().catch((error) => {
console.error("Error disposing Miniflare instance:", error);
});
miniflare = undefined;
}
// Reset the flag so that if a `buildEnd` hook is called again before the next
// configureServer hook then we do dispose of miniflare correctly.
restartingServer = false;
},
async configureServer(viteDevServer) {
updateRestartingServerFlag(viteDevServer);

const inputInspectorPort = await getInputInspectorPortOption(
pluginConfig,
viteDevServer
Expand Down Expand Up @@ -399,6 +421,8 @@ export function cloudflare(pluginConfig: PluginConfig = {}): vite.Plugin[] {
};
},
async configurePreviewServer(vitePreviewServer) {
updateRestartingServerFlag(vitePreviewServer);

const workerConfigs = getWorkerConfigs(
vitePreviewServer.config.root,
pluginConfig.experimental?.mixedMode ?? false
Expand All @@ -409,7 +433,7 @@ export function cloudflare(pluginConfig: PluginConfig = {}): vite.Plugin[] {
vitePreviewServer
);

const miniflare = new Miniflare(
miniflare = new Miniflare(
await getPreviewMiniflareOptions(
vitePreviewServer,
workerConfigs,
Expand All @@ -419,19 +443,17 @@ export function cloudflare(pluginConfig: PluginConfig = {}): vite.Plugin[] {
)
);

handleWebSocket(
vitePreviewServer.httpServer,
() => miniflare.dispatchFetch
);
const dispatchFetch = miniflare.dispatchFetch;

handleWebSocket(vitePreviewServer.httpServer, () => dispatchFetch);

// In preview mode we put our middleware at the front of the chain so that all assets are handled in Miniflare
vitePreviewServer.middlewares.use(async (req, res, next) => {
try {
const request = createRequest(req, res);
const response = await miniflare.dispatchFetch(
toMiniflareRequest(request),
{ redirect: "manual" }
);
const response = await dispatchFetch(toMiniflareRequest(request), {
redirect: "manual",
});

// Vite uses HTTP/2 when `preview.https` is enabled
if (req.httpVersionMajor === 2) {
Expand Down
Loading