{"id":47606767,"url":"https://github.com/block65/vite-plugin-vinext-payload","last_synced_at":"2026-05-03T17:01:38.037Z","repository":{"id":345648687,"uuid":"1186469912","full_name":"block65/vite-plugin-vinext-payload","owner":"block65","description":"Vite plugin for running Payload CMS with vinext","archived":false,"fork":false,"pushed_at":"2026-05-01T07:02:56.000Z","size":248,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-01T07:12:22.219Z","etag":null,"topics":["cloudflare","next","nextjs","vinext","vite"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/vite-plugin-vinext-payload","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/block65.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-19T16:53:43.000Z","updated_at":"2026-05-01T07:03:00.000Z","dependencies_parsed_at":"2026-04-02T12:12:43.062Z","dependency_job_id":null,"html_url":"https://github.com/block65/vite-plugin-vinext-payload","commit_stats":null,"previous_names":["block65/vite-plugin-vinext-payload"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/block65/vite-plugin-vinext-payload","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/block65%2Fvite-plugin-vinext-payload","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/block65%2Fvite-plugin-vinext-payload/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/block65%2Fvite-plugin-vinext-payload/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/block65%2Fvite-plugin-vinext-payload/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/block65","download_url":"https://codeload.github.com/block65/vite-plugin-vinext-payload/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/block65%2Fvite-plugin-vinext-payload/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32577126,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-03T06:36:36.687Z","status":"ssl_error","status_checked_at":"2026-05-03T06:36:09.306Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloudflare","next","nextjs","vinext","vite"],"created_at":"2026-04-01T19:30:44.613Z","updated_at":"2026-05-03T17:01:38.031Z","avatar_url":"https://github.com/block65.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# vite-plugin-vinext-payload\n\nVite plugin for running [Payload CMS](https://payloadcms.com/) with [vinext](https://github.com/cloudflare/vinext) (Cloudflare's Vite-based re-implementation of Next.js).\n\n\u003e **Experimental.** Both vinext and this plugin are experimental.\n\u003e\n\u003e **Validated against:** Payload `3.82.1`, vinext `0.0.41`, Vite `^8.0.0` (Rolldown), Node `\u003e=24`.\n\u003e\n\u003e Peer dependency ranges are pinned to the validated stack — see [`docs/upstream-bugs.md`](docs/upstream-bugs.md) for known regressions.\n\n## Migrating from Next.js\n\nIf you have an existing Payload CMS project on Next.js:\n\n```sh\nnpm install -D vinext vite             # Install vinext\nnpx vinext init                        # Convert Next.js → vinext\nnpm install -D vite-plugin-vinext-payload\nnpx vite-plugin-vinext-payload init    # Apply Payload-specific fixes\nnpm run dev\n```\n\n\u003e **Note:** `vinext init` runs `npm install` internally. If you hit peer dependency conflicts (common with `@vitejs/plugin-react`), run `npm install -D vinext vite --legacy-peer-deps` before `npx vinext init`.\n\nThe plugin's `init` command is idempotent — safe to run multiple times. It:\n\n- Adds `payloadPlugin()` to your `vite.config.ts`\n- Extracts the inline server function from `layout.tsx` into a separate `'use server'` module (required for Vite's RSC transform)\n- Adds `normalizeParams` to the admin page\n- If a `wrangler.{jsonc,json,toml}` is present, also adds `cloudflare()` to `vite.config.ts` and `@cloudflare/vite-plugin` to `devDependencies`\n\nUse `--dry-run` to preview changes without writing files.\n\nFor Cloudflare D1 projects, see **[Cloudflare D1 guide](docs/cloudflare-d1.md)** for additional configuration.\n\n## Quick Start\n\nIf you've already run `init`, or are setting up manually:\n\n```ts\n// vite.config.ts\nimport { defineConfig } from \"vite\";\nimport vinext from \"vinext\";\nimport { payloadPlugin } from \"vite-plugin-vinext-payload\";\n\nexport default defineConfig({\n\tplugins: [vinext(), payloadPlugin()],\n});\n```\n\nFor Cloudflare Workers with RSC:\n\n```ts\nimport { cloudflare } from \"@cloudflare/vite-plugin\";\nimport vinext from \"vinext\";\nimport { defineConfig } from \"vite\";\nimport { payloadPlugin } from \"vite-plugin-vinext-payload\";\n\nexport default defineConfig({\n\tplugins: [\n\t\tcloudflare({\n\t\t\tviteEnvironment: { name: \"rsc\", childEnvironments: [\"ssr\"] },\n\t\t}),\n\t\tvinext(),\n\t\tpayloadPlugin(),\n\t],\n});\n```\n\n`cloudflare:workers` is externalized automatically — no need to pass it via `ssrExternal`.\n\n## Options\n\n```ts\npayloadPlugin({\n\t// Additional packages to externalize from SSR bundling\n\tssrExternal: [\"some-native-package\"],\n\n\t// Additional packages to exclude from optimizeDeps\n\texcludeFromOptimize: [\"some-broken-package\"],\n\n\t// Additional CJS packages needing default export interop\n\tcjsInteropDeps: [\"some-cjs-dep\"],\n});\n```\n\n## What It Does\n\n`payloadPlugin()` composes these sub-plugins. They are not exported individually — splits exist purely for readability and maintenance:\n\n| Plugin | Owner bug | What it does |\n| --- | --- | --- |\n| `payloadUseClientBarrel` | Payload | Auto-detects `@payloadcms/*` barrel files that re-export from `'use client'` modules and excludes them from RSC pre-bundling (pre-bundling strips the directive, breaking client references) |\n| `payloadServerExternals` | Vite | Externalizes packages from both `ssr` and `rsc` environments. Only build tools and native addons are externalized (workerd can't resolve externals at runtime). Uses `configEnvironment` because `ssr.external` only applies to the `ssr` environment, and writes to `build.rolldownOptions.external` because `@cloudflare/vite-plugin` rejects `resolve.external` |\n| `payloadWorkerdCompat` | workerd / Rolldown | Four module-resolution / bundle-time fixes needed before code can evaluate inside workerd: (1) `resolveId` fallback for `node:*` CJS requires that bypass `@cloudflare/vite-plugin`'s filtered hook, (2) try-catch wrapper for undici's `detectRuntimeFeatureByExportedProperty` which crashes due to Rolldown's CJS→ESM interop returning void, (3) `import.meta.url ?? \"file:///\"` guards for `fileURLToPath` / `createRequire` patterns that crash in bundled workerd asset chunks, (4) `console.createTask` polyfill — workerd defines the method but throws \"not implemented\", breaking React 19 dev mode's async stack traces. Injected via both Vite transform and optimizeDeps rolldown plugin to cover pre-bundled deps |\n| `payloadWorkerdEntry` | Rolldown / @cloudflare/vite-plugin | `generateBundle` hook that re-wraps the RSC entry default export in `{ fetch }` when Rolldown inlines vinext's Workers handler wrapper into a bare function (regression of [workers-sdk#10213](https://github.com/cloudflare/workers-sdk/issues/10213) on Vite 8/Rolldown) |\n| `payloadHtmlDiffExportFix` | @vitejs/plugin-rsc / Rolldown | Patches `@payloadcms/ui/dist/exports/rsc/index.js` at build start to stabilize `getHTMLDiffComponents` export when RSC/Rolldown reports it as missing in latest templates |\n| `payloadOptimizeDeps` | vinext | Per-environment optimizeDeps: excludes problematic packages, force-includes CJS transitive deps for the client. Auto-discovers all `next/*` alias specifiers from the resolved config so the optimizer doesn't discover them at runtime (which causes a full page reload) |\n| `payloadCjsTransform` | Vite | Fixes `this` → `globalThis` in UMD/CJS wrappers and wraps `module.exports` with ESM scaffolding (skips React/ReactDOM which Vite 8 handles natively) |\n| `payloadCliStubs` | Payload | Stubs packages not needed at web runtime (`console-table-printer`, `json-schema-to-typescript`, `esbuild-register`, `ws`) |\n| `payloadNavComponentFix` | Payload | Patches `DefaultNavClient` and `DocumentTabLink` to not switch element types (`\u003ca\u003e` vs `\u003cdiv\u003e`) based on `usePathname()`/`useParams()` — prevents React 19 tree-destroying hydration mismatches (AST-based via ast-grep) |\n| `payloadNextNavigationFix` | vinext | Patches vinext's `next/navigation` shim on disk so `usePathname`/`useParams`/`useSearchParams` use client snapshots during hydration instead of the server context (which is `null` on the client) |\n| `payloadRedirectFix` | vinext | Catches `NEXT_REDIRECT` errors that leak through the RSC stream during async rendering and converts them to client-side `location.replace()` redirects |\n| `payloadRscExportFix` | @vitejs/plugin-rsc | Fixes `@vitejs/plugin-rsc`'s CSS export transform dropping exports after sourcemap comments |\n| `payloadRscRuntime` | vinext / workerd / pnpm | RSC environment patches: stubs `file-type` and `drizzle-kit/api`, and patches the RSC serializer to silently drop non-serializable values (functions, RegExps) at the server/client boundary (matching Next.js prod behavior) |\n| `payloadServerActionFix` | vinext | Moves `getReactRoot().render()` after the `returnValue` check in vinext's browser entry so data-returning server actions (like `getFormState`) don't trigger a re-render that resets Payload's form state. Also rewrites the browser entry's relative shim import to use the pre-bundled alias (AST-based via ast-grep) |\n| `cjsInterop` | Vite | Fixes CJS default export interop for packages like `bson-objectid` (via [vite-plugin-cjs-interop](https://github.com/nicolo-ribaudo/vite-plugin-cjs-interop)) |\n\n## Requirements\n\n- Node.js `\u003e=24`\n- Vite `^8.0.0`\n- vinext `0.0.41` (exact — vinext is pre-1.0; every patch can break things)\n- Payload CMS `^3.82.0`\n\n## Known Compatibility Issues\n\nThese all work fine on Next.js — they exist because vinext reimplements Next.js's framework layer on Vite. See [`docs/upstream-bugs.md`](docs/upstream-bugs.md) for details on what Next.js does differently.\n\n| Issue | Owner | Our workaround |\n| --- | --- | --- |\n| Barrel exports missing `'use client'` directive | Payload | Auto-exclude affected packages from RSC optimizeDeps |\n| RSC export transform drops exports after sourcemap comments | @vitejs/plugin-rsc | Post-transform newline insertion |\n| `getHTMLDiffComponents` missing export in RSC build | @vitejs/plugin-rsc / Rolldown | Patch `@payloadcms/ui/dist/exports/rsc/index.js` at build start |\n| `console.createTask` throws \"not implemented\" | workerd | Try/catch polyfill |\n| `node:*` CJS requires bypass cloudflare plugin's resolveId filter | Rolldown / @cloudflare/vite-plugin | Filterless resolveId fallback routing to unenv polyfills |\n| undici `detectRuntimeFeatureByExportedProperty` crashes on void | Rolldown | Try-catch wrapper around detection function |\n| `import.meta.url` undefined in bundled workerd asset chunks | workerd | `?? \"file:///\"` fallback guard on `fileURLToPath` and `createRequire` |\n| `ssr.external` only applies to \"ssr\" environment, not RSC | Vite | Use `build.rolldownOptions.external` via `configEnvironment` for both ssr/rsc |\n| `file-type` / `drizzle-kit/api` unresolvable in workerd | pnpm + Vite | Stub modules for RSC |\n| Navigation shim `getServerSnapshot` returns wrong values during hydration | vinext | Patch on disk to use client snapshots |\n| Browser entry imports shims via relative paths → optimizer reload + duplicate React | vinext | Rewrite import to aliased specifier; auto-include all `next/*` aliases in optimizeDeps |\n| `render()` called before `returnValue` check → form state reset | vinext | AST transform to reorder render after returnValue |\n| Components switch element types based on pathname/params → tree-destroying hydration mismatch | Payload | AST transform to force consistent element types |\n| Non-serializable values (functions, RegExps) not silently dropped at RSC boundary | vinext | Patch serializer throws to `return undefined` |\n| `NEXT_REDIRECT` errors leak through RSC stream during async rendering | vinext | Client-side redirect interception |\n| Rolldown inlines Workers entry wrapper into bare function | Rolldown / @cloudflare/vite-plugin | `generateBundle` hook re-wraps default export in `{ fetch }` ([workers-sdk#10213](https://github.com/cloudflare/workers-sdk/issues/10213)) |\n| CJS default export interop (e.g. `bson-objectid`) breaks named-import desugaring | Vite | `vite-plugin-cjs-interop` for the curated package list |\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblock65%2Fvite-plugin-vinext-payload","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblock65%2Fvite-plugin-vinext-payload","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblock65%2Fvite-plugin-vinext-payload/lists"}