保姆级教程-从0开始搭建一个规范的React+Ts+vite项目

前言

不知道大家平时是怎么搭建项目的,工作时一般都是使用公司脚手架搭建项目。 私底下想做点东西我常用由creat-react-app或者vite创建一个项目,然后装一大堆的配置。 为了更好的摸鱼🐟,我打算建一个标准化的React项目。

这篇文章就是搭建的过程,命令行操作单独列出来了,CV即可

新建一个文件夹,开始项目搭建

bash 复制代码
mkdir template-ts-react
cd template-ts-react

包管理工具

项目采用pnpm作为包管理工具,其速度快,而且节省磁盘空间

bash 复制代码
pnpm init

(可选) 将pnpm切换成tabao镜像

bash 复制代码
# 查看pnpm源
pnpm get registry
# 切换tabao镜像
pnpm config set registry https://registry.npmmirror.com
pnpm install

# 还原
pnpm config set registry https://registry.npmjs.org

这样设置源也有一些问题,自己用用到还算好,但如果碰到日常开发使用公司的私有源就有点麻烦。

使用nrm切换能更方便些

bash 复制代码
pnpm i -g nrm
nrm use taobao
# 添加私有源
nrm add <registry> <url>
nrm del <registry>
# 查看源
nrm ls

切换源之后pnpm全局安装会出现 ERR_PNPM_REGISTRIES_MISMATCH问题 按提示重新安装下好了

bash 复制代码
pnpm i -g
pnpm i -g pnpm

vite

Vite原生支持ESM和Typescript,支持自动热更新,构建速度也比webpack快。除了陈年老项目实在想不出不用的理由。。。

bash 复制代码
pnpm i vite -D

在项目根目录新建一个index.html,为作为入口文件。

bash 复制代码
# 会开启一个本地服务器,就可以直接打开这个index.html页面
pnpm vite

vite v1版本使用Koa开启本地服务器,v2及以上版本使用connect中间件的形式, live-server也是使用connect中间件的形式

根目录下新建下一个vite.config.ts,安装下@vitejs/plugin-react,开启HMR特性

bash 复制代码
pnpm i @vitejs/plugin-react -D
ts 复制代码
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  base: './',
  plugins: [react()],
})

引入React 和 Typescript

React核心代码位于React包中,虚拟DOM相关代码在React的Reconciler包中,使用虚拟DOM对接不同的宿主环境,调用对应的API,就能实现多平台的渲染能力。

在浏览器和Nodejs宿主环境使用ReactDOM。

bash 复制代码
pnpm i react react-dom

这里以版本的形式列出了部分React的变化,标记红色粗体部分在后续的操作中会接触到

并发模式

在项目中使用React第一步就是需要先创建一个React root,用于在浏览器DOM中显示元素,React v16和v17版本创建的项目有些是使用ReactDOM.render(<App />, document.getElementById('root'));,v18则全面开启并发模式(ConCurrent),实现并发更新

差异如下:

tsx 复制代码
// src/main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'

import App from './App'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)
tsx 复制代码
// src/App.tsx
function App() {
  return <div>Hello World</div>
}

export default App

新的JSX转换方式

浏览器本身并不支持JSX,v17之前的旧版本JSX需要借助babel-plugin-transform-react-jsx转化成React.createElement,因此即便没使用React也需要显示引入React

转换后的结果如下:

JS 复制代码
import React from 'react';

function App() {
  return React.createElement('h1', null, 'Hello world');
}

得益于v17版本引入的全新的JSX转换,即使无需引入React也能够使用JSX

jsx 复制代码
// 由编译器引入(禁止自己引入!)
import {jsx as _jsx} from 'react/jsx-runtime';

function App() {
  return _jsx('h1', { children: 'Hello world' });
}

Typescript

但是继续开发时就会发现ts不支持JSX的语法,还需外要额外配置下ts

bash 复制代码
# 安装下typescript和React的类型声明
pnpm i typescript  @types/react @types/react-dom -D
# 生成tsconfig.json
tsc -init

设置下tsconfig.json,找到"jsx": "preserve"这一项,修改值为"jsx": "react-jsx" , 此时TS的报错问题就解决了。

对根目录的index.html做下修改,设置根结点,以模块形式引入main.tsx,就建立一个最基本的结构了

html 复制代码
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React + TS</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>
bash 复制代码
pnpm vite

就可以启动本地服务器在浏览器上可以看到渲染出的内容了

代码格式

没有规范的代码格式会导致:

  • 代码格式风格不统一,要花更多的时间看代码
  • 没有统一的规范,会导致在多人协作的代码提交中会有很多的格式修改,造成不必要的消耗。非常影响排查问题

ESLint

ESLint 是一个根据方案识别并报告 ECMAScript/JavaScript 代码问题的工具,其目的是使代码风格更加一致并避免错误。

