React 低代码项目:项目创建

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 .(无需全局安装)


问题修复

文件系统操作冲突

问题快照:

问题分析:

这个错误信息表明在使用 npxcreate-react-app 创建新的 React 应用时,出现了由于文件系统操作(特别是重命名)导致的权限或存在冲突的问题。具体而言,npm 在尝试重命名缓存目录中的某个文件时遇到了文件已经存在的问题。同时,还涉及到权限不足的情况。

错误码和系统调用:

  • npm ERR! code EEXIST:表示在进行文件操作时,目标路径已经存在同名文件。这通常出现在尝试创建、移动或重命名一个文件到一个已经存在的文件路径时。
  • npm ERR! syscall rename:指出失败的系统调用是 rename,即在尝试重命名一个文件路径的时候发生错误。

解决方案:

  1. 清理 npm 缓存

使用 npm cache clean --force 来强制清理 npm 缓存。这可以解决由缓存文件损坏引起的问题。

bash 复制代码
npm cache clean --force
  1. 检查并修复权限问题
  • 确保您具有对 .npm 目录的正确权限。有时候因为之前的安装操作以 root 用户执行导致现在的用户权限不足。

  • 使用以下命令更改 .npm 目录的所有权:

    bash 复制代码
    sudo chown -R $(whoami) ~/.npm
  • 如果您在全局安装包时遇到权限问题,可以考虑使用 nvm(Node Version Manager)来管理 Node.js 和 npm,以避免使用 sudo。

  1. 删除冲突文件
  • 手动删除错误信息中提到的具体路径上的冲突文件:
bash 复制代码
rm -rf /Users/nathanchen/.npm/_cacache/content-v2/sha512/30/8b/3c91d31ffce7e8ab92600bb41d5442612d23c9ac1ad212415b7d768686fe6cc3a56ae156e64fa442b6f60b1be83eb0c02eb87bbaaf76e4a44351555f
  1. 使用 -force 参数重新运行命令
  • 使用 -force 参数来强制覆盖现有文件,不过这需要谨慎,因为它可能会覆盖掉重要文件。

  • 修改命令如下:

    bash 复制代码
    npx create-react-app my-app --template typescript --force
  1. 确保 npm 和 Node.js 是最新的
  • 更新 npm 到最新版本,这样能避免已知的旧版本问题:

    bash 复制代码
    npm install -g npm@latest
  • 确保 Node.js 也是最新稳定版,可以从官方网站下载更新版本。

  1. 查看详细日志
  • 查看完整的日志文件 /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

问题分析:

  1. 错误代码和信息
    • 错误信息 Error: error:0308010C:digital envelope routines::unsupported 以及 ERR_OSSL_EVP_UNSUPPORTED 指向了 OpenSSL 的加密相关功能。
    • digital envelope routines 是 OpenSSL 中用于加密和解密操作的一部分,表明问题与加密算法相关。
  2. Node.js 系统内部调用
    • 错误栈中的 at new Hash (node:internal/crypto/hash:68:19)at Object.createHash (node:crypto:138:10) 显示了错误发生在 Node.js 自身的加密模块中,这是一个明确的信号,指出问题与加密哈希创建有关。
  3. OpenSSL 相关的错误信息
    • opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ] 提供了进一步的证据,指出这个问题是由于加密库初始化失败引起的。

解决方案:

  1. 降级 Node.js 版本

    • 使用 nvm (Node Version Manager)切换到稍微旧一点的 Node.js 版本,比如 16.x 或 14.x。

    • 例如:

      bash 复制代码
      nvm install 16
      nvm use 16
  2. 设置环境变量以禁用 OpenSSL 3.0 的严格模式

    • 可以通过在运行命令前设置环境变量来临时规避该问题。

    • 在终端中执行以下命令:

      bash 复制代码
      export NODE_OPTIONS=--openssl-legacy-provider
      npm start
    • 或者将其添加到你的项目的 package.jsonscripts 中:

      json 复制代码
      "scripts": {
        "start": "export NODE_OPTIONS=--openssl-legacy-provider && react-scripts start"
      }
  3. 确保所有依赖项是最新的

    • 更新所有与项目相关的包,因为较新的版本可能已经修复了与 OpenSSL 3.0 不兼容的问题。

    • 运行以下命令更新:

      bash 复制代码
      npm update
  4. 检查特定于 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 pluginextend 的区别:

  • 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

  1. CommonJS 模块.eslintrc.js 文件使用的是 CommonJS 模块语法,适用于 Node.js 环境。这意味着你可以使用 require 来导入模块,并使用 module.exports 导出配置。
  2. 传统用法.eslintrc.js 是 ESLint 长期以来默认推荐的配置文件格式之一,广泛使用并兼容多数项目。
  3. 灵活性:支持动态计算或条件逻辑,因为它是一个标准的 JavaScript 文件,你可以编写任何合法的 JavaScript 代码。

eslint.config.mjs

  1. ECMAScript 模块 (ESM)eslint.config.mjs 使用的是 ECMAScript 模块语法,这是现代 JavaScript 标准。使用 importexport 语法进行模块管理。
  2. 现代化趋势:随着 Node.js 在较新版本中对 ESM 的支持增强,ESLint 也开始转向支持这种更现代的模块系统。这与 JavaScript 生态系统整体向 ESM 的迁移一致。
  3. 文件扩展名.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"
  }
}
相关推荐
zm38 分钟前
C基础寒假练习(4)
java·前端·数据库
学问小小谢1 小时前
第23节课:前端调试技巧—掌握浏览器开发者工具与性能优化
前端·学习·安全·性能优化·交互·html5
@大迁世界2 小时前
React Native 0.77 发布:更强的样式支持与性能优化
javascript·react native·react.js·ecmascript
NiNg_1_2342 小时前
使用CSS实现一个加载的进度条
前端·css·进度条
汪子熙2 小时前
Angular 项目中 Could not find Nx modules in this workspace 错误的分析与解决
前端·javascript
我的青春不太冷3 小时前
深入探讨:服务器如何响应前端请求及后端如何查看前端提交的数据(基础语法版)
服务器·前端·状态模式
qq_544329175 小时前
CRM项目的开发与调试整体策略
前端·后端·bug