Next-js-Boilerplate渐进式迁移:从Create React App到Next.js分步指南
Next-js-Boilerplate渐进式迁移:从Create React App到Next.js分步指南
引言:为什么要迁移到Next.js?
你还在为Create React App的性能瓶颈、SEO问题和复杂的配置而烦恼吗?随着React生态的不断发展,Next.js已经成为构建现代React应用的首选框架。本指南将带你逐步完成从Create React App到Next.js的平滑迁移,充分利用Next.js 14+的强大功能,包括App Router、服务器组件、内置优化和增强的开发体验。
读完本文,你将能够:
- 理解Create React App与Next.js的核心差异
- 分步实施迁移计划,最小化业务中断
- 利用Next.js的高级特性提升应用性能和SEO
- 优化开发流程,集成TypeScript、ESLint和测试工具
- 解决常见迁移问题,确保平稳过渡
一、迁移前的准备工作
1.1 环境要求检查
在开始迁移前,请确保你的开发环境满足以下要求:
| 环境要求 | 版本 | 检查命令 |
|---|---|---|
| Node.js | >=20 | node -v |
| npm | >=8 | npm -v |
| Git | 任意稳定版 | git --version |
| 操作系统 | Windows/macOS/Linux | - |
如果需要升级Node.js,建议使用nvm(Node Version Manager)进行版本管理。
1.2 项目评估与规划
在迁移前,对现有Create React App项目进行全面评估至关重要。创建一个迁移清单,包括:
- 项目规模和复杂度
- 使用的第三方库和依赖
- 自定义配置(webpack、babel等)
- 路由结构
- 状态管理方案
- API调用方式
- 测试覆盖率
以下是一个项目评估表,可帮助你识别潜在挑战:
| 项目特性 | 现状 | Next.js对应方案 | 迁移难度 |
|---|---|---|---|
| 路由管理 | React Router | App Router/Page Router | 中 |
| 数据获取 | 客户端fetch/axios | 服务器组件/SWR/React Query | 中 |
| 状态管理 | Redux/MobX/Context API | React Context/Zustand/Jotai | 低-中 |
| 样式方案 | CSS Modules/SCSS/Styled Components | Tailwind CSS/CSS Modules | 低 |
| 构建工具 | CRA内置webpack | Next.js内置webpack | 低 |
| 测试工具 | Jest/React Testing Library | Vitest/Playwright | 中 |
1.3 创建迁移分支
为避免影响现有开发,建议在Git中创建专门的迁移分支:
# 克隆仓库
git clone https://gitcode.com/GitHub_Trending/ne/Next-js-Boilerplate
cd Next-js-Boilerplate
# 创建迁移分支
git checkout -b migrate-from-cra
二、项目结构迁移
2.1 目录结构对比
Create React App和Next.js的目录结构有显著差异,特别是在引入App Router后。以下是主要对比:
# Create React App 典型结构
src/
├── assets/ # 静态资源
├── components/ # React组件
├── pages/ # 页面组件 (通常与React Router配合)
├── services/ # API服务
├── utils/ # 工具函数
├── App.js # 根组件
├── index.js # 入口文件
└── routes.js # 路由配置
# Next.js 14+ App Router结构
src/
├── app/ # App Router根目录
│ ├── [locale]/ # 国际化路由
│ │ ├── (auth)/ # 认证相关路由组
│ │ └── (marketing)/ # 营销页面路由组
│ ├── api/ # API路由
│ ├── layout.tsx # 根布局
│ └── page.tsx # 首页
├── components/ # React组件
├── libs/ # 工具库和配置
├── models/ # 数据模型
└── utils/ # 工具函数
2.2 核心文件迁移
2.2.1 从index.js到App Router入口
Create React App的入口文件通常是src/index.js,而Next.js 14+使用App Router时,入口是src/app/layout.tsx和src/app/page.tsx。
迁移步骤:
- 创建根布局文件
src/app/layout.tsx:
// src/app/layout.tsx
import '@/styles/global.css';
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Next.js Boilerplate',
description: '从Create React App迁移到Next.js的示例项目',
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
- 创建首页文件
src/app/page.tsx:
// src/app/page.tsx
export default function Home() {
return (
<main>
<h1>欢迎来到Next.js应用</h1>
{/* 迁移自CRA的首页内容 */}
</main>
);
}
2.2.2 路由系统迁移
将React Router迁移到Next.js App Router是迁移过程中的核心任务之一。Next.js App Router基于文件系统,使用目录结构定义路由。
关键差异对比:
| 功能 | React Router (CRA) | Next.js App Router |
|---|---|---|
| 路由定义 | JSX配置或routes.js | 文件系统目录结构 |
| 动态路由 | :param 语法 |
[param] 目录 |
| 嵌套路由 | Outlet 组件 |
嵌套目录 + layout.tsx |
| 路由守卫 | 自定义HOC或组件 | 中间件(middleware.ts) |
| 代码分割 | 需要手动配置 | 自动基于路由分割 |
迁移示例:
CRA中使用React Router的路由配置:
// src/routes.js
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Contact from './pages/Contact';
import NotFound from './pages/NotFound';
function AppRoutes() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
迁移到Next.js App Router:
src/
└── app/
├── page.tsx # 对应 / 路由
├── about/
│ └── page.tsx # 对应 /about 路由
├── contact/
│ └── page.tsx # 对应 /contact 路由
└── not-found.tsx # 对应 404 路由
2.3 静态资源迁移
Next.js提供了更高效的静态资源处理方式。将CRA项目中的静态资源迁移到Next.js:
- 将
public/目录下的所有文件复制到Next.js项目的public/目录。 - 将组件中引用的资源路径从相对路径改为绝对路径:
// CRA
import logo from './logo.svg';
<img src={logo} alt="Logo" />
// Next.js
<img src="/logo.svg" alt="Logo" />
- 对于需要优化的图片,使用Next.js的
next/image组件:
import Image from 'next/image';
function Logo() {
return (
<Image
src="/logo.svg"
alt="Logo"
width={120}
height={40}
priority // 首屏关键图片
/>
);
}
三、依赖与配置迁移
3.1 package.json 配置迁移
对比CRA和Next.js项目的package.json,主要差异在依赖和脚本部分。以下是关键迁移步骤:
- 核心依赖替换:
{
"dependencies": {
// 移除CRA依赖
"react-scripts": "^5.0.1",
"react-router-dom": "^6.22.0",
// 添加Next.js核心依赖
"next": "^15.5.0",
"react": "19.1.1",
"react-dom": "19.1.1"
}
}
- 脚本命令替换:
{
"scripts": {
// 移除CRA脚本
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
// 添加Next.js脚本
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "vitest run",
"test:e2e": "playwright test"
}
}
- 添加TypeScript支持(如果使用):
Next.js Boilerplate已内置TypeScript支持,确保tsconfig.json配置正确:
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [{ "name": "next" }],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
3.2 样式方案迁移
Next.js Boilerplate使用Tailwind CSS作为主要样式方案。如果你的CRA项目使用其他样式方案,需要进行相应迁移:
3.2.1 从CSS/SCSS迁移到Tailwind CSS
- 安装Tailwind CSS依赖:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
- 配置Tailwind CSS:
// tailwind.config.js
module.exports = {
content: [
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
- 创建全局CSS文件:
/* src/styles/global.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
- 在根布局中导入全局CSS:
// src/app/layout.tsx
import '@/styles/global.css';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
- 将组件中的CSS类迁移到Tailwind类:
// CRA中的CSS Modules方式
import styles from './Button.module.css';
function Button() {
return <button className={styles.primary}>Click me</button>;
}
// Next.js中的Tailwind方式
function Button() {
return <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Click me</button>;
}
3.2.2 保留CSS Modules(如果需要)
如果你希望继续使用CSS Modules,Next.js也提供了良好支持:
src/
├── components/
│ ├── Button.tsx
│ └── Button.module.css
// src/components/Button.tsx
import styles from './Button.module.css';
export default function Button() {
return <button className={styles.button}>Click me</button>;
}
3.3 环境变量配置
Next.js和Create React App在环境变量处理上有所不同:
| 特性 | Create React App | Next.js |
|---|---|---|
| 前缀 | REACT_APP_* | NEXT_PUBLIC_* (客户端) |
| 服务器端变量 | 无特殊前缀 | 无前缀 (仅服务器访问) |
| 默认环境文件 | .env.development, .env.production | .env.local, .env.development.local等 |
| 加载顺序 | 特定环境文件覆盖通用文件 | 更具体的环境文件覆盖一般文件 |
迁移步骤:
- 将所有
REACT_APP_*前缀的环境变量重命名为NEXT_PUBLIC_*:
# .env.development
# 从
REACT_APP_API_URL=http://localhost:3001/api
# 改为
NEXT_PUBLIC_API_URL=http://localhost:3001/api
- 对于仅在服务器端使用的变量,移除前缀:
# .env.local
# 服务器端专用变量,不会暴露给客户端
DB_CONNECTION_STRING=postgres://user:pass@localhost:5432/mydb
- 在代码中使用环境变量:
// 客户端组件中
console.log(process.env.NEXT_PUBLIC_API_URL);
// 服务器组件中
console.log(process.env.DB_CONNECTION_STRING);
四、核心功能迁移
4.1 页面和组件迁移
将CRA项目中的页面和组件迁移到Next.js时,需要注意以下几点:
- 文件扩展名:将
.js或.jsx文件改为.tsx(如果使用TypeScript)。 - 默认导出:页面组件应使用默认导出。
- 导入路径:利用Next.js的路径别名
@/*简化导入。
迁移示例:
CRA中的页面组件:
// src/pages/Home.jsx
import React from 'react';
import Header from '../components/Header';
import Footer from '../components/Footer';
import HeroSection from '../components/HeroSection';
import FeaturesSection from '../components/FeaturesSection';
function HomePage() {
return (
<div className="app">
<Header />
<main>
<HeroSection />
<FeaturesSection />
</main>
<Footer />
</div>
);
}
export default HomePage;
迁移到Next.js的页面组件:
// src/app/page.tsx
import Header from '@/components/Header';
import Footer from '@/components/Footer';
import HeroSection from '@/components/HeroSection';
import FeaturesSection from '@/components/FeaturesSection';
export default function HomePage() {
return (
<div className="min-h-screen flex flex-col">
<Header />
<main className="flex-grow">
<HeroSection />
<FeaturesSection />
</main>
<Footer />
</div>
);
}
4.2 数据获取迁移
Next.js提供了多种数据获取方式,与CRA中通常在客户端获取数据的方式有很大不同:
| 数据获取方式 | Create React App | Next.js App Router |
|---|---|---|
| 主要位置 | 客户端组件 useEffect | 服务器组件顶层 |
| 数据获取API | fetch, axios等 | fetch (扩展版), 第三方库 |
| 缓存策略 | 需手动实现 | 内置缓存和重新验证 |
| 预渲染 | 无 | 静态生成(SSG)和服务器端渲染(SSR) |
| 增量静态再生 | 无 | ISR (Incremental Static Regeneration) |
迁移示例:客户端数据获取
CRA中使用useEffect获取数据:
// src/pages/Products.jsx
import { useState, useEffect } from 'react';
function Products() {
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchProducts() {
try {
setLoading(true);
const response = await fetch('/api/products');
if (!response.ok) throw new Error('Failed to fetch products');
const data = await response.json();
setProducts(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
fetchProducts();
}, []);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div>
<h1>Products</h1>
<ul>
{products.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
</div>
);
}
export default Products;
Next.js中使用服务器组件获取数据:
// src/app/products/page.tsx
async function getProducts() {
const response = await fetch('https://api.example.com/products', {
next: { revalidate: 60 }, // 每60秒重新验证数据
});
if (!response.ok) {
throw new Error('Failed to fetch products');
}
return response.json();
}
export default async function ProductsPage() {
const products = await getProducts();
return (
<div>
<h1 className="text-3xl font-bold mb-6">Products</h1>
<ul className="space-y-4">
{products.map(product => (
<li key={product.id} className="border p-4 rounded-lg">
{product.name}
</li>
))}
</ul>
</div>
);
}
4.3 API路由迁移
Create React App通常需要单独的后端服务来提供API,而Next.js内置了API路由功能:
迁移步骤:
- 创建API路由目录:
mkdir -p src/app/api
- 将CRA项目中的API逻辑迁移到Next.js API路由:
CRA项目中可能使用Express后端:
// server/routes/products.js
const express = require('express');
const router = express.Router();
const Product = require('../models/Product');
router.get('/', async (req, res) => {
try {
const products = await Product.find();
res.json(products);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
router.post('/', async (req, res) => {
try {
const product = new Product(req.body);
await product.save();
res.status(201).json(product);
} catch (err) {
res.status(400).json({ error: err.message });
}
});
module.exports = router;
迁移到Next.js API路由:
// src/app/api/products/route.ts
import { NextResponse } from 'next/server';
import { Product } from '@/models/Product';
// GET请求处理
export async function GET() {
try {
const products = await Product.find();
return NextResponse.json(products);
} catch (err) {
return NextResponse.json(
{ error: (err as Error).message },
{ status: 500 }
);
}
}
// POST请求处理
export async function POST(request: Request) {
try {
const data = await request.json();
const product = new Product(data);
await product.save();
return NextResponse.json(product, { status: 201 });
} catch (err) {
return NextResponse.json(
{ error: (err as Error).message },
{ status: 400 }
);
}
}
- 更新客户端API调用URL:
// 从
fetch('http://localhost:3001/api/products')
// 改为
fetch('/api/products')
4.4 认证系统迁移
Next.js Boilerplate集成了Clerk认证系统,提供了比CRA项目中通常使用的自定义认证更完善的解决方案:
迁移步骤:
- 安装Clerk依赖:
npm install @clerk/nextjs @clerk/localizations
- 在Next.js配置中添加Clerk:
// src/app/layout.tsx
import { ClerkProvider } from '@clerk/nextjs';
import { frFR } from '@clerk/localizations';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<ClerkProvider localization={frFR}>
{children}
</ClerkProvider>
</body>
</html>
);
}
- 创建认证页面:
// src/app/(auth)/sign-in/page.tsx
import { SignIn } from '@clerk/nextjs';
export default function SignInPage() {
return (
<div className="flex justify-center items-center min-h-screen">
<SignIn />
</div>
);
}
// src/app/(auth)/sign-up/page.tsx
import { SignUp } from '@clerk/nextjs';
export default function SignUpPage() {
return (
<div className="flex justify-center items-center min-h-screen">
<SignUp />
</div>
);
}
- 创建认证保护路由:
// src/middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
const isProtectedRoute = createRouteMatcher([
'/dashboard(.*)',
'/profile(.*)',
]);
export default clerkMiddleware((auth, req) => {
if (isProtectedRoute(req)) {
auth.protect();
}
});
export const config = {
matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'],
};
- 在组件中使用认证状态:
// src/components/Header.tsx
import { UserButton, useAuth } from '@clerk/nextjs';
export default function Header() {
const { isSignedIn } = useAuth();
return (
<header className="flex justify-between items-center p-4 border-b">
<h1 className="text-xl font-bold">My App</h1>
<nav>
{isSignedIn ? (
<UserButton />
) : (
<div className="space-x-2">
<a href="/sign-in" className="px-4 py-2">Sign In</a>
<a href="/sign-up" className="px-4 py-2 bg-blue-500 text-white">Sign Up</a>
</div>
)}
</nav>
</header>
);
}
五、国际化支持迁移
Next.js Boilerplate内置了强大的国际化(i18n)支持,使用next-intl库。如果你的CRA项目使用其他i18n解决方案(如react-i18next),可以按以下步骤迁移:
5.1 安装和配置next-intl
- 安装依赖:
npm install next-intl
- 创建国际化配置:
// src/libs/I18n.ts
import { getRequestConfig } from 'next-intl/server';
export default getRequestConfig(async ({ requestLocale }) => {
// 获取请求的语言环境
const locale = requestLocale || 'en';
return {
locale,
messages: (await import(`../locales/${locale}.json`)).default,
};
});
- 配置Next.js:
// next.config.ts
import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin('./src/libs/I18n.ts');
/** @type {import('next').NextConfig} */
const nextConfig = {
// 其他配置...
};
export default withNextIntl(nextConfig);
5.2 创建翻译文件
// src/locales/en.json
{
"Index": {
"welcome": "Welcome",
"description": "This is a sample application",
"learn_more": "Learn more"
},
"Button": {
"submit": "Submit",
"cancel": "Cancel"
}
}
// src/locales/fr.json
{
"Index": {
"welcome": "Bienvenue",
"description": "Ceci est une application exemple",
"learn_more": "En savoir plus"
},
"Button": {
"submit": "Soumettre",
"cancel": "Annuler"
}
}
5.3 在组件中使用翻译
// src/components/Welcome.tsx
import { useTranslations } from 'next-intl';
export default function Welcome() {
const t = useTranslations('Index');
return (
<div>
<h1>{t('welcome')}</h1>
<p>{t('description')}</p>
<button>{t('learn_more')}</button>
</div>
);
}
5.4 设置国际化路由
// src/app/[locale]/layout.tsx
import { NextIntlClientProvider } from 'next-intl';
import { getTranslations } from 'next-intl/server';
export default async function LocaleLayout({
children,
params: { locale }
}) {
const messages = await getTranslations({ locale, namespace: 'Layout' });
return (
<html lang={locale}>
<body>
<NextIntlClientProvider locale={locale} messages={messages}>
{children}
</NextIntlClientProvider>
</body>
</html>
);
}
// 生成静态参数
export function generateStaticParams() {
return ['en', 'fr'].map(locale => ({ locale }));
}
六、测试系统迁移
Next.js Boilerplate使用Vitest和Playwright进行测试,而CRA通常使用Jest和React Testing Library。以下是迁移测试系统的主要步骤:
6.1 单元测试迁移(Jest到Vitest)
- 安装Vitest相关依赖:
npm install -D vitest @vitejs/plugin-react vite-tsconfig-paths @vitest/coverage-v8 jsdom
- 创建Vitest配置文件:
// vitest.config.mts
import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
import { defineConfig } from 'vitest/config';
export default defineConfig({
plugins: [react(), tsconfigPaths()],
test: {
environment: 'jsdom',
coverage: {
include: ['src/**/*'],
exclude: ['src/**/*.stories.tsx'],
},
setupFiles: ['./src/setupTests.ts'],
},
});
- 创建测试设置文件:
// src/setupTests.ts
import '@testing-library/jest-dom/vitest';
- 更新package.json脚本:
{
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage"
}
}
- 迁移测试文件:
大多数Jest测试可以直接在Vitest中运行,只需将文件扩展名从.test.js改为.test.tsx(如果使用TypeScript):
// src/components/Hello.test.tsx
import { render, screen } from '@testing-library/react';
import Hello from './Hello';
describe('Hello', () => {
it('renders a welcome message', () => {
render(<Hello name="John" />);
expect(screen.getByText(/hello, john!/i)).toBeInTheDocument();
});
});
6.2 端到端测试迁移(Cypress到Playwright)
Next.js Boilerplate使用Playwright进行端到端测试:
- 安装Playwright:
npm install -D playwright @playwright/test
npx playwright install
- 创建Playwright配置:
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests/e2e',
timeout: 30 * 1000,
expect: {
timeout: 5000,
},
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 1,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
webServer: {
command: 'npm run dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
},
});
- 创建测试文件:
// tests/e2e/homepage.spec.ts
import { test, expect } from '@playwright/test';
test('has title', async ({ page }) => {
await page.goto('/');
// 检查标题
await expect(page).toHaveTitle(/Next.js Boilerplate/);
// 检查欢迎消息
await expect(page.getByRole('heading', { name: /welcome/i })).toBeVisible();
});
test('navigates to about page', async ({ page }) => {
await page.goto('/');
// 点击关于链接
await page.getByRole('link', { name: /about/i }).click();
// 验证导航
await expect(page).toHaveURL(/about/);
await expect(page.getByRole('heading', { name: /about us/i })).toBeVisible();
});
- 添加测试脚本:
{
"scripts": {
"test:e2e": "playwright test",
"test:e2e:ui": "playwright test --ui",
"test:e2e:report": "playwright show-report"
}
}
七、部署与CI/CD迁移
7.1 构建流程迁移
Next.js的构建流程与Create React App有所不同:
| 特性 | Create React App | Next.js |
|---|---|---|
| 构建命令 | npm run build |
npm run build |
| 输出目录 | build/ |
.next/ |
| 静态导出 | npm run build + 配置 |
next export (仅静态站点) |
| 构建产物 | 纯静态文件 | 混合静态/动态文件,API路由等 |
| 构建分析 | 需要第三方工具 | 内置分析工具 @next/bundle-analyzer |
迁移步骤:
- 更新构建脚本:
{
"scripts": {
"build": "next build",
"build:analyze": "ANALYZE=true next build",
"start": "next start",
"export": "next export" // 仅静态站点需要
}
}
- 配置构建分析(可选):
// next.config.ts
import withBundleAnalyzer from '@next/bundle-analyzer';
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
module.exports = withBundleAnalyzer({
// 你的Next.js配置
});
7.2 CI/CD配置迁移
Next.js Boilerplate使用GitHub Actions进行CI/CD。以下是从CRA项目迁移CI/CD配置的基本步骤:
- 创建GitHub Actions配置文件:
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run lint
run: npm run lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
build:
runs-on: ubuntu-latest
needs: [lint, test]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache:.github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [ main ]
更多推荐

所有评论(0)