create-next-imagicma 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +42 -0
  2. package/bin/create-next-imagicma.mjs +220 -0
  3. package/package.json +19 -0
  4. package/template/.env.example +10 -0
  5. package/template/AGENTS.md +146 -0
  6. package/template/README.md +36 -0
  7. package/template/app/_components/DevPreviewShield.tsx +638 -0
  8. package/template/app/api/greeting/route.ts +27 -0
  9. package/template/app/error.tsx +93 -0
  10. package/template/app/favicon.ico +0 -0
  11. package/template/app/globals.css +145 -0
  12. package/template/app/hello/_components/HelloClient.tsx +94 -0
  13. package/template/app/hello/page.tsx +23 -0
  14. package/template/app/layout.tsx +29 -0
  15. package/template/app/page.tsx +49 -0
  16. package/template/app/providers.tsx +25 -0
  17. package/template/components/ui/accordion.tsx +58 -0
  18. package/template/components/ui/alert-dialog.tsx +141 -0
  19. package/template/components/ui/alert.tsx +61 -0
  20. package/template/components/ui/aspect-ratio.tsx +7 -0
  21. package/template/components/ui/avatar.tsx +51 -0
  22. package/template/components/ui/badge.tsx +40 -0
  23. package/template/components/ui/breadcrumb.tsx +117 -0
  24. package/template/components/ui/button.tsx +64 -0
  25. package/template/components/ui/calendar.tsx +72 -0
  26. package/template/components/ui/card.tsx +87 -0
  27. package/template/components/ui/carousel.tsx +262 -0
  28. package/template/components/ui/chart.tsx +365 -0
  29. package/template/components/ui/checkbox.tsx +30 -0
  30. package/template/components/ui/collapsible.tsx +11 -0
  31. package/template/components/ui/command.tsx +153 -0
  32. package/template/components/ui/context-menu.tsx +200 -0
  33. package/template/components/ui/dialog.tsx +122 -0
  34. package/template/components/ui/drawer.tsx +118 -0
  35. package/template/components/ui/dropdown-menu.tsx +200 -0
  36. package/template/components/ui/form.tsx +178 -0
  37. package/template/components/ui/hover-card.tsx +29 -0
  38. package/template/components/ui/input-otp.tsx +71 -0
  39. package/template/components/ui/input.tsx +25 -0
  40. package/template/components/ui/label.tsx +26 -0
  41. package/template/components/ui/menubar.tsx +256 -0
  42. package/template/components/ui/navigation-menu.tsx +130 -0
  43. package/template/components/ui/pagination.tsx +119 -0
  44. package/template/components/ui/popover.tsx +31 -0
  45. package/template/components/ui/progress.tsx +28 -0
  46. package/template/components/ui/radio-group.tsx +44 -0
  47. package/template/components/ui/resizable.tsx +45 -0
  48. package/template/components/ui/scroll-area.tsx +48 -0
  49. package/template/components/ui/select.tsx +160 -0
  50. package/template/components/ui/separator.tsx +31 -0
  51. package/template/components/ui/sheet.tsx +140 -0
  52. package/template/components/ui/sidebar.tsx +732 -0
  53. package/template/components/ui/skeleton.tsx +17 -0
  54. package/template/components/ui/slider.tsx +28 -0
  55. package/template/components/ui/switch.tsx +29 -0
  56. package/template/components/ui/table.tsx +119 -0
  57. package/template/components/ui/tabs.tsx +55 -0
  58. package/template/components/ui/textarea.tsx +24 -0
  59. package/template/components/ui/toast.tsx +129 -0
  60. package/template/components/ui/toaster.tsx +35 -0
  61. package/template/components/ui/toggle-group.tsx +61 -0
  62. package/template/components/ui/toggle.tsx +45 -0
  63. package/template/components/ui/tooltip.tsx +30 -0
  64. package/template/drizzle.config.ts +50 -0
  65. package/template/eslint.config.mjs +18 -0
  66. package/template/hooks/use-greeting.ts +15 -0
  67. package/template/hooks/use-mobile.ts +21 -0
  68. package/template/hooks/use-toast.ts +194 -0
  69. package/template/lib/queryClient.ts +59 -0
  70. package/template/lib/utils.ts +6 -0
  71. package/template/next.config.ts +8 -0
  72. package/template/package.json +81 -0
  73. package/template/pnpm-lock.yaml +6937 -0
  74. package/template/postcss.config.mjs +7 -0
  75. package/template/public/file.svg +1 -0
  76. package/template/public/globe.svg +1 -0
  77. package/template/public/next.svg +1 -0
  78. package/template/public/vercel.svg +1 -0
  79. package/template/public/window.svg +1 -0
  80. package/template/server/db.ts +24 -0
  81. package/template/server/storage.ts +41 -0
  82. package/template/shared/routes.ts +13 -0
  83. package/template/shared/schema.ts +17 -0
  84. package/template/tailwind.config.mjs +96 -0
  85. package/template/tsconfig.json +35 -0
  86. package/template/types/pg.d.ts +19 -0
