๐Ÿ“ฆ cloudflare / vinext

๐Ÿ“„ vite.config.ts ยท 102 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102import { defineConfig } from "vite";
import vinext from "vinext";
import { cloudflare } from "@cloudflare/vite-plugin";
import mdx from "@mdx-js/rollup";
import { remarkCodeHike, recmaCodeHike, type CodeHikeConfig } from "codehike/mdx";
import path from "node:path";

const codeHikeConfig: CodeHikeConfig = {
  components: { code: "MyCode", inlineCode: "MyInlineCode" },
};

/**
 * Vite config for the Next.js App Router Playground running on vinext.
 *
 * This replaces next.config.ts โ€” all Next.js features are provided by
 * the vinext plugin + @vitejs/plugin-rsc for RSC support.
 *
 * To run: npx vite dev
 * To build: npx vite build
 * To deploy to Cloudflare: npx wrangler deploy
 */
export default defineConfig({
  plugins: [
    // Shim React canary APIs (ViewTransition, addTransitionType) that don't
    // exist in stable React 19. Provides no-op replacements so the
    // view-transitions page degrades gracefully instead of crashing.
    {
      name: "shim-react-canary",
      resolveId(id) {
        if (id === "virtual:react-with-canary") return "\0virtual:react-with-canary";
      },
      load(id) {
        if (id === "\0virtual:react-with-canary") {
          return `
            export * from "react";
            export { default } from "react";
            import React from "react";
            export const ViewTransition = React.ViewTransition || (({ children }) => children);
            export const addTransitionType = React.addTransitionType || (() => {});
          `;
        }
      },
      transform(code, id) {
        // Rewrite imports from 'react' that reference canary APIs
        if (
          !id.includes("node_modules") &&
          (id.endsWith(".tsx") || id.endsWith(".ts") || id.endsWith(".jsx") || id.endsWith(".js")) &&
          (code.includes("ViewTransition") || code.includes("addTransitionType")) &&
          /from\s+['"]react['"]/.test(code)
        ) {
          // Only rewrite if the import actually destructures ViewTransition or addTransitionType
          const importRegex = /import\s*\{[^}]*(ViewTransition|addTransitionType)[^}]*\}\s*from\s*['"]react['"]/;
          if (importRegex.test(code)) {
            const result = code.replace(
              /from\s*['"]react['"]/g,
              'from "virtual:react-with-canary"',
            );
            if (result !== code) {
              return { code: result, map: null };
            }
          }
        }
        return null;
      },
    },

    // MDX support with CodeHike remark/recma plugins โ€” transforms .mdx files
    // into React components and processes !!col directives, code annotations, etc.
    mdx({
      remarkPlugins: [[remarkCodeHike, codeHikeConfig]],
      recmaPlugins: [[recmaCodeHike, codeHikeConfig]],
    }),

    // vinext plugin (provides all next/* shims, routing, SSR, RSC).
    // @vitejs/plugin-rsc is auto-registered when app/ is detected.
    vinext(),

    // Cloudflare Workers plugin โ€” builds for workerd runtime.
    // The worker entry runs in the RSC environment, with SSR as a child.
    cloudflare({
      viteEnvironment: {
        name: "rsc",
        childEnvironments: ["ssr"],
      },
    }),
  ],

  resolve: {
    alias: {
      // Map #/* imports to the project root (matches tsconfig paths)
      "#": path.resolve(__dirname),
      // Map bare 'app/' imports (tsconfig baseUrl: ".")
      "app": path.resolve(__dirname, "app"),
      // server-only is a guard package โ€” resolve to empty module in SSR
      "server-only": path.resolve(__dirname, "server-only-shim.ts"),
    },
  },

  // Use postcss.config.js for Tailwind CSS processing
  // (Do NOT override with empty plugins array)
});