Next.js create-next-app:default-tw-empty 模板 README 背后的脚手架工程化机制
【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js
本文以create-next-app生成的项目 README 模板为主体,完整解读其“Getting Started / Learn More / Deploy”三段内容的由来,并结合 Next.js 仓库中模板安装逻辑的源码(packages/create-next-app/templates/index.ts),说明这份 README 是如何在脚手架流程中被拷贝、重命名并落盘的,同时还原default-tw-empty模板的完整文件结构与自动生成的package.json细节,帮助读者从零创建 Next.js 项目后,知其然亦知其所以然。
一、生成的 README:新项目的第一份上手指南
当你使用create-next-app创建一个采用Pages Router + Tailwind CSS的 JavaScript 项目时,项目根目录下会出现一份由 README-template.md 生成的README.md。它的完整内容如下(模板原文):
This is a Next.js project bootstrapped with
create-next-app.
Getting Started
启动开发服务器的标准操作:
npm run dev # or yarn dev # or pnpm dev # or bun dev随后在浏览器中打开http://localhost:3000即可查看运行结果。
接下来可以开始编辑页面:修改pages/index.js文件即可,编辑保存后页面会自动热更新(auto-updates)。
Learn More
原文档列出的学习资源对应到本仓库内,可以映射为以下文档目录,方便在源码树中直接查阅:
- Next.js 官方文档:仓库内 docs/01-app 为 App Router 文档、docs/02-pages 为 Pages Router 文档(本模板基于 Pages Router);
- 交互式教程与 GitHub 仓库:原文档指向官方 Learn Next.js 教程与 Next.js 仓库,欢迎反馈与贡献。
Deploy on Vercel
原文档推荐的最简部署方式是使用 Next.js 创作者提供的 Vercel 平台进行部署,并指向官方“部署(deploying)”文档获取进一步细节。部署文档在仓库中对应 docs/01-app 与 docs/02-pages 下的 deploying 章节(本文不输出外部链接,可在此目录中检索 “deploying” 主题文档)。
这份 README 虽然简短,但它精确概括了default-tw-empty模板项目的三个关键事实:
- 项目由
create-next-app脚手架生成,而非手写; - 采用Pages Router(入口是
pages/index.js,而不是 App Router 的app/page.tsx); - 默认端口
3000,支持 npm / yarn / pnpm / bun 四种包管理器。
二、README 的来路:模板拷贝与重命名机制
这份 README 并不是手工维护在目标项目里的,而是脚手架在初始化时从模板目录拷贝并改名而来。核心逻辑位于 templates/index.ts 的installTemplate函数:
const templatePath = path.join(__dirname, template, mode); const copySource = ["**"]; if (!eslint) copySource.push("!eslint.config.mjs"); if (!biome) copySource.push("!biome.json"); if (!tailwind || bundler === Bundler.Turbopack) { copySource.push("!postcss.config.mjs"); } await copy(copySource, root, { parents: true, cwd: templatePath, rename(name) { switch (name) { case "gitignore": { return `.${name}`; // gitignore -> .gitignore } // README.md is ignored by webpack-asset-relocator-loader used by ncc: case "README-template.md": { return "README.md"; // 模板文件改名为目标项目的 README.md } default: { return name; } } }, });从源码结构看,这里有两个值得注意的工程细节(见 templates/index.ts#L83-L97):
- 为什么叫
README-template.md而不是README.md?源码注释给出了原因:create-next-app通过 ncc 打包为单文件分发,ncc 内部的 webpack-asset-relocator-loader 会忽略(丢失)名为README.md的资源,因此模板以README-template.md命名保存,安装时再重命名为README.md; - 条件化拷贝:
copySource用 fast-glob 的否定模式按需剔除文件——未启用 ESLint 时排除eslint.config.mjs,未启用 Biome 时排除biome.json,未启用 Tailwind 或选择 Turbopack 时排除postcss.config.mjs。这意味着你拿到的模板目录是按你的选项裁剪过的,而不是无脑全量拷贝。
同理,模板中的gitignore文件会被重命名为.gitignore落盘。
三、default-tw-empty 模板全景:文件结构与默认配置
3.1 模板矩阵
仓库中create-next-app内置 8 种模板、2 种语言模式,定义见 templates/types.ts:
export type TemplateType = | "app" // App Router | "app-api" // 纯 API(Route Handlers) | "app-empty" | "app-tw" // App Router + Tailwind | "app-tw-empty" | "default" // Pages Router | "default-empty" | "default-tw" // Pages Router + Tailwind | "default-tw-empty"; // Pages Router + Tailwind,无示例内容 export type TemplateMode = "js" | "ts";本文主角default-tw-empty即Pages Router + Tailwind CSS + 极简内容的组合:相比default模板,它去掉了示例页面中的富内容,只保留一个“Hello world!”,适合希望从最干净起点出发的团队。
3.2 JavaScript 模式下的文件清单
templates/default-tw-empty/js 目录下的完整文件:
pages/_app.js、pages/_document.js、pages/index.js— Pages Router 的入口三件套;styles/globals.css— 全局样式;next.config.mjs— Next.js 配置;postcss.config.mjs— Tailwind v4 的 PostCSS 集成;jsconfig.json— JavaScript 项目的路径别名配置;eslint.config.mjs/biome.json— 按选项二选一落盘;gitignore— 安装时重命名为.gitignore;README-template.md— 安装时重命名为README.md(本文主体文档)。
3.3 关键文件内容
首页 pages/index.js:
import Head from "next/head"; export default function Home() { return ( <> <Head> <title>Create Next App</title> <meta name="description" content="Generated by create next app" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> </Head> <main> <div>Hello world!</div> </main> </> ); }这正是 README 中 “You can start editing the page by modifyingpages/index.js” 所指的文件:它通过next/head注入标题与描述,并在<main>中渲染占位内容,编辑后由开发服务器的热更新立即生效。
next.config.mjs:
/** @type {import('next').NextConfig} */ const nextConfig = { /* config options here */ reactStrictMode: true, }; export default nextConfig;默认开启reactStrictMode(React 严格模式)。注意其中的占位注释/* config options here */并非装饰:installTemplate在启用 React Compiler 或 Cache Components 时,会向该位置注入reactCompiler: true、cacheComponents: true+partialPrefetching: true等配置项(见 templates/index.ts#L139-L170);启用 Rspack 时还会把export default nextConfig;改写为export default withRspack(nextConfig);。
postcss.config.mjs 与 styles/globals.css:
const config = { plugins: { "@tailwindcss/postcss": {}, }, }; export default config;@import "tailwindcss";这里可以看到模板已升级到Tailwind CSS v4的写法:PostCSS 端使用官方@tailwindcss/postcss插件,全局样式只需一行@import "tailwindcss",不再需要 v3 时代的@tailwind base;等指令与tailwind.config.js。若选择 Turbopack 作为打包器,postcss.config.mjs会被拷贝规则排除,转而由next.config.mjs注入turbopack.rules中的@tailwindcss/turbopackloader(见 templates/index.ts#L115-L137)。
四、脚手架自动生成的 package.json
README 里npm run dev等命令能跑起来,是因为installTemplate在拷贝模板文件之后,还动态生成了目标项目的package.json(见 templates/index.ts#L281-L301):
scripts: { dev: `next dev${bundlerFlags}`, // Turbopack 时无后缀;Webpack 时为 "next dev --webpack" build: `next build${bundlerFlags}`, start: "next start", ...(eslint && { lint: "eslint" }), ...(biome && { lint: "biome check", format: "biome format --write" }), }, dependencies: { react: "19.2.8", // nextjsReactPeerVersion,与 next 的 peer 版本对齐 "react-dom": "19.2.8", next: <当前 next 版本>, }依赖版本由仓库中的常量统一管理(templates/index.ts#L19-L21 的nextjsReactPeerVersion = "19.2.8",并有注释提示sync-react脚本依赖该行,不可随意改名或格式化)。
按选项条件追加的依赖(templates/index.ts#L303-L352):
| 选项 | 追加内容 |
|---|---|
| Rspack bundler | next-rspack依赖 |
| React Compiler | devDeps 追加babel-plugin-react-compiler: 1.0.0 |
TypeScript 模式(mode === "ts") | typescript: ^5、@types/node: ^20、@types/react/@types/react-dom: ^19 |
| Tailwind | tailwindcss: ^4+@tailwindcss/postcss: ^4(Turbopack 下换成@tailwindcss/turbopack) |
| ESLint | eslint: ^9+eslint-config-next |
| Biome | @biomejs/biome: 2.4.2 |
此外,针对包管理器还有两处兼容性处理(templates/index.ts#L382-L451):
- pnpm:为 v10+ 生成
pnpm-workspace.yaml(v10 用ignoredBuiltDependencies,v11 起改用allowBuilds映射),将sharp与unrs-resolver的构建脚本默认禁用,避免安装时编译原生代码; - bun:写入
ignoreScripts与trustedDependencies字段,达到与 pnpm 等价的静默效果; - corepack 版本锁定:非 npm 的包管理器会在
package.json中写入packageManager字段(如pnpm@x.y.z),确保团队成员与 CI 使用相同的包管理器版本,规避版本差异导致的脚手架行为偏差。
安装完成后,脚手架还会尽力运行一次 typegen(生成.next/types类型文件),失败仅打印错误而不中断创建流程(“Best effort: do not fail app creation if typegen fails”,见 templates/index.ts#L472-L480)。
五、实操:从零跑通模板
以本模板对应的选项组合为例,在仓库外任意目录执行:
# 使用 Pages Router(非 app 模式)+ Tailwind,JavaScript 模式 npx create-next-app@latest my-app --no-app --tailwind --js创建流程中你会依次看到installTemplate打印的Using <packageManager>.与Initializing project with template: default-tw-empty日志(对应 templates/index.ts#L65-L70),随后自动安装依赖。完成后:
cd my-app npm run dev # 或 yarn dev / pnpm dev / bun dev打开http://localhost:3000应看到“Hello world!”页面;修改pages/index.js中的<div>内容并保存,开发服务器自动热更新。若启用过--src-dir,installTemplate会把pages/、app/、styles/(见 templates/index.ts#L43 的SRC_DIR_NAMES)整体迁入src/目录,并同步改写首页中对pages/index的文字提示。
六、小结
- README-template.md 是
create-next-app为 Pages Router + Tailwind 模板项目生成的标准 README,内容覆盖启动命令(npm/yarn/pnpm/bun)、pages/index.js编辑入口与部署指引三部分; - 它由 templates/index.ts 中的
installTemplate在初始化时拷贝并重命名落盘,命名README-template.md是为了规避 ncc 打包时资源定位器对README.md的忽略; - 该模板属于 8 模板 × js/ts 双模式矩阵中的
default-tw-empty(见 templates/types.ts),自带 Tailwind v4(@tailwindcss/postcss+ 单行@import "tailwindcss")与reactStrictMode默认配置; - 脚手架同时按选项裁剪模板文件、注入条件化依赖并生成
package.json(含 pnpm/bun 的构建脚本策略与 corepack 版本锁定),使 README 中承诺的dev命令开箱即用。
【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考