Logo
热心市民王先生

关键代码验证

技术研究 人工智能 GitHub

mkdir my-vinext-app && cd my-vinext-app

快速开始示例

全新项目创建

# 创建项目目录
mkdir my-vinext-app && cd my-vinext-app

# 初始化 package.json
npm init -y

# 安装依赖
npm install vinext next react react-dom
npm install -D vite @vitejs/plugin-rsc

# 对于 Cloudflare Workers 部署
npm install -D @cloudflare/vite-plugin wrangler

基础配置

App Router 配置 (vite.config.ts)

import { defineConfig } from "vite";
import vinext from "vinext";
import rsc from "@vitejs/plugin-rsc";
import { cloudflare } from "@cloudflare/vite-plugin";

export default defineConfig({
  plugins: [
    // 1. Vinext 核心插件 - 处理 Next.js API 兼容
    vinext(),
    
    // 2. RSC 插件 - 支持 React Server Components
    rsc({
      entries: {
        // RSC 服务端渲染入口
        rsc: "virtual:vinext-rsc-entry",
        // SSR 入口
        ssr: "virtual:vinext-app-ssr-entry",
        // 客户端水合入口
        client: "virtual:vinext-app-browser-entry",
      },
    }),
    
    // 3. Cloudflare 插件 - Workers 运行时支持
    cloudflare({
      viteEnvironment: { 
        name: "rsc", 
        childEnvironments: ["ssr"] 
      },
    }),
  ],
});

Pages Router 配置(更简单)

import { defineConfig } from "vite";
import vinext from "vinext";

export default defineConfig({
  plugins: [vinext()],
});

项目结构

my-vinext-app/
├── app/                    # App Router 目录
│   ├── layout.tsx         # 根布局
│   ├── page.tsx           # 首页
│   ├── loading.tsx        # 加载状态
│   ├── error.tsx          # 错误处理
│   └── about/
│       └── page.tsx       # /about 页面
├── public/                 # 静态资源
├── next.config.js          # Next.js 配置(兼容)
├── vite.config.ts          # Vite 配置
└── package.json

核心功能验证

1. Server Components 示例

// app/page.tsx - Server Component(默认)
async function getData() {
  const res = await fetch('https://api.example.com/data', {
    // 自动使用 'use cache' 或 ISR
    next: { revalidate: 60 }
  });
  return res.json();
}

export default async function HomePage() {
  // 直接在服务端获取数据
  const data = await getData();
  
  return (
    <main>
      <h1>Server Component 示例</h1>
      <p>数据获取时间: {new Date().toISOString()}</p>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </main>
  );
}

2. Client Components 示例

// app/counter.tsx - Client Component
'use client';

import { useState } from 'react';

export function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <button onClick={() => setCount(c => c + 1)}>
      Count: {count}
    </button>
  );
}
// app/page.tsx - 在 Server Component 中使用 Client Component
import { Counter } from './counter';

export default function HomePage() {
  return (
    <main>
      <h1>混合渲染示例</h1>
      <p>这部分在服务端渲染</p>
      <Counter /> {/* 客户端水合 */}
    </main>
  );
}

3. Server Actions 示例

// app/actions.ts
'use server';

import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';

export async function createTodo(formData: FormData) {
  const title = formData.get('title') as string;
  
  // 在服务端执行数据库操作
  await db.todo.create({ data: { title } });
  
  // 重新验证缓存
  revalidatePath('/todos');
  
  // 或重定向
  redirect('/todos');
}
// app/todos/page.tsx
import { createTodo } from '../actions';

export default function TodosPage() {
  return (
    <form action={createTodo}>
      <input name="title" placeholder="New todo" required />
      <button type="submit">Add</button>
    </form>
  );
}

4. 缓存配置示例

// 使用 Cloudflare KV 作为缓存后端
import { KVCacheHandler } from 'vinext/cloudflare';
import { setCacheHandler } from 'next/cache';

// 在 worker/index.ts 或入口文件中设置
export default {
  async fetch(request: Request, env: Env) {
    // 设置 KV 缓存处理器
    setCacheHandler(new KVCacheHandler(env.CACHE_KV));
    
    // ... 处理请求
  }
};
// 使用 "use cache" 指令
'use cache';

import { cacheLife, cacheTag } from 'next/cache';

