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


问题修复

文件系统操作冲突

问题快照:

问题分析:

这个错误信息表明在使用 npx 和 create-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.json 的 scripts 中:

      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 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

  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 标准。使用 import 和 export 语法进行模块管理。
  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"
  }
}
相关推荐
卸任15 小时前
Vibe coding工具使用心得
前端·ai编程
brien916 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance16 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M16 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写16 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李17 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易17 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马17 小时前
前沿视界
前端
kyriewen17 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易17 小时前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员