bash 复制代码
# 初始化eslint配置
npx eslint --init

就直接使用现成的ESlint标准了,不折腾了

根目录新建一个.eslintignore,里面存放Eslint不检测的文件

复制代码
node_modules
.eslintrc.cjs
dist

Prettier

使用Prettier格式化代码,但是同时启用ESLint+Prettier,ESlint会先执行,Prettier后执行,导致代码格式反复横跳。

bash 复制代码
pnpm i prettier eslint-plugin-prettier eslint-config-prettier -D

Eslint和prettier的冲突处理可以参考下prettier/eslint-plugin-prettier的配置方式

根目录下新建.prettierrc.cjs,添加下Prettier配置

java 复制代码
module.exports = {
  printWidth: 100, //单行长度
  tabWidth: 2, //缩进长度
  useTabs: false, //使用空格代替tab缩进
  semi: false, //句末使用分号
  singleQuote: true, //使用单引号
  quoteProps: 'as-needed', //仅在必需时为对象的key添加引号
  jsxSingleQuote: true, // jsx中使用单引号
  bracketSpacing: true, //在对象前后添加空格-eg: { foo: bar }
  jsxBracketSameLine: true, //多属性html标签的'>'折行放置
  arrowParens: 'always', //单参数箭头函数参数周围使用圆括号-eg: (x) => x
  requirePragma: false, //无需顶部注释即可格式化
  insertPragma: false, //在已被preitter格式化的文件顶部加上标注
  endOfLine: 'auto', //结束行形式
  embeddedLanguageFormatting: 'auto', //对引用代码进行格式化
}

.eslintrc.js添加下规则,extends添加'plugin:prettier/recommended',关闭冲突规则。 plugins中添加'prettier',使得Eslint可以通过Prettier格式化代码

js 复制代码
  extends: ['standard-with-typescript','plugin:react/recommended','plugin:prettier/recommended'],
  plugins: ['react', 'prettier'],
  rules: {
    'react/jsx-use-react': 0, // React V17开始JSX已经不再需要引入React
    'react/react-in-jsx-scope': 0, // 同上
    'import/first': 0, // 消除绝对路径必须要在相对路径前引入,
    'no-mixed-spaces-and-tabs': 2, // 禁止空格和 tab 的混合缩进
    'no-debugger': 2, // 禁止有debugger
    'space-infix-ops': 2, // 要求操作符周围有空格
    'space-before-blocks': 2, // 要求语句块之前有空格
    '@typescript-eslint/explicit-function-return-type': 0, // 禁止函数必须要定义返回类型
  },

Stylelint

使用Stylelint规范化CSS,可以控制下CSS属性的书写顺序,看起来更加工整。

项目使用的是less,需要安装对应的less相关的库

arduino 复制代码
pnpm i less stylelint stylelint-config-standard-less postcss-less -D

可以根据项目和习惯自定义CSS属性的属性顺序,也可以直接使用社区方案

  1. 自定义CSS属性的属性顺序
bash 复制代码
pnpm i stylelint-order -D

.stylelintrc.cjs按照下面代码进行配置,order/properties-order中存放指定属性的前后顺序

js 复制代码
module.exports = {
  extends: ['stylelint-config-standard-less'],
  overrides: [{ files: ['**/*.less'], customSyntax: 'postcss-less' }],
  plugins: ['stylelint-order'],
  rules: {
    'order/order': ['custom-properties', 'declarations'],
    'order/properties-order': ['width', 'height'],
  },
}
  1. 使用社区方案 在awesome-stylelint上有其他已经配置好的方案,开盒即用

这里就以stylelint-config-recess-order为例

css 复制代码
pnpm i stylelint-config-recess-order -D
css 复制代码
module.exports = {
  extends: ['stylelint-config-standard-less', 'stylelint-config-recess-order'],
  overrides: [{ files: ['**/*.less'], customSyntax: 'postcss-less' }],
  plugins: [],
  rules: {},
}

规范化提交

Commitizen

没有明确的提交规范会导致commit message非常随意,看着都头疼,非常影响定位问题和修bug的效率。

使用Commitizen规范下commit message。

bash 复制代码
# 初始化下git
git init

# 安装配置Commitizen
pnpm install commitizen -D
commitizen init cz-conventional-changelog --pnpm --save-dev --save-exact

# 后续就可以使用commitizen
git cz

husky

husky 是一个增强的 git hook 工具,可以在 git hook 的各个阶段执行我们在 package.json 中配置好的script。

bash 复制代码
# 安装husky
pnpm dlx husky-init
pnpm install
代码检验

在commit之前,执行lint进行代码校验 在package.json中添加下lint指令,使用eslint使用自动修复在src目录下ts和tsx文件

json 复制代码
"scripts": {
    "lint": "eslint --fix --ext .ts,.tsx src"
},
bash 复制代码
npx husky add .husky/pre-commit "pnpm run lint"
提交信息检验

