Date: January 29, 2025
项目创建
思路:
- 使用 Create-React-App 创建 React 项目
- 使用 Vite 创建 React 项目
- 使用 eslint prettier husty 等,制定编码规则
创建项目
注:在这之前,推荐 node 版本:
node/18.20.6
,否则会遇到各种兼容性bug
jsx
## 使用 npx
npx create-react-app my-app --template typescript
## 使用 npm
npm init react-app my-app --template typescript
**项目结构:**项目入口 src/App.js
启动项目:npm start
📒 笔记:
npm 和 npx 的区别:
npm
更侧重于包的管理和维护。npx
则专注于命令行工具的即时执行和跨项目的一次性操作。
npm | npx | |
---|---|---|
用途 | 管理和安装包 | 临时执行包 |
是否需要安装 | 需要先 npm install |
不需要安装,直接运行 |
作用范围 | 主要用于项目依赖 | 主要用于 CLI 工具 |
示例 | npm install -g eslint eslint . |
npx eslint . (无需全局安装) |
问题修复
文件系统操作冲突
问题快照:
问题分析:
这个错误信息表明在使用 npx
和 create-react-app
创建新的 React 应用时,出现了由于文件系统操作(特别是重命名)导致的权限或存在冲突的问题。具体而言,npm 在尝试重命名缓存目录中的某个文件时遇到了文件已经存在的问题。同时,还涉及到权限不足的情况。
错误码和系统调用:
npm ERR! code EEXIST
:表示在进行文件操作时,目标路径已经存在同名文件。这通常出现在尝试创建、移动或重命名一个文件到一个已经存在的文件路径时。npm ERR! syscall rename
:指出失败的系统调用是rename
,即在尝试重命名一个文件路径的时候发生错误。
解决方案:
- 清理 npm 缓存:
使用 npm cache clean --force
来强制清理 npm 缓存。这可以解决由缓存文件损坏引起的问题。
bash
npm cache clean --force
- 检查并修复权限问题:
-
确保您具有对
.npm
目录的正确权限。有时候因为之前的安装操作以root
用户执行导致现在的用户权限不足。 -
使用以下命令更改
.npm
目录的所有权:bashsudo chown -R $(whoami) ~/.npm
-
如果您在全局安装包时遇到权限问题,可以考虑使用 nvm(Node Version Manager)来管理 Node.js 和 npm,以避免使用 sudo。
- 删除冲突文件:
- 手动删除错误信息中提到的具体路径上的冲突文件:
bash
rm -rf /Users/nathanchen/.npm/_cacache/content-v2/sha512/30/8b/3c91d31ffce7e8ab92600bb41d5442612d23c9ac1ad212415b7d768686fe6cc3a56ae156e64fa442b6f60b1be83eb0c02eb87bbaaf76e4a44351555f
- 使用
-force
参数重新运行命令:
-
使用
-force
参数来强制覆盖现有文件,不过这需要谨慎,因为它可能会覆盖掉重要文件。 -
修改命令如下:
bashnpx create-react-app my-app --template typescript --force
- 确保 npm 和 Node.js 是最新的:
-
更新 npm 到最新版本,这样能避免已知的旧版本问题:
bashnpm install -g npm@latest
-
确保 Node.js 也是最新稳定版,可以从官方网站下载更新版本。
- 查看详细日志:
- 查看完整的日志文件
/Users/nathanchen/.npm/_logs/2025-01-30T05_48_04_261Z-debug-0.log
,以获取更多信息和上下文,帮助诊断特定问题。
这里我采用 清理 npm 缓存 成功解决问题,从而项目可以正常创建
jsx
nathanchen@192 wenjuan-nathan % sudo npm cache clean --force
Password:
npm WARN using --force Recommended protections disabled.
注:记得采用 sudo 来获取权限创建
OpenSSL加密算法不兼容
问题快照:
jsx
Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:68:19)
at Object.createHash (node:crypto:138:10)
at module.exports (/Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/webpack/lib/util/createHash.js:90:53)
at NormalModule._initBuildHash (/Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/webpack/lib/NormalModule.js:401:16)
at handleParseError (/Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/webpack/lib/NormalModule.js:449:10)
at /Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/webpack/lib/NormalModule.js:481:5
at /Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/webpack/lib/NormalModule.js:342:12
at /Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/loader-runner/lib/LoaderRunner.js:373:3
at iterateNormalLoaders (/Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/loader-runner/lib/LoaderRunner.js:214:10)
at iterateNormalLoaders (/Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/loader-runner/lib/LoaderRunner.js:221:10)
at /Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/loader-runner/lib/LoaderRunner.js:236:3
at runSyncOrAsync (/Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/loader-runner/lib/LoaderRunner.js:130:11)
at iterateNormalLoaders (/Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/loader-runner/lib/LoaderRunner.js:232:2)
at Array.<anonymous> (/Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/loader-runner/lib/LoaderRunner.js:205:4)
at Storage.finished (/Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:55:16)
at /Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:91:9
/Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/react-scripts/scripts/start.js:19
throw err;
^
Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:68:19)
at Object.createHash (node:crypto:138:10)
at module.exports (/Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/webpack/lib/util/createHash.js:90:53)
at NormalModule._initBuildHash (/Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/webpack/lib/NormalModule.js:401:16)
at /Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/webpack/lib/NormalModule.js:433:10
at /Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/webpack/lib/NormalModule.js:308:13
at /Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/loader-runner/lib/LoaderRunner.js:367:11
at /Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/loader-runner/lib/LoaderRunner.js:233:18
at context.callback (/Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/loader-runner/lib/LoaderRunner.js:111:13)
at /Users/nathanchen/Documents/1Front-End/前端开发/Projects/wenjuan/源码/wenjuan-nathan/my-app/node_modules/babel-loader/lib/index.js:51:103 {
opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
library: 'digital envelope routines',
reason: 'unsupported',
code: 'ERR_OSSL_EVP_UNSUPPORTED'
}
Node.js v21.4.0
问题分析:
- 错误代码和信息 :
- 错误信息
Error: error:0308010C:digital envelope routines::unsupported
以及ERR_OSSL_EVP_UNSUPPORTED
指向了 OpenSSL 的加密相关功能。 digital envelope routines
是 OpenSSL 中用于加密和解密操作的一部分,表明问题与加密算法相关。
- 错误信息
- Node.js 系统内部调用 :
- 错误栈中的
at new Hash (node:internal/crypto/hash:68:19)
和at Object.createHash (node:crypto:138:10)
显示了错误发生在 Node.js 自身的加密模块中,这是一个明确的信号,指出问题与加密哈希创建有关。
- 错误栈中的
- OpenSSL 相关的错误信息 :
opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ]
提供了进一步的证据,指出这个问题是由于加密库初始化失败引起的。
解决方案:
-
降级 Node.js 版本:
-
使用
nvm
(Node Version Manager)切换到稍微旧一点的 Node.js 版本,比如 16.x 或 14.x。 -
例如:
bashnvm install 16 nvm use 16
-
-
设置环境变量以禁用 OpenSSL 3.0 的严格模式:
-
可以通过在运行命令前设置环境变量来临时规避该问题。
-
在终端中执行以下命令:
bashexport NODE_OPTIONS=--openssl-legacy-provider npm start
-
或者将其添加到你的项目的
package.json
的scripts
中:json"scripts": { "start": "export NODE_OPTIONS=--openssl-legacy-provider && react-scripts start" }
-
-
确保所有依赖项是最新的:
-
更新所有与项目相关的包,因为较新的版本可能已经修复了与 OpenSSL 3.0 不兼容的问题。
-
运行以下命令更新:
bashnpm update
-
-
检查特定于 Webpack 的问题:
- 有时候,特定版本的 Webpack 对某些配置或插件的支持可能不完整,查看 Webpack 和相关插件的文档,确认是否有已知问题和修复。
这里我采用降级 Node 版本来解决,采用 node/16.19.0
版本
编码规范
高质量代码特点:
- 严格编码规范(靠工具、流程,而非自觉)
- 合理、规范的注释
- 代码合理拆分
采用工具:
- eslint- 检查语法语义,如变量未定义、定义未使用
- prettier - 检查编码风格,如每一行末尾是否加分号
eslint
安装插件:
bash
npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin -save-dev
初始化配置文件 .eslint.js
bash
npx eslint --init
配置清单:
jsx
@eslint/create-config: v1.4.0
✔ How would you like to use ESLint? · problems
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · react
✔ Does your project use TypeScript? · typescript
✔ Where does your code run? · browser
The config that you've selected requires the following dependencies:
eslint, globals, @eslint/js, typescript-eslint, eslint-plugin-react
✔ Would you like to install them now? · No / Yes
✔ Which package manager do you want to use? · npm
☕️Installing...
笔记:
eslint
plugin
与extend
的区别:
extend
提供的是 eslint 现有规则的一系列预设plugin
则提供了除预设之外的自定义规则,当你在 eslint 的规则里找不到合适的的时候就可以借用插件来实现了
安装插件 eslint
,此时就可以看到代码 App.txs
中的错误提示(如定义一个未使用的变量)
在 package.json
中增加 scripts "lint": " eslint 'src/**/*.+(js|ts|jsx|tsx)' "
控制台运行 npm run lint
也可以看到错误提示。如果要自动修复,可以加 --fix
参数
eslint.config.mjs
与.eslintrc.js
在使用 npx eslint --init
初始化 ESLint 配置时,你可能会注意到生成的配置文件是 eslint.config.mjs
而不是传统的 .eslintrc.js
.eslintrc.js
- CommonJS 模块 :
.eslintrc.js
文件使用的是 CommonJS 模块语法,适用于 Node.js 环境。这意味着你可以使用require
来导入模块,并使用module.exports
导出配置。 - 传统用法 :
.eslintrc.js
是 ESLint 长期以来默认推荐的配置文件格式之一,广泛使用并兼容多数项目。 - 灵活性:支持动态计算或条件逻辑,因为它是一个标准的 JavaScript 文件,你可以编写任何合法的 JavaScript 代码。
eslint.config.mjs
- ECMAScript 模块 (ESM) :
eslint.config.mjs
使用的是 ECMAScript 模块语法,这是现代 JavaScript 标准。使用import
和export
语法进行模块管理。 - 现代化趋势:随着 Node.js 在较新版本中对 ESM 的支持增强,ESLint 也开始转向支持这种更现代的模块系统。这与 JavaScript 生态系统整体向 ESM 的迁移一致。
- 文件扩展名 :
.mjs
扩展名明确表明该文件使用的是 ECMAScript 模块语法,这对于某些工具和运行环境可以自动识别和处理。
总之,两者都可以用于配置 ESLint,只是在模块规范和文件格式上有所不同。选择哪个取决于你的项目环境以及对现代 JavaScript 特性的需求。
prettier
安装插件:
bash
npm install prettier eslint-config-prettier eslint-plugin-prettier -save-dev
eslint-config-prettier
禁用所有和 Prettier 产生冲突的规则eslint-plugin-prettier
把 Prettier 应用到 Eslint,配合 rules"prettier/prettier": "error"
实现 Eslint 提醒。
安装 vscode 插件 prettier
,此时可以看到代码 App.txs
中的格式提示(如末尾是否使用 ;
,或单引号、双引号)
插件配置:
1-配置 eslint 配置文件的 extends
jsx
import globals from 'globals'
import pluginJs from '@eslint/js'
import tseslint from 'typescript-eslint'
import pluginReact from 'eslint-plugin-react'
import prettierPlugin from 'eslint-plugin-prettier'
import prettierConfig from 'eslint-config-prettier'
/** @type {import('eslint').Linter.Config[]} */
export default [
{ files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'] },
{ languageOptions: { globals: globals.browser } },
pluginJs.configs.recommended,
...tseslint.configs.recommended,
pluginReact.configs.flat.recommended,
// 添加 Prettier 规则
{
plugins: { prettier: prettierPlugin },
rules: {
...prettierConfig.rules, // 兼容 Prettier
'prettier/prettier': 'warn', // 显示 Prettier 格式化建议
},
},
]
2-在 package.json
中增加 scripts:
json
"format": " prettier --write 'src/**/*.+(js|ts|jsx|tsx)' "
控制台运行 npm run format
可以修复所有的格式错误
3-设置 vscode .vscode/settings.json
自动保存格式,可以在文件保存时,自动保留格式
json
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}
4-项目中增加配置文件 .prettierrc.json
规定自己的编码格式,运行 npm run format
可以看到效果,保存文件也可以看到效果。
jsx
{
"arrowParens": "avoid",
"bracketSpacing": true,
"endOfLine": "lf",
"jsxBracketSameLine": false,
"printWidth": 100,
"proseWrap": "preserve",
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"useTabs": false,
"trailingComma": "es5",
"parser": "typescript"
}
jsx
// 箭头函数只有一个参数的时候可以忽略括号
arrowParens: "avoid",
// 括号内部不要出现空格
bracketSpacing: true,
// 行结束符使用 Unix 格式
endOfLine: "lf",
// true: Put > on the Last Line instead of at a new Line
jsxBracketSameLine: false,
// 行宽
printWidth: 100,
// 换行方式
proseWrap: "preserve",
// 分号
semi: false,
// 使用单引号
singleQuote: true,
// 缩进
tabWidth: 2,
// 使用 tab 缩进
useTabs: false,
// 后置逗号,多行对象、数组在最后一行增加逗号
trailingComma: "es5",
// 解析器
parser: "typescript"
注意:如果此处没效果,可以重启 vscode 再重试。
注意事项:
一直搞不定,重启 vscode 就好了。在 vscode 搜"prettier" 插件时,发现一个 "reload required" 的提示,于是就重启了
- CRA 创建的项目,配置文件是
js
格式 - vite 创建的项目,配置文件是
cjs
格式
流程管理
github管理项目:
jsx
echo "# LowCode" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:NathanCh3n/LowCode.git
git push -u origin main
husky
介绍:
- 一个 git hook 工具
- 在 git commit 之前执行自定义的命令
- 如执行代码风格的检查,避免提交非规范代码
安装依赖:
npm install husky -save-dev
增加三个 pre-commit
命令
jsx
npm run lint
npm run format
git add .
通过命令加:
jsx
npx husky add .husky/pre-commit "npm run lint"
或者通过项目中 .husky 文件来配置
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint
npm run format
git add .
测试:
可以故意制造一个错误:定义一个未使用变量(eslint 配置文件 rules
增加 'no-unused-vars': 'error',
),然后执行 git commit
试试
参考文档:
https://github.com/typicode/husky
commit-lint
**介绍:**用于限制 commit 的提交规范
安装:
jsx
npm install --save-dev @commitlint/cli
配置:
.husky 下新增 commit-msg 文件
jsx
# Add commit message linting to commit-msg hook
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg
笔记:
commit 规则可以查看
node_modules/@commitlint/config-conventional
(在 commitlint.config.js
中有配置)
尝试 git commit -m "test"
会失败,再尝试 git commit -m "chore: commit lint"
会成功
参考文档:
https://github.com/conventional-changelog/commitlint#getting-started
附录:package.json
推荐node版本:node/18.20.6
jsx
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.18.11",
"@types/react-dom": "^18.0.10",
"ahooks": "^3.7.4",
"ajv": "^8.17.1",
"ajv-keywords": "^5.1.0",
"antd": "^5.2.2",
"classnames": "^2.3.2",
"formik": "^2.2.9",
"immer": "^9.0.19",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.43.1",
"react-scripts": "5.0.1",
"sass": "^1.58.0",
"styled-components": "^5.3.6",
"styled-jsx": "^5.1.2",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"lint": " eslint 'src/**/*.+(js|ts|jsx|tsx)' ",
"format": " prettier --write 'src/**/*.+(js|ts|jsx|tsx)' ",
"prepare": "husky install"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@commitlint/cli": "^17.4.2",
"@commitlint/config-conventional": "^17.4.2",
"@types/react": "^19.0.8",
"@types/styled-components": "^5.1.26",
"@typescript-eslint/eslint-plugin": "^5.50.0",
"@typescript-eslint/parser": "^5.50.0",
"eslint": "^8.33.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.32.2",
"husky": "^8.0.3",
"prettier": "^2.8.3"
}
}