1import path from "node:path";
2import * as vite from "vite";
3import { describe, expect, it, vi } from "vitest";
4import cloudflareVitePlugin, {
5 ALCHEMY_CLOUDFLARE_VITE_PLUGIN_NAME,
6 OFFICIAL_CLOUDFLARE_VITE_PLUGIN_NAME,
7 disableOfficialCloudflareVitePlugins,
8} from "../plugin.ts";
9
10const root = path.join(import.meta.dirname, "fixtures");
11
12const flattenPlugins = (
13 plugins: ReadonlyArray<unknown>,
14): Array<vite.Plugin> => {
15 const flat: Array<vite.Plugin> = [];
16 const visit = (entry: unknown): void => {
17 if (Array.isArray(entry)) {
18 for (const child of entry) visit(child);
19 return;
20 }
21 if (entry && typeof entry === "object" && "name" in entry) {
22 flat.push(entry as vite.Plugin);
23 }
24 };
25 for (const entry of plugins) visit(entry);
26 return flat;
27};
28
29const hasCloudflarePlugin = (plugins: ReadonlyArray<vite.Plugin>): boolean =>
30 plugins.some(
31 (plugin) =>
32 plugin.name === OFFICIAL_CLOUDFLARE_VITE_PLUGIN_NAME ||
33 plugin.name.startsWith(`${OFFICIAL_CLOUDFLARE_VITE_PLUGIN_NAME}:`),
34 );
35
36describe("alchemy Cloudflare Vite plugin name", () => {
37 it("registers a prefixed presence plugin, not the official exact name", () => {
38 const plugins = flattenPlugins([
39 cloudflareVitePlugin({ main: "./worker-entry.ts" }),
40 ]);
41 expect(
42 plugins.some(
43 (plugin) => plugin.name === ALCHEMY_CLOUDFLARE_VITE_PLUGIN_NAME,
44 ),
45 ).toBe(true);
46 expect(
47 plugins.some(
48 (plugin) => plugin.name === OFFICIAL_CLOUDFLARE_VITE_PLUGIN_NAME,
49 ),
50 ).toBe(false);
51 expect(hasCloudflarePlugin(plugins)).toBe(true);
52 });
53
54 it("no-ops official plugin hooks already present in config.plugins", async () => {
55 const officialConfig = vi.fn(() => ({
56 define: { "import.meta.official": JSON.stringify(true) },
57 }));
58 const officialResolved = vi.fn();
59 const official: vite.Plugin = {
60 name: OFFICIAL_CLOUDFLARE_VITE_PLUGIN_NAME,
61 enforce: "pre",
62 config: officialConfig,
63 configResolved: officialResolved,
64 };
65
66 let seenByLaterConfig = false;
67 const scanner: vite.Plugin = {
68 name: "vinext-style-scan",
69 enforce: "pre",
70 config(config) {
71 seenByLaterConfig = hasCloudflarePlugin(
72 flattenPlugins(config.plugins ?? []),
73 );
74 },
75 };
76
77 const resolved = await vite.resolveConfig(
78 {
79 configFile: false,
80 root,
81 logLevel: "silent",
82 plugins: [
83 official,
84 scanner,
85 cloudflareVitePlugin({ main: "./worker-entry.ts" }),
86 ],
87 },
88 "serve",
89 );
90
91 expect(officialConfig).not.toHaveBeenCalled();
92 expect(officialResolved).not.toHaveBeenCalled();
93 expect(seenByLaterConfig).toBe(true);
94 expect(resolved.define?.["import.meta.official"]).toBeUndefined();
95 expect(
96 resolved.plugins.some(
97 (plugin) => plugin.name === ALCHEMY_CLOUDFLARE_VITE_PLUGIN_NAME,
98 ),
99 ).toBe(true);
100 });
101
102 it("disables nested official child plugins by object identity", () => {
103 const childConfig = vi.fn();
104 const child: vite.Plugin = {
105 name: `${OFFICIAL_CLOUDFLARE_VITE_PLUGIN_NAME}:compat`,
106 config: childConfig,
107 };
108 const disabled = disableOfficialCloudflareVitePlugins([[child]]);
109 expect(disabled).toBe(1);
110 void (child.config as () => void)();
111 expect(childConfig).not.toHaveBeenCalled();
112 });
113});