(可选) 在husky中添加prepare-commit-msg

bash 复制代码
npx husky add .husky/prepare-commit-msg "exec < /dev/tty && npx cz --hook || true"

这样使用git commit会自动进入到commitizen,但是我不建议这样操作。 改变 git commit 命令原有的行为 ,失去快速提交的方式,像 git commit -m "chore: ...",可能其他项目参与者并不知道使用commitizen进行提交,即便输入符合规范的commit message信息,也会跳转到commitizen补全信息,而且这个命令行交互效果体验很差 但直接使用git commit提交,又不能限制提交的message,因此额外添加了commitlint进行判断

使用commitlint工具对git commit提交的message信息进行检验

bash 复制代码
pnpm i @commitlint/config-conventional @commitlint/cli -D

在package.json中添加

json 复制代码
  "scripts": {
    "commitlint": "commitlint --config commitlint.config.cjs -e -V"
  },

配置下husky的commit-msg

bash 复制代码
npx husky add .husky/commit-msg 'pnpm run commitlint'

配置下commitlint的配置文件commitlint.config.cjs

cjs 复制代码
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      ['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'chore', 'revert', 'build'],
    ],
    'type-case': [0],
    'type-empty': [0],
    'scope-empty': [0],
    'scope-case': [0],
    'subject-full-stop': [0, 'never'],
    'subject-case': [0, 'never'],
    'header-max-length': [0, 'always', 72],
  },
}

现在既能够支持使用git cz方式提交commit,也能使用git commit按照规范快速提交

样式检验
sql 复制代码
  "scripts": {
    "stylelint": "stylelint \"src/**/*.less\" --fix"
  },
sql 复制代码
npx husky add .husky/pre-commit 'pnpm run stylelint'

代码生成

Snippets

之前使用create-react-app搭建的项目时一直觉得那种只需要在输入几个像crf的字符,就能快速生成一段代码的方式很方便,自己搭建的项目里面肯定也要加上这样的功能。

大部分的IDE都支持自定义代码片段功能,我就以VScode为例建立一个自定义的Snippets

VScode中ctrl+shift+P搜索Snippets就能找到对应的设置。 可选择全局或者项目内设置snippets,设置后就会出现一个后缀名为code-snippets的文件。 Snippets有特定的语法,学习起来还要花时间,所以直接使用代码转Snippet的方案snippet-generator.app/,设置下代码和想使用的prefix前缀,cv下粘到code-snippets 文件里面就好了

hygen

在一些场景下像组件,都是有比较固定的文件结构和代码结构,直接copy旧组件还要删除多余的部分,这可太麻烦了,有时候还会带入一些bug。

既然是固定的结构那直接使用代码生成器根据指定模板生成即可。

使用hygen生成代码

bash 复制代码
pnpm i hygen -D
hygen init self

初始化之后会创建一个根目录下创建一个_templates文件夹,内部存放模板,接下来我们就创建一个名为component的模板。

bash 复制代码
hygen generator new component

模板的结构与ejs类似,前面一部分存放生成代码的位置,后面一部分就是ejs的写法,使用尖括号加百分号的标记来执行代码和插值。

ts 复制代码
---
to: src/components/<%= name %>/index.tsx
---

import React,{ FC } from "react";

interface I<%= name %>Props {
}

const <%= name %>:FC<I<%= name %>Props> = (props) => {
  return <div></div>
}

export default <%= name %>

根据这个模板可以在 src/components/指定的目录下根据模板生成指定的代码。

bash 复制代码
hygen component new Button

相关推荐
斟的是酒中桃7 分钟前
基于Transformer的智能对话系统:FastAPI后端与Streamlit前端实现
前端·transformer·fastapi
烛阴25 分钟前
Fract - Grid
前端·webgl
JiaLin_Denny40 分钟前
React 实现人员列表多选、全选与取消全选功能
前端·react.js·人员列表选择·人员选择·人员多选全选·通讯录人员选择
brzhang44 分钟前
我见过了太多做智能音箱做成智障音箱的例子了,今天我就来说说如何做意图识别
前端·后端·架构
为什么名字不能重复呢?1 小时前
Day1||Vue指令学习
前端·vue.js·学习
eternalless1 小时前
【原创】中后台前端架构思路 - 组件库(1)
前端·react.js·架构
Moment2 小时前
基于 Tiptap + Yjs + Hocuspocus 的富文本协同项目,期待你的参与 😍😍😍
前端·javascript·react.js
Krorainas2 小时前
HTML 页面禁止缩放功能
前端·javascript·html
whhhhhhhhhw3 小时前
Vue3.6 无虚拟DOM模式
前端·javascript·vue.js
鱼樱前端3 小时前
rust基础(一)
前端·rust