package/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # create-next-imagicma
2
+
3
+ 一个极简的项目脚手架(类似 `create-next-app`),用于从本仓库模板快速生成新项目。
4
+
5
+ ## 使用
6
+
7
+ ```bash
8
+ npm install -g create-next-imagicma
9
+ create-next-imagicma <project-dir> [--port <1-65535>]
10
+ ```
11
+
12
+ 本地(未发布)使用示例:
13
+
14
+ ```bash
15
+ cd /Users/alexliu/Project/nextjs-app
16
+ node ./create-next-imagicma/bin/create-next-imagicma.mjs demo-5001 --port 5001
17
+ ```
18
+
19
+ ## 参数
20
+
21
+ - `--port <number>`:设置新项目 `dev/start` 的默认端口(写入 `next ... -p <port>`)。
22
+ - 运行时仍可覆盖,例如:`pnpm dev -- -p 6001` 或 `PORT=6001 pnpm start`
23
+
24
+ ## 依赖安装策略
25
+
26
+ - 优先使用 `pnpm install`
27
+ - 如果没有 `pnpm`,会尝试 `corepack pnpm install`
28
+ - 如果依然不可用,会自动回退到 `npm install`
29
+
30
+ ## 维护模板
31
+
32
+ 在脚手架目录执行(默认从同级的 `../nextjs-app` 同步):
33
+
34
+ ```bash
35
+ pnpm run sync-template
36
+ ```
37
+
38
+ 可通过环境变量自定义源仓库路径:
39
+
40
+ ```bash
41
+ SOURCE_REPO=/abs/path/to/source pnpm run sync-template
42
+ ```
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from "node:child_process";
3
+ import fs from "node:fs/promises";
4
+ import path from "node:path";
5
+ import process from "node:process";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+ const TEMPLATE_DIR = path.resolve(__dirname, "..", "template");
11
+
12
+ function printHelp() {
13
+ console.log(`create-next-imagicma <project-dir> [--port <1-65535>]
14
+
15
+ 参数:
16
+ --port <number> 设置新项目 dev/start 的默认端口(next ... -p)
17
+ -h, --help 显示帮助
18
+ `);
19
+ }
20
+
21
+ function parsePort(raw) {
22
+ const port = Number(raw);
23
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
24
+ throw new Error(
25
+ `--port 参数不合法:${JSON.stringify(raw)}(期望 1-65535 的整数)`,
26
+ );
27
+ }
28
+ return port;
29
+ }
30
+
31
+ function sanitizePackageName(raw) {
32
+ const normalized = raw
33
+ .toLowerCase()
34
+ .replace(/[^a-z0-9-]+/gu, "-")
35
+ .replace(/^-+|-+$/gu, "");
36
+ return normalized || "my-app";
37
+ }
38
+
39
+ function parseArgs(argv) {
40
+ let projectDir;
41
+ let port;
42
+
43
+ for (let i = 0; i < argv.length; i += 1) {
44
+ const arg = argv[i];
45
+
46
+ if (arg === "-h" || arg === "--help") {
47
+ return { help: true };
48
+ }
49
+
50
+ if (arg === "--port") {
51
+ const value = argv[i + 1];
52
+ if (!value) {
53
+ throw new Error("--port 缺少值:请使用 --port <number>");
54
+ }
55
+ port = parsePort(value);
56
+ i += 1;
57
+ continue;
58
+ }
59
+
60
+ if (arg.startsWith("--port=")) {
61
+ port = parsePort(arg.slice("--port=".length));
62
+ continue;
63
+ }
64
+
65
+ if (arg.startsWith("-")) {
66
+ throw new Error(`未知参数:${arg}`);
67
+ }
68
+
69
+ if (!projectDir) {
70
+ projectDir = arg;
71
+ continue;
72
+ }
73
+
74
+ throw new Error(`多余的参数:${arg}`);
75
+ }
76
+
77
+ if (!projectDir) {
78
+ throw new Error("缺少 <project-dir>:请指定要创建的项目目录名/路径");
79
+ }
80
+
81
+ return { projectDir, port, help: false };
82
+ }
83
+
84
+ async function ensureTargetDirEmpty(targetDir) {
85
+ try {
86
+ const stat = await fs.stat(targetDir);
87
+ if (!stat.isDirectory()) {
88
+ throw new Error(`目标路径已存在且不是目录:${targetDir}`);
89
+ }
90
+ const entries = await fs.readdir(targetDir);
91
+ if (entries.length > 0) {
92
+ throw new Error(`目标目录已存在且非空:${targetDir}`);
93
+ }
94
+ } catch (error) {
95
+ if (error && typeof error === "object" && error.code === "ENOENT") {
96
+ return;
97
+ }
98
+ throw error;
99
+ }
100
+ }
101
+
102
+ async function updatePackageName(targetDir, port) {
103
+ const pkgPath = path.join(targetDir, "package.json");
104
+ const raw = await fs.readFile(pkgPath, "utf8");
105
+ const pkg = JSON.parse(raw);
106
+ const devScript = port === undefined ? "next dev" : `next dev -p ${port}`;
107
+ const startScript =
108
+ port === undefined ? "next start" : `next start -p ${port}`;
109
+
110
+ pkg.name = sanitizePackageName(path.basename(targetDir));
111
+ pkg.scripts = {
112
+ ...(pkg.scripts ?? {}),
113
+ dev: devScript,
114
+ start: startScript,
115
+ };
116
+ await fs.writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
117
+ }
118
+
119
+ function runCommand(command, args, options) {
120
+ return new Promise((resolve, reject) => {
121
+ const child = spawn(command, args, { stdio: "inherit", ...options });
122
+ child.on("error", reject);
123
+ child.on("close", (code) => resolve(code ?? 0));
124
+ });
125
+ }
126
+
127
+ function isCommandMissingError(error) {
128
+ return (
129
+ !!error &&
130
+ typeof error === "object" &&
131
+ "code" in error &&
132
+ error.code === "ENOENT"
133
+ );
134
+ }
135
+
136
+ async function installDependencies(targetDir) {
137
+ console.log("\n正在安装依赖(优先 pnpm)...\n");
138
+
139
+ try {
140
+ const pnpmCode = await runCommand("pnpm", ["install"], { cwd: targetDir });
141
+ if (pnpmCode === 0) return { ok: true, installer: "pnpm" };
142
+ return { ok: false, installer: "pnpm" };
143
+ } catch (error) {
144
+ if (!isCommandMissingError(error)) {
145
+ throw error;
146
+ }
147
+ }
148
+
149
+ console.log("未检测到全局 pnpm,尝试使用 corepack 调用 pnpm...\n");
150
+ try {
151
+ const corepackCode = await runCommand("corepack", ["pnpm", "install"], {
152
+ cwd: targetDir,
153
+ });
154
+ if (corepackCode === 0) return { ok: true, installer: "pnpm" };
155
+ } catch (error) {
156
+ if (!isCommandMissingError(error)) throw error;
157
+ }
158
+
159
+ console.log("将使用 npm 安装依赖。\n");
160
+
161
+ try {
162
+ const npmCode = await runCommand("npm", ["install"], { cwd: targetDir });
163
+ if (npmCode === 0) return { ok: true, installer: "npm" };
164
+ return { ok: false, installer: "npm" };
165
+ } catch (error) {
166
+ if (isCommandMissingError(error)) {
167
+ console.error("未检测到 npm,请先安装 Node.js/npm。");
168
+ return { ok: false, installer: null };
169
+ }
170
+ throw error;
171
+ }
172
+ }
173
+
174
+ async function main() {
175
+ const parsed = parseArgs(process.argv.slice(2));
176
+ if (parsed.help) {
177
+ printHelp();
178
+ return;
179
+ }
180
+
181
+ const { projectDir, port } = parsed;
182
+ const targetDir = path.resolve(process.cwd(), projectDir);
183
+
184
+ await ensureTargetDirEmpty(targetDir);
185
+ await fs.mkdir(targetDir, { recursive: true });
186
+
187
+ await fs.cp(TEMPLATE_DIR, targetDir, { recursive: true });
188
+ await updatePackageName(targetDir, port);
189
+
190
+ const installResult = await installDependencies(targetDir);
191
+ if (!installResult.ok) {
192
+ console.error("\n依赖安装失败(不会回滚已生成的项目)。你可以稍后手动重试:");
193
+ console.error(` cd ${projectDir}`);
194
+ console.error(" pnpm install");
195
+ console.error(" npm install\n");
196
+ console.error("若你当前环境存在代理导致安装失败,可尝试清空代理环境变量后重试:");
197
+ console.error(" HTTP_PROXY= HTTPS_PROXY= pnpm install");
198
+ console.error(" HTTP_PROXY= HTTPS_PROXY= npm install\n");
199
+ process.exitCode = 1;
200
+ return;
201
+ }
202
+
203
+ console.log(`\n✅ 项目已创建:${targetDir}`);
204
+ if (port !== undefined) {
205
+ console.log(`已设置默认端口:${port}(写入 dev/start 启动命令)`);
206
+ }
207
+ console.log("\n下一步:");
208
+ console.log(` cd ${projectDir}`);
209
+ if (installResult.installer === "npm") {
210
+ console.log(" npm run dev\n");
211
+ } else {
212
+ console.log(" pnpm dev\n");
213
+ }
214
+ }
215
+
216
+ main().catch((error) => {
217
+ const message = error instanceof Error ? error.message : String(error);
218
+ console.error(`\n错误:${message}`);
219
+ process.exitCode = 1;
220
+ });
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "create-next-imagicma",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "bin": {
6
+ "create-next-imagicma": "./bin/create-next-imagicma.mjs"
7
+ },
8
+ "files": [
9
+ "bin/**",
10
+ "template/**",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "sync-template": "node ./scripts/sync-template.mjs"
15
+ },
16
+ "engines": {
17
+ "node": ">=18.17.0"
18
+ }
19
+ }
@@ -0,0 +1,10 @@
1
+ # 复制为 .env.local 并填入真实值(.env.local 不会被提交)
2
+ #
3
+ # Postgres 连接串(Drizzle + pg 使用)
4
+ # 示例:
5
+ # DATABASE_URL="postgres://user:pass@localhost:5432/mydb"
6
+ DATABASE_URL=""
7
+
8
+ # 可选:运行端口(某些平台/容器会要求读取 PORT,例如 Replit 默认 5000)
9
+ # PORT=5000
10
+
@@ -0,0 +1,146 @@
1
+ # 项目 Agent 指南(Next.js + Tailwind v4 + shadcn/ui + React Query + Drizzle)
2
+
3
+ 本文档用于指导(人类或 AI)在本仓库中进行一致、可维护的开发与迁移工作。**默认使用中文沟通与输出**(除非用户明确要求其他语言)。
4
+
5
+ ## 1) 技术栈与约束
6
+
7
+ - **框架**:Next.js(App Router,目录为 `app/`)
8
+ - **语言**:TypeScript(`strict: true`,`noEmit: true`)
9
+ - **UI**:Tailwind CSS v4 + shadcn/ui(Radix UI 组件为基础)
10
+ - **主题**:`next-themes`,采用 `darkMode: ["class"]`
11
+ - **请求层**:`@tanstack/react-query` + `fetch` 封装
12
+ - **契约**:`zod`(对 API 返回做 schema 校验)
13
+ - **数据库**:Postgres + Drizzle ORM(`pg` + `drizzle-orm` + `drizzle-kit`)
14
+
15
+ ### 运行环境提示(重要)
16
+ - `DATABASE_URL` 必须通过环境变量提供(建议放在 `.env.local`,不要提交到 Git)。
17
+ - `server/*` 代码属于 **Node.js runtime**(依赖 `pg`),Next route handlers 需要 `export const runtime = "nodejs"`。
18
+
19
+ ## 2) 目录结构约定
20
+
21
+ - `app/`
22
+ - Next.js 路由与页面(Server Component 默认)
23
+ - `app/providers.tsx`:全局 Provider(Theme + React Query + Tooltip + Toaster)
24
+ - `app/api/*`:Route Handlers(替代传统 Express)
25
+ - `components/ui/`
26
+ - 从模板迁移的 shadcn/ui 组件(**统一为 Client Components**)
27
+ - 规则:文件顶部保持 `"use client";`,避免 RSC 边界问题
28
+ - `hooks/`
29
+ - 可复用 hooks(例如 toast、mobile、请求 hook)
30
+ - 规则:一般也视为客户端使用,文件顶部带 `"use client";`
31
+ - `lib/`
32
+ - 工具与客户端通用封装(例如 `lib/utils.ts` 的 `cn()`、`lib/queryClient.ts`)
33
+ - `shared/`
34
+ - 共享契约与 schema(例如 `shared/routes.ts`、`shared/schema.ts`)
35
+ - 这些文件应当 **不依赖 Next/React**,以便在 client/server 两端共同使用
36
+ - `server/`
37
+ - 服务端基础设施(例如 `server/db.ts`、`server/storage.ts`)
38
+ - 必须 `import "server-only";`,避免被客户端错误引用
39
+ - `types/`
40
+ - 本地类型补丁(当网络/依赖限制导致无法安装 `@types/*` 时使用)
41
+
42
+ ## 3) 常用命令(pnpm)
43
+
44
+ 本项目**仅允许使用 pnpm** 安装依赖(见 `package.json` 的 `packageManager` / `engines` / `preinstall`)。
45
+
46
+ 以仓库根目录为工作目录:
47
+
48
+ - 开发:`pnpm dev`
49
+ - 构建:`pnpm build`(当前脚本使用 `next build --webpack`,避免 Turbopack 在部分受限环境下失败)
50
+ - Lint:`pnpm lint`
51
+ - 类型检查:`pnpm check`
52
+ - DB 同步:`pnpm db:push`
53
+
54
+ > 若安装依赖出现网络/代理问题,可临时在命令前清空代理环境变量:
55
+ > `HTTP_PROXY= HTTPS_PROXY= pnpm install`
56
+
57
+ ## 4) 环境变量与数据库
58
+
59
+ ### 必需环境变量
60
+ - `DATABASE_URL`:Postgres 连接串(例:`postgres://user:pass@host:5432/dbname`)
61
+
62
+ ### Drizzle
63
+ - 配置:`drizzle.config.ts`
64
+ - Schema:`shared/schema.ts`
65
+ - 迁移输出目录(默认):`migrations/`
66
+
67
+ **开发流程建议**
68
+ 1. 配置 `.env.local` 的 `DATABASE_URL`
69
+ 2. 执行 `pnpm db:push` 初始化/同步表结构
70
+ 3. 启动 `pnpm dev`
71
+
72
+ ## 5) UI / Tailwind / 主题
73
+
74
+ ### Tailwind v4
75
+ - 全局样式:`app/globals.css`(包含 shadcn 常用 CSS 变量)
76
+ - Tailwind 配置:`tailwind.config.mjs`(通过 `app/globals.css` 顶部的 `@config` 指令加载)
77
+
78
+ ### 主题(dark mode)
79
+ - 通过 `next-themes` 在 `<html class="dark">` 上切换
80
+ - `app/layout.tsx` 中应包含 `suppressHydrationWarning` 以减少 hydration 警告
81
+
82
+ ### shadcn/ui 迁移注意事项
83
+ - `components/ui/*` 大量依赖 Tailwind 主题 token(如 `bg-background`、`text-foreground` 等)
84
+ - 这些 token 由 `tailwind.config.mjs` 的颜色映射 + `app/globals.css` 的 CSS 变量共同提供
85
+ - 若新增组件:优先保持与现有 `components/ui` 同风格(使用 `cn()`、Radix、`cva()`)
86
+
87
+ ## 6) 请求层(React Query)
88
+
89
+ - QueryClient 构建:`lib/queryClient.ts` 导出 `makeQueryClient()`
90
+ - 全局挂载:`app/providers.tsx` 使用 `useState(() => makeQueryClient())`,避免跨请求共享单例
91
+ - 推荐模式:
92
+ - 将 API 路径与响应 schema 放在 `shared/routes.ts`
93
+ - 客户端 hook(例如 `hooks/use-greeting.ts`)中调用 `fetch` 并用 Zod parse 校验返回
94
+
95
+ ## 7) API 设计与契约(shared/routes)
96
+
97
+ - `shared/routes.ts` 是“唯一真相”(path/method/response schema)
98
+ - Route Handler(`app/api/**/route.ts`)建议:
99
+ 1. 调用 server 层(`server/*`)获取数据
100
+ 2. `api.xxx.responses[200].parse(body)` 校验输出
101
+ 3. `NextResponse.json(body)`
102
+
103
+ ## 8) 代码质量与规则
104
+
105
+ - TypeScript:保持 `strict`,不使用 `any`(如因外部依赖类型缺失,优先在 `types/` 提供最小可用声明)
106
+ - React:遵守 “components/hooks must be pure” 的 lint 规则(避免在 render 中调用 `Math.random()`、`Date.now()` 等)
107
+ - Server-only:凡是 DB/私密逻辑一律放 `server/`,并显式 `import "server-only"`
108
+ - 不提交敏感信息:不要提交 `.env.local`、密钥、数据库连接串
109
+
110
+ ## 9) Git/分支约定(可选)
111
+
112
+ - 若需要新建分支,建议使用前缀:`codex/xxx`
113
+
114
+ ## 10) 给 AI/自动化的“无交互启动”清单
115
+
116
+ 当启动者不是开发者(例如 AI Agent、CI Runner、平台工作流)时,推荐按以下顺序执行:
117
+
118
+ 1) 安装依赖
119
+ - `pnpm install`(有 `pnpm-lock.yaml` 时优先)
120
+ 2) 准备环境变量(至少要有 `DATABASE_URL`)
121
+ - 方式 A:平台/Runner 注入 `DATABASE_URL`
122
+ - 方式 B:在仓库根目录写入 `.env.local`(不要提交)
123
+ 3) 初始化数据库结构(只需首次或 schema 变更后)
124
+ - `pnpm db:push`
125
+ 4) 启动
126
+ - 开发:`pnpm dev`
127
+ - 生产:`pnpm build` 然后 `pnpm start`
128
+
129
+ > 说明:`drizzle.config.ts` 会尝试读取 `.env.local` / `.env` 来获取 `DATABASE_URL`,避免自动化环境仅写文件但未显式 `export` 导致 CLI 取不到。
130
+
131
+ ## 11) 迁移验证入口
132
+
133
+ - API:`GET /api/greeting`(文件:`app/api/greeting/route.ts`)
134
+ - Demo 页面:`/hello`(文件:`app/hello/page.tsx`)
135
+
136
+ ## 12) 常见问题排障
137
+
138
+ - `DATABASE_URL 未设置`
139
+ - 确认 `.env.local` 里有 **未注释** 的 `DATABASE_URL="..."`,或 Runner 里已注入环境变量
140
+ - `关系 "messages" 不存在` / `table does not exist`
141
+ - 先执行 `pnpm db:push`
142
+ - UI 样式不生效 / 主题色不对
143
+ - 确认 `app/globals.css` 顶部包含 `@config "../tailwind.config.mjs";`
144
+ - 确认 `tailwind.config.mjs` 的 `content` 覆盖到了 `components/ui` 等目录
145
+ - 构建报 Turbopack/受限环境问题
146
+ - 当前 `pnpm build` 已固定使用 `next build --webpack`(见 `package.json`)
@@ -0,0 +1,36 @@
1
+ This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
2
+
3
+ ## Getting Started
4
+
5
+ First, run the development server:
6
+
7
+ ```bash
8
+ npm run dev
9
+ # or
10
+ yarn dev
11
+ # or
12
+ pnpm dev
13
+ # or
14
+ bun dev
15
+ ```
16
+
17
+ Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18
+
19
+ You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20
+
21
+ This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
22
+
23
+ ## Learn More
24
+
25
+ To learn more about Next.js, take a look at the following resources:
26
+
27
+ - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28
+ - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29
+
30
+ You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
31
+
32
+ ## Deploy on Vercel
33
+
34
+ The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35
+
36
+ Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.