// 函数级别的缓存
export async function getCachedData() {
  'use cache';
  cacheLife('hours'); // 缓存 1 小时
  cacheTag('data');   // 可标记清除
  
  return fetchExpensiveData();
}

5. 中间件示例

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  // 获取请求路径
  const { pathname } = request.nextUrl;
  
  // 检查认证
  const token = request.cookies.get('token')?.value;
  
  // 保护 /admin 路由
  if (pathname.startsWith('/admin') && !token) {
    return NextResponse.redirect(new URL('/login', request.url));
  }
  
  // 添加自定义 header
  const response = NextResponse.next();
  response.headers.set('x-custom-header', 'vinext');
  
  return response;
}

export const config = {
  matcher: ['/((?!_next/static|favicon.ico).*)'],
};

从现有 Next.js 项目迁移

自动化迁移

# 在现有 Next.js 项目中
npx vinext init

该命令会自动:

  1. 运行兼容性检查 (vinext check)
  2. 安装 Vite 和相关依赖
  3. 重命名 CJS 配置文件(避免 ESM 冲突)
  4. 添加 "type": "module" 到 package.json
  5. 添加 npm scripts
  6. 生成 vite.config.ts

手动迁移步骤

  1. 安装依赖
npm install vinext
npm install -D vite @vitejs/plugin-rsc @cloudflare/vite-plugin
  1. 更新 package.json scripts
{
  "scripts": {
    "dev:vinext": "vinext dev",
    "build:vinext": "vinext build",
    "deploy:vinext": "vinext deploy",
    "dev": "next dev",
    "build": "next build"
  }
}
  1. 创建 vite.config.ts(见上方配置示例)

  2. 处理兼容性问题

# 检查兼容性
npx vinext check

# 输出示例:
# ✓ next/link - 支持
# ✓ App Router - 支持
# ⚠ next/image - 部分支持(无构建时优化)
# ✗ sharp - Workers 环境不支持(自动 stub)

常见迁移问题及解决方案

问题解决方案
CJS 配置报错重命名为 .cjs 后缀
path alias 不生效安装 vite-tsconfig-paths
MDX 不支持添加 @mdx-js/rollup
原生 Node 模块报错使用 Vinext 自动 stub 或手动 polyfill
图片优化失效使用 @unpic/react 或 Cloudflare Images

部署到 Cloudflare Workers

配置 wrangler

// wrangler.jsonc
{
  "name": "my-vinext-app",
  "compatibility_date": "2026-02-26",
  "main": "./worker/index.ts",
  "assets": {
    "directory": "./dist/client"
  },
  "kv_namespaces": [
    {
      "binding": "CACHE_KV",
      "id": "your-kv-namespace-id"
    }
  ],
  "d1_databases": [
    {
      "binding": "DB",
      "database_id": "your-d1-database-id"
    }
  ]
}

部署命令

# 一键部署
vinext deploy

# 指定环境
vinext deploy --env staging

# 预览部署
vinext deploy --preview

# 带 TPR(流量感知预渲染)
vinext deploy --experimental-tpr

Worker 入口文件示例

// worker/index.ts
import { createVinextHandler } from 'vinext/cloudflare';

export default createVinextHandler({
  // 自定义缓存配置
  cacheHandler: env => new KVCacheHandler(env.CACHE_KV),
  
  // 错误处理
  onError: (error, request) => {
    console.error('Request failed:', request.url, error);
  },
});

性能优化配置

1. 图片优化

// 使用 @unpic/react 替代 next/image
import { Image } from '@unpic/react';

export function OptimizedImage() {
  return (
    <Image
      src="https://example.com/photo.jpg"
      layout="constrained"
      width={800}
      height={600}
      alt="Description"
    />
  );
}

2. 字体加载

// 使用 next/font/google(运行时加载)
import { Inter } from 'next/font/google';

const inter = Inter({ subsets: ['latin'] });

export default function Layout({ children }) {
  return (
    <html className={inter.className}>
      <body>{children}</body>
    </html>
  );
}

3. 代码分割

Vite 自动处理代码分割,可通过动态导入进一步优化:

// 动态导入 heavy component
const HeavyChart = dynamic(() => import('./HeavyChart'), {
  loading: () => <p>Loading chart...</p>,
  ssr: false, // 禁用服务端渲染
});

参考资料