vinext-vite-nextjs by aradotso/trending-skills
npx skills add https://github.com/aradotso/trending-skills --skill vinext-vite-nextjsSkill 由 ara.so 提供 — Daily 2026 Skills 集合。
vinext 是一个 Vite 插件,它重新实现了 Next.js 的公共 API 接口(路由、SSR、RSC、next/* 导入、CLI),使得现有的 Next.js 应用可以在 Vite 上运行,而不是使用 Next.js 编译器。它的目标是实现约 94% 的 API 覆盖率,同时支持 Pages Router 和 App Router,并能原生部署到 Cloudflare Workers,同时通过可选的 Nitro 支持 AWS、Netlify、Vercel 等平台。
# 自动化一键迁移
npx vinext init
这将执行以下操作:
vinext check)vite、@vitejs/plugin-react 作为开发依赖@vitejs/plugin-rsc、react-server-dom-webpack广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
package.json 中添加 "type": "module"postcss.config.js → postcss.config.cjs)dev:vinext 和 build:vinext 脚本vite.config.ts迁移是非破坏性的 — Next.js 仍然可以与 vinext 并存。
npm install -D vinext vite @vitejs/plugin-react
# 仅 App Router 需要:
npm install -D @vitejs/plugin-rsc react-server-dom-webpack
更新 package.json 脚本:
{
"scripts": {
"dev": "vinext dev",
"build": "vinext build",
"start": "vinext start",
"deploy": "vinext deploy"
}
}
npx skills add cloudflare/vinext
# 然后在你的 AI 工具中:"migrate this project to vinext"
| 命令 | 描述 |
|---|---|
vinext dev | 启动开发服务器(支持 HMR) |
vinext build | 生产环境构建 |
vinext start | 本地生产服务器用于测试 |
vinext deploy | 构建并部署到 Cloudflare Workers |
vinext init | 从 Next.js 自动迁移 |
vinext check | 迁移前扫描兼容性问题 |
vinext lint | 委托给 eslint 或 oxlint |
vinext dev -p 3001 -H 0.0.0.0
vinext deploy --preview
vinext deploy --env staging --name my-app
vinext deploy --skip-build --dry-run
vinext deploy --experimental-tpr
vinext init --port 3001 --skip-check --force
vinext 会自动检测 app/ 或 pages/ 目录,并自动加载 next.config.js。基本使用无需 vite.config.ts。
vite.config.tsimport { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { vinext } from 'vinext/vite'
export default defineConfig({
plugins: [
react(),
vinext(),
],
})
vite.config.tsimport { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import rsc from '@vitejs/plugin-rsc'
import { vinext } from 'vinext/vite'
export default defineConfig({
plugins: [
react(),
rsc(),
vinext(),
],
})
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { vinext } from 'vinext/vite'
import { cloudflare } from '@cloudflare/vite-plugin'
export default defineConfig({
plugins: [
cloudflare(),
react(),
vinext(),
],
})
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { vinext } from 'vinext/vite'
import nitro from 'vite-plugin-nitro'
export default defineConfig({
plugins: [
react(),
vinext(),
nitro({ preset: 'vercel' }), // 或 'netlify', 'aws-amplify', 'deno-deploy' 等
],
})
vinext 使用与 Next.js 相同的目录约定 — 无需更改:
my-app/
├── app/ # App Router (自动检测)
│ ├── layout.tsx
│ ├── page.tsx
│ └── api/route.ts
├── pages/ # Pages Router (自动检测)
│ ├── index.tsx
│ └── api/hello.ts
├── public/ # 静态资源
├── next.config.js # 自动加载
├── package.json
└── vite.config.ts # 基本使用可选
// pages/index.tsx
import type { GetServerSideProps, InferGetServerSidePropsType } from 'next'
type Props = { data: string }
export const getServerSideProps: GetServerSideProps<Props> = async (ctx) => {
return { props: { data: 'Hello from SSR' } }
}
export default function Home({ data }: InferGetServerSidePropsType<typeof getServerSideProps>) {
return <h1>{data}</h1>
}
// pages/posts/[id].tsx
import type { GetStaticPaths, GetStaticProps } from 'next'
export const getStaticPaths: GetStaticPaths = async () => {
return {
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
fallback: false,
}
}
export const getStaticProps: GetStaticProps = async ({ params }) => {
return { props: { id: params?.id } }
}
export default function Post({ id }: { id: string }) {
return <p>Post {id}</p>
}
// pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'
export default function handler(req: NextApiRequest, res: NextApiResponse) {
res.status(200).json({ message: 'Hello from vinext' })
}
// app/page.tsx
export default async function Page() {
const data = await fetch('https://api.example.com/data').then(r => r.json())
return <main>{data.title}</main>
}
// app/api/route.ts
import { NextRequest, NextResponse } from 'next/server'
export async function GET(request: NextRequest) {
return NextResponse.json({ status: 'ok' })
}
export async function POST(request: NextRequest) {
const body = await request.json()
return NextResponse.json({ received: body })
}
// app/actions.ts
'use server'
export async function submitForm(formData: FormData) {
const name = formData.get('name')
// 服务器端逻辑写在这里
return { success: true, name }
}
// app/form.tsx
'use client'
import { submitForm } from './actions'
export function Form() {
return (
<form action={submitForm}>
<input name="name" />
<button type="submit">Submit</button>
</form>
)
}
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const token = request.cookies.get('token')
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/dashboard/:path*'],
}
// app/api/kv/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { getCloudflareContext } from 'cloudflare:workers'
export async function GET(request: NextRequest) {
const { env } = getCloudflareContext()
const value = await env.MY_KV.get('key')
return NextResponse.json({ value })
}
// app/page.tsx
import Image from 'next/image'
export default function Page() {
return (
<Image
src="/hero.png"
alt="Hero"
width={800}
height={400}
priority
/>
)
}
// app/nav.tsx
'use client'
import Link from 'next/link'
import { useRouter, usePathname } from 'next/navigation'
export function Nav() {
const router = useRouter()
const pathname = usePathname()
return (
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<button onClick={() => router.push('/dashboard')}>Dashboard</button>
</nav>
)
}
# 认证(只需一次)
wrangler login
# 部署
vinext deploy
# 部署到预览环境
vinext deploy --preview
# 部署到指定环境
vinext deploy --env production --name my-production-app
对于 CI/CD,可以设置 CLOUDFLARE_API_TOKEN 环境变量来代替 wrangler login。
wrangler.toml (Cloudflare 配置)name = "my-app"
compatibility_date = "2024-01-01"
compatibility_flags = ["nodejs_compat"]
[[kv_namespaces]]
binding = "MY_KV"
id = "your-kv-namespace-id"
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "my-bucket"
npm install -D vite-plugin-nitro
# 然后将 nitro 插件添加到 vite.config.ts 中,并指定目标预设
# nitro({ preset: 'netlify' })
# nitro({ preset: 'vercel' })
# nitro({ preset: 'aws-amplify' })
next.config.js 支持vinext 会自动加载你现有的 next.config.js:
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{ protocol: 'https', hostname: 'images.example.com' },
],
},
env: {
MY_VAR: process.env.MY_VAR,
},
redirects: async () => [
{ source: '/old', destination: '/new', permanent: true },
],
rewrites: async () => [
{ source: '/api/:path*', destination: 'https://backend.example.com/:path*' },
],
}
module.exports = nextConfig
在迁移前运行以识别不支持的功能:
npx vinext check
这会扫描:
next.config.js 选项与 Next.js 工作方式相同 — .env、.env.local、.env.production:
# .env.local
NEXT_PUBLIC_API_URL=https://api.example.com
DATABASE_URL=$DATABASE_URL
// 在客户端代码中可访问(NEXT_PUBLIC_ 前缀)
const apiUrl = process.env.NEXT_PUBLIC_API_URL
// 仅服务器端
const dbUrl = process.env.DATABASE_URL
// tsconfig.json — 直接使用
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
}
}
npm install -D tailwindcss postcss autoprefixer
# 重命名 postcss.config.js → postcss.config.cjs (vinext init 会自动完成)
// postcss.config.cjs
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
# vinext init 会自动处理,或手动重命名:
mv postcss.config.js postcss.config.cjs
mv tailwind.config.js tailwind.config.cjs
确保 package.json 中包含 "type": "module"。
vinext init 覆盖了现有的 vite.config.tsvinext init --force
vinext init --skip-check
vinext dev -p 3001
vinext init --port 3001
wrangler 未认证wrangler login
# 或设置环境变量:
export CLOUDFLARE_API_TOKEN=your_token_here
vinext deploy --dry-run
App Router 构建会生成三个环境(RSC + SSR + 客户端)。如果遇到构建错误,请确保安装了所有三个插件:
npm install -D @vitejs/plugin-rsc react-server-dom-webpack
并且你的 vite.config.ts 以正确的顺序包含了 react() 和 rsc() 插件。
next/image、next/link、next/router、next/navigation、next/headnext/font、next/dynamicnext.config.js (重定向, 重写, 头部, 环境变量, 图片)每周安装量
284
代码仓库
GitHub Stars
10
首次出现
7 天前
安全审计
已安装于
gemini-cli283
github-copilot283
codex283
amp283
cline283
kimi-cli283
Skill by ara.so — Daily 2026 Skills collection.
vinext is a Vite plugin that reimplements the Next.js public API surface (routing, SSR, RSC, next/* imports, CLI) so existing Next.js apps run on Vite instead of the Next.js compiler. It targets ~94% API coverage, supports both Pages Router and App Router, and deploys natively to Cloudflare Workers with optional Nitro support for AWS, Netlify, Vercel, and more.
# Automated one-command migration
npx vinext init
This will:
vinext check)vite, @vitejs/plugin-react as devDependencies@vitejs/plugin-rsc, react-server-dom-webpack for App Router"type": "module" to package.jsonpostcss.config.js → postcss.config.cjs)dev:vinext and build:vinext scriptsvite.config.tsMigration is non-destructive — Next.js still works alongside vinext.
npm install -D vinext vite @vitejs/plugin-react
# App Router only:
npm install -D @vitejs/plugin-rsc react-server-dom-webpack
Update package.json scripts:
{
"scripts": {
"dev": "vinext dev",
"build": "vinext build",
"start": "vinext start",
"deploy": "vinext deploy"
}
}
npx skills add cloudflare/vinext
# Then in your AI tool: "migrate this project to vinext"
| Command | Description |
|---|---|
vinext dev | Start dev server with HMR |
vinext build | Production build |
vinext start | Local production server for testing |
vinext deploy | Build + deploy to Cloudflare Workers |
vinext init | Automated migration from Next.js |
vinext check | Scan for compatibility issues before migrating |
vinext dev -p 3001 -H 0.0.0.0
vinext deploy --preview
vinext deploy --env staging --name my-app
vinext deploy --skip-build --dry-run
vinext deploy --experimental-tpr
vinext init --port 3001 --skip-check --force
vinext auto-detects app/ or pages/ directory and loads next.config.js automatically. No vite.config.ts is required for basic usage.
vite.config.tsimport { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { vinext } from 'vinext/vite'
export default defineConfig({
plugins: [
react(),
vinext(),
],
})
vite.config.tsimport { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import rsc from '@vitejs/plugin-rsc'
import { vinext } from 'vinext/vite'
export default defineConfig({
plugins: [
react(),
rsc(),
vinext(),
],
})
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { vinext } from 'vinext/vite'
import { cloudflare } from '@cloudflare/vite-plugin'
export default defineConfig({
plugins: [
cloudflare(),
react(),
vinext(),
],
})
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { vinext } from 'vinext/vite'
import nitro from 'vite-plugin-nitro'
export default defineConfig({
plugins: [
react(),
vinext(),
nitro({ preset: 'vercel' }), // or 'netlify', 'aws-amplify', 'deno-deploy', etc.
],
})
vinext uses the same directory conventions as Next.js — no changes required:
my-app/
├── app/ # App Router (auto-detected)
│ ├── layout.tsx
│ ├── page.tsx
│ └── api/route.ts
├── pages/ # Pages Router (auto-detected)
│ ├── index.tsx
│ └── api/hello.ts
├── public/ # Static assets
├── next.config.js # Loaded automatically
├── package.json
└── vite.config.ts # Optional for basic usage
// pages/index.tsx
import type { GetServerSideProps, InferGetServerSidePropsType } from 'next'
type Props = { data: string }
export const getServerSideProps: GetServerSideProps<Props> = async (ctx) => {
return { props: { data: 'Hello from SSR' } }
}
export default function Home({ data }: InferGetServerSidePropsType<typeof getServerSideProps>) {
return <h1>{data}</h1>
}
// pages/posts/[id].tsx
import type { GetStaticPaths, GetStaticProps } from 'next'
export const getStaticPaths: GetStaticPaths = async () => {
return {
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
fallback: false,
}
}
export const getStaticProps: GetStaticProps = async ({ params }) => {
return { props: { id: params?.id } }
}
export default function Post({ id }: { id: string }) {
return <p>Post {id}</p>
}
// pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'
export default function handler(req: NextApiRequest, res: NextApiResponse) {
res.status(200).json({ message: 'Hello from vinext' })
}
// app/page.tsx
export default async function Page() {
const data = await fetch('https://api.example.com/data').then(r => r.json())
return <main>{data.title}</main>
}
// app/api/route.ts
import { NextRequest, NextResponse } from 'next/server'
export async function GET(request: NextRequest) {
return NextResponse.json({ status: 'ok' })
}
export async function POST(request: NextRequest) {
const body = await request.json()
return NextResponse.json({ received: body })
}
// app/actions.ts
'use server'
export async function submitForm(formData: FormData) {
const name = formData.get('name')
// server-side logic here
return { success: true, name }
}
// app/form.tsx
'use client'
import { submitForm } from './actions'
export function Form() {
return (
<form action={submitForm}>
<input name="name" />
<button type="submit">Submit</button>
</form>
)
}
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const token = request.cookies.get('token')
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/dashboard/:path*'],
}
// app/api/kv/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { getCloudflareContext } from 'cloudflare:workers'
export async function GET(request: NextRequest) {
const { env } = getCloudflareContext()
const value = await env.MY_KV.get('key')
return NextResponse.json({ value })
}
// app/page.tsx
import Image from 'next/image'
export default function Page() {
return (
<Image
src="/hero.png"
alt="Hero"
width={800}
height={400}
priority
/>
)
}
// app/nav.tsx
'use client'
import Link from 'next/link'
import { useRouter, usePathname } from 'next/navigation'
export function Nav() {
const router = useRouter()
const pathname = usePathname()
return (
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<button onClick={() => router.push('/dashboard')}>Dashboard</button>
</nav>
)
}
# Authenticate (once)
wrangler login
# Deploy
vinext deploy
# Deploy to preview
vinext deploy --preview
# Deploy to named environment
vinext deploy --env production --name my-production-app
For CI/CD, set CLOUDFLARE_API_TOKEN environment variable instead of wrangler login.
wrangler.toml (Cloudflare config)name = "my-app"
compatibility_date = "2024-01-01"
compatibility_flags = ["nodejs_compat"]
[[kv_namespaces]]
binding = "MY_KV"
id = "your-kv-namespace-id"
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "my-bucket"
npm install -D vite-plugin-nitro
# Then add nitro plugin to vite.config.ts with your target preset
# nitro({ preset: 'netlify' })
# nitro({ preset: 'vercel' })
# nitro({ preset: 'aws-amplify' })
next.config.js Supportvinext loads your existing next.config.js automatically:
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{ protocol: 'https', hostname: 'images.example.com' },
],
},
env: {
MY_VAR: process.env.MY_VAR,
},
redirects: async () => [
{ source: '/old', destination: '/new', permanent: true },
],
rewrites: async () => [
{ source: '/api/:path*', destination: 'https://backend.example.com/:path*' },
],
}
module.exports = nextConfig
Run before migrating to identify unsupported features:
npx vinext check
This scans for:
next.config.js optionsWorks the same as Next.js — .env, .env.local, .env.production:
# .env.local
NEXT_PUBLIC_API_URL=https://api.example.com
DATABASE_URL=$DATABASE_URL
// Accessible in client code (NEXT_PUBLIC_ prefix)
const apiUrl = process.env.NEXT_PUBLIC_API_URL
// Server-only
const dbUrl = process.env.DATABASE_URL
// tsconfig.json — works as-is
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
}
}
npm install -D tailwindcss postcss autoprefixer
# Rename postcss.config.js → postcss.config.cjs (vinext init does this automatically)
// postcss.config.cjs
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
# vinext init handles this automatically, or rename manually:
mv postcss.config.js postcss.config.cjs
mv tailwind.config.js tailwind.config.cjs
Ensure package.json has "type": "module".
vinext init overwrites existing vite.config.tsvinext init --force
vinext init --skip-check
vinext dev -p 3001
vinext init --port 3001
wrangler not authenticated for deploywrangler login
# or set env var:
export CLOUDFLARE_API_TOKEN=your_token_here
vinext deploy --dry-run
App Router builds produce three environments (RSC + SSR + client). If you see build errors, ensure all three plugins are installed:
npm install -D @vitejs/plugin-rsc react-server-dom-webpack
And your vite.config.ts includes both react() and rsc() plugins in the correct order.
next/image, next/link, next/router, next/navigation, next/headnext/font, next/dynamicnext.config.js (redirects, rewrites, headers, env, images)Weekly Installs
284
Repository
GitHub Stars
10
First Seen
7 days ago
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
gemini-cli283
github-copilot283
codex283
amp283
cline283
kimi-cli283
Azure 升级评估与自动化工具 - 轻松迁移 Functions 计划、托管层级和 SKU
68,100 周安装
Resend 邮件发送与接收 API 指南:Node.js/Python SDK 使用、批量发送与幂等性
4,500 周安装
视觉设计基础:排版、色彩、间距与图标系统设计指南 | 构建一致可访问的UI
4,600 周安装
Web组件设计指南:构建可复用UI组件库与设计系统的最佳实践
4,700 周安装
Godot 4 GDScript 设计模式与最佳实践 - 游戏开发架构、信号、场景优化
4,700 周安装
blucli (blu) - 命令行控制 Bluesound/NAD 播放器,支持设备管理、播放控制和脚本自动化
278 周安装
变更日志自动化工具:自动生成发布说明,管理语义化版本控制
4,700 周安装
vinext lint | Delegate to eslint or oxlint |