
next.js 是一个基于 React 的轻量化服务端渲染框架,它提供了一些开箱即用的特性,如基于文件系统的路由器、自动代码分割、静态文件服务、CSS 模块化、服务端渲染、热模块替换等,使得开发者可以快速高效构建 React 应用程序
特点
Next.js 14 对 Node.js 版本要求 18.17 以上
# 自动安装
npx create-next-app@latest
# 已创建项目手动安装
npm install next@latest react@latest react-dom@latest使用 TypeScript 模板来创建一个默认的 Next.js 应用
npx create-next-app@latest
What is your project named? ... next-project
Would you like to use TypeScript? ... No / Yes
Would you like to use ESLint? ... No / Yes
Would you like to use Tailwind CSS? ... No / Yes
Would you like to use `src/` directory? ... No / Yes
Would you like to use App Router? (recommended) ... No / Yes
Would you like to customize the default import alias (@/*)? ... No / Yes
What import alias would you like configured? ... @/*
Creating a new Next.js app in D:\study\react\next-project.src/ directory 默认是 app 路径(前端一般较多使用 src 目录,这个选 NO 会生成 src/app 路径)命令执行完成后,运行项目
npm run dev打开 http://localhost:3000 成功运行

Git 提交信息需要遵循 Angular 约定是为了使提交信息格式清晰、易于阅读和理解,从而提高代码协作的效率
"husky"是一个为了方便使用Git hooks的工具,它能够帮助你在项目中自动化地执行一些Git相关的操作。使用husky,你可以在Git的一些关键操作(例如提交、推送、合并等)前或后,执行一些脚本或命令,比如代码格式化、自动化测试、打包发布等
他可以帮助我们额外拦截一些如git commit等指令。需要注意的是,husky只在Git仓库中才能正常工作,所以在使用之前请确保你的项目已经初始化为Git仓库
npm install husky --save-devpackage.json 中新增 husky 配置
{
"scripts": {
"prepare": "husky install"
},
"husky": {
"hooks": {
"pre-commit": "npm run lint && npm run test"
}
}
}执行 husky install
# prepare在npm install的时候会自动自行
npm run prepare
# 或者
npx husky install执行完这个命令后,工程目录中会生成.husky 目录,存储 hooks
创建一个 hook
# 脚本创建 9.0版本add废弃了(会提示 add command is deprecated),可以手动创建或者脚本创建
npx husky add .husky/pre-commit "npm run lint"
# 脚本创建2
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg手动创建 .husky 目录下创建 pre-commit 和 commit-msg
# pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo "husky pre-commit" && npx lint-staged
# commit-msg
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo "husky commit-msg" && npx --no-install commitlint --edit $1配置完成后 git commit 的时候就会对相关文件执行 lint-staged 和 message 校验的工作了
git commit执行之后会报错是因为我们还没配置commitlint (Please add rules to your commitlint.config.js)下面我们就开始配置
对自动生成 commit 信息的校验
npm install @commitlint/config-conventional @commitlint/cli --save-dev更目录创建 commitlint.config.js 文件,配置 commitlint
module.exports = {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [
2,
"always",
[
"build",
"feat",
"fix",
"docs",
"style",
"refactor",
"test",
"chore",
"revert"
]
],
"subject-full-stop": [0, "never"],
"subject-case": [0, "never"]
}
};再次执行git commit,只要commit信息符合 commitlint.config.js 配置,就能成功
全局安装 commitizen
npm install -g commitizen
npm install -g cz-conventional-changelog随后你就可以使用以下命令获得中规中距的 commit 信息了。
git cz安装 cz-customizable
pnpm install cz-customizable --save-dev添加以下配置到 package.json 中
{
"config": {
"commitizen": {
"path": "node_modules/cz-customizable"
}
}
}项目根目录下创建.cz-config.js 文件来自定义提示(默认是.cz-config.js 文件,如果想对.cz-config.js 文件进行重命名则使用 cz-customizable 配置)
module.exports = {
// type 类型(定义之后,可通过上下键选择)
types: [
{ value: "feat", name: "✨ feat: 新增功能" },
{ value: "fix", name: "🐛 fix: 修复 bug" },
{ value: "docs", name: "📝 docs: 文档变更" },
{
value: "style",
name: "💄 style: 代码格式(不影响功能,例如空格、分号等格式修正)"
},
{
value: "refactor",
name: "♻️ refactor: 代码重构(不包括 bug 修复、功能新增)"
},
{ value: "perf", name: "⚡️ perf: 性能优化" },
{ value: "test", name: "✅ test: 添加、修改测试用例" },
{
value: "build",
name:
"🚀 build: 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)"
},
{ value: "ci", name: "ci: 修改 CI 配置、脚本" },
{
value: "chore",
name:
"🔧 chore: 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)"
},
{ value: "revert", name: "⏪ revert: 回滚 commit" }
],
// scope 类型(定义之后,可通过上下键选择)
scopes: [
["docs", "文档相关"],
["components", "组件相关"],
["hooks", "hook 相关"],
["utils", "utils 相关"],
["element-ui", "对 element-ui 的调整"],
["styles", "样式相关"],
["deps", "项目依赖"],
["auth", "对 auth 修改"],
["other", "其他修改"],
// 如果选择 custom,后面会让你再输入一个自定义的 scope。也可以不设置此项,把后面的 allowCustomScopes 设置为 true
["custom", "以上都不是?我要自定义"]
].map(([value, description]) => {
return {
value,
name: `${value.padEnd(30)} (${description})`
};
}),
// 是否允许自定义填写 scope,在 scope 选择的时候,会有 empty 和 custom 可以选择。
// allowCustomScopes: true,
// allowTicketNumber: false,
// isTicketNumberRequired: false,
// ticketNumberPrefix: 'TICKET-',
// ticketNumberRegExp: '\\d{1,5}',
// 针对每一个 type 去定义对应的 scopes,例如 fix
/*
scopeOverrides: {
fix: [
{ name: 'merge' },
{ name: 'style' },
{ name: 'e2eTest' },
{ name: 'unitTest' }
]
},
*/
// 交互提示信息
messages: {
type: "选择你要提交的类型:",
scope: "\n选择一个 scope(可选):",
// 选择 scope: custom 时会出下面的提示
customScope: "请输入自定义的 scope:",
subject: "填写简短精炼的变更描述:\n",
body: '填写更加详细的变更描述(可选)。使用 "|" 换行:\n',
breaking: "列举非兼容性重大的变更(可选):\n",
footer: "列举出所有变更的 ISSUES CLOSED(可选)。 例如: #31, #34:\n",
confirmCommit: "确认提交?"
},
// 设置只有 type 选择了 feat 或 fix,才询问 breaking message
allowBreakingChanges: ["feat", "fix"],
// 跳过要询问的步骤
// skipQuestions: ['body', 'footer'],
// subject 限制长度
subjectLimit: 100,
breaklineChar: "|" // 支持 body 和 footer
// footerPrefix : 'ISSUES CLOSED:'
// askForBreakingChangeFirst : true,
};此时再次运行 git cz 时就可以看到
? 请选择提交的类型: (Use arrow keys)
❯ ✨ feat: 新增功能
🐛 fix: 修复 bug
📝 docs: 文档变更
💄 style: 样式格式(不影响代码运行的变动)
♻️ refactor: 重构 (既不增加feature, 也不是修复bug)
⚡️ perf: 性能优化
✅ test: 增加测试使用lint-staged, 对暂存区代码进行eslint校验和prettier格式化
npm install lint-staged --save-dev在 package.json 中配置 lint-staged 配置表明在运行 lint-staged 的时候将只匹配 src 和 test 目录下的 ts 和 tsx 文件
{
"lint-staged": {
"src/*.{js,jsx,mjs,ts,tsx}": [
"node_modules/.bin/prettier --write",
"eslint --config .eslintrc.js"
],
"src/*.{css,scss,less,json,html,md,markdown}": [
"node_modules/.bin/prettier --write",
"git add"
]
}
}这样,每次在执行 git commit 命令时,都会自动执行 npx lint-staged(package.json 中配置的 lint-staged)
根目录下新增 .vscode 文件夹,创建 settings.json 文件,该文件是一个覆盖已安装 vscode 的默认设置值,该文件配置仅对当前项目生效
具体配置说明可以点左下角设置按钮,找到设置菜单,打开后可以查看自己 vscode 的各项设置
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "explicit"
},
"editor.tabSize": 2
}在 .vscode 目录下创建 launch.json 文件
{
"version": "0.1.0",
"configurations": [
{
"name": "Next.js: debug server-side",
"type": "node-terminal",
"request": "launch",
"command": "npm run dev"
},
{
"name": "Next.js: debug client-side",
"type": "chrome",
"request": "launch",
"url": "<http://localhost:3000>"
},
{
"name": "Next.js: debug full stack",
"type": "node-terminal",
"request": "launch",
"command": "npm run dev",
"serverReadyAction": {
"pattern": "started server on .+, url: (https?://.+)",
"uriFormat": "%s",
"action": "debugWithChrome"
}
}
]
}在初始化 next14 版本的项目时,会有个选项询问是否喜欢 src 目录结构,nextjs 默认是不会生成 src 目录结构的,因此如果喜欢 src 风格的目录结构,这个选项要注意一下
# 是否生成src的目录结构
Would you like to use `src/` directory? ... No / Yes我默认生成的是 src 风格的目录
/app 默认生成的 app 路径
/app/pages 路由页面
/utils 工具类脚本
/components 组成应用程序的各个 UI 组件将位于此处代码规范推荐使用创建项目时的 eslint 支持
# 这个选项选YES,自动生成eslint配置和安装对应的依赖包
Would you like to use ESLint? ... No / Yes自动格式化我们安装 prettier 插件实现
npm install prettier --save-dev根目录添加两个文件,.prettierrc 和.prettierignore
.prettierrc 项目的 prettier 配置(配置什么完全取决于自己团队或自己的代码风格)
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"singleQuote": true
}.prettierignore 忽略代码格式化的文件或文件夹
.yarn
.next
dist
node_modules自动化 prettier,在 package.json 中新增 script 脚本
{
"scripts: {
...
"prettier": "prettier --write ."
}
}以上配置好之后可以试着执行
npm run prettier看下自己配置的格式化有没有生效
依赖包 fs-extra mustache log-symbols inquirer 等依赖
注意:如果出现 Error [ERR_REQUIRE_ESM]: require() of ES Module not supported 说明是某个包不支持 require,就需要看对应的包哪个版本支持 require,我这边碰到两个包最新版本不支持 require,因此我选择了低版本(inquirer@7.1.0, log-symbols@4.0.0)
npm i fs-extra mustache log-symbols inquirer --save-dev根目录创建 bin 文件夹,存放创建模板等脚本
bin 文件夹下创建 new/index.js 用于生成模板文件
const rimraf = require("rimraf");
const inquirer = require("inquirer");
const fs = require("fs-extra");
const path = require("path");
const Mustache = require("mustache");
const createModuleFiles = (moduleName, moduleType, moduleDesc) => {
const outputName =
moduleName[0].toLowerCase() + moduleName.slice(1, moduleName.length);
const templates = [
{
template: "moduleComponentTsx.tpl",
output: `app/components/${moduleName}/${moduleName}.tsx`
},
{
template: "moduleComponentStyle.tpl",
output: `app/components/${moduleName}/${moduleName}.module.css`
}
];
try {
let tpl, output;
templates.forEach(temp => {
tpl = fs.readFileSync(
path.resolve(__dirname, `./templates/component/${temp.template}`),
"utf8"
);
output = Mustache.render(tpl, { moduleName, outputName, moduleDesc });
fs.outputFileSync(path.resolve(process.cwd(), temp.output), output);
});
console.log("模块文件创建完成");
} catch (error) {
console.error(error);
}
};
class NewModule {
constructor() {
this.createModule();
}
async createModule() {
// 模块类型
const moduleType = await this.inputType();
// 模块名
const moduleName = await this.inputName();
// 模块描述
const moduleDesc = await this.inputDesc();
// 清除重名文件
await this.clearFile(moduleName, moduleType);
createModuleFiles(moduleName, moduleType, moduleDesc);
}
async inputType() {
const { moduleType } = await inquirer.prompt([
{
name: "moduleType",
message: "请选择创建类型",
type: "list",
choices: [
{
name: "UI组件",
value: "component"
},
{
name: "页面",
value: "page"
}
],
default: "component"
}
]);
return moduleType;
}
async inputName() {
const { moduleName } = await inquirer.prompt([
{
name: "moduleName",
message: "请输入模块名称",
type: "input"
}
]);
return moduleName;
}
async inputDesc() {
const { moduleDesc } = await inquirer.prompt([
{
name: "moduleDesc",
message: "请输入模块描述",
type: "input"
}
]);
return moduleDesc;
}
async clearFile(moduleName, moduleType) {
if (moduleType === "page") {
rimraf.rimraf(
path.resolve(process.cwd(), "app/component", `${moduleName}.module.css`)
);
rimraf.rimraf(
path.resolve(process.cwd(), "app/app", `${moduleName}.tsx`)
);
} else if (moduleType === "component") {
}
}
}
new NewModule();new 文件夹下创建 templates 目录,用于存放模板文件,创建 moduleComponentTsx.tpl 文件,存放下面代码 双花括号里的都是变量,通过传参读取对应的值
// {{moduleDesc}}
import styles from './{{outputName}}.module.css';
export interface I{{outputName}} {
sampleTextProp: string;
}
const {{outputName}}: React.FC<I{{outputName}}> = ({sampleTextProp}) => {
return (
<div className={styles.{{outputName}}}>
{ sampleTextProp }
</div>
)
}
export default {{outputName}};
pages 的逻辑类似,模板自己重新定义
在 package.json 创建对应的创建脚本
{
"scripts: {
...
"create": "node bin/new"
}
}运行命令
npm run create可以到自己设置的目录查看是否创建成功
效果
