1

本文记录了使用vitejs, antd, react, redux搭建项目过程,其它包含了集成jest单元测试, tailwindcss使用,eslint代码格式化以及 git 代码提交规范化等功能。

1. 初始化项目

我们使用 Vite.js 来打包我们的代码。

运行如下命令:

pnpm create vite

会出现如下的选择:

√ Project name: ... react-redux-starter   # 设置项目名  这里我们设置为react-redux-starter
√ Select a framework: » React  # 选择框架 React
√ Select a variant: » TypeScript + SWC 

到这里我们项目初始化完成。 这时可以看到我们初始化的项目目录如下:

react-redux-starter
    │  .gitignore
    │  index.html
    │  package.json
    │  tsconfig.json     # typescript 配置文件
    │  tsconfig.node.json # typescript 配置文件
    │  vite.config.ts    # vite 配置文件
    │
    ├─public
    │      vite.svg
    │
    └─src
        │  App.css
        │  App.tsx
        │  index.css
        │  main.tsx
        │  vite-env.d.ts
        │
        └─assets
                react.svg

这里我们先把初始化的代码清理一下:

App.cssindex.css 清空

// App.tsx

import './App.css'

function App() {
  return (
    <div>
      Hello world!
    </div>
  )
}

export default App

这一步骤 代码参考

2 集成 antd 与 tailwindcss

pnpm add antd @ant-design/icons
pnpm install -D tailwindcss postcss autoprefixer

# 生成 tailwind 配置文件
npx tailwindcss init -p

运行完以上命令,在根目录下会生成两个配置文件 postcss.config.jstailwindcss.config.js, 其中 postcss.config.js 这个文件是不需要修改的, 我们用默认的生成的就行。 然后我们修改一下 tailwindcss.config.js 这个配置文件如下:

/** @type {import('tailwindcss').Config} */
module.exports = {
 // content 配置 tailwind 要处理的文件。
 // 只有在这里配置的文件,才能使用 tailwind 的样式,进而由 PostCSS 打包进实际项目中
  content: [ 
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}"
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

到这里 tailwindcss 的配置已经完成,接下就需要把 tailwindcss 的样式应用到我们的项目中去。

首先我们先编辑 index.css

@tailwind base;
@tailwind components;
@tailwind utilities;

然后打开 App.tsx 编辑,加上 tailwindcss 样式测试一下

import { Button } from 'antd'
import { CiCircleFilled } from '@ant-design/icons'
import './App.css'

function App() {
  return (
    <div className='font-bold text-red-500 bg-[#ccc] h-screen w-screen'>
      <Button type="primary" className='flex items-center'>
        <CiCircleFilled size={16}/> Hello world!
      </Button>
    </div>
  )
}

export default App

此时我们就可以看到 tailwindcss 样式 和 antd 组件都生效了。

如果样式未生效,请检查:

  • tailwindcss.config.js 配置文件里的 content 是否配置了
  • index.css 是否加入了 tailwindcss 的样式引入
  • main.tsx 中是否引入了 index.css

这一步骤 代码参考

3. 集成 Redux

接着下来,我们把 Redux 状态管理集成到我们的项目中。

pnpm add @reduxjs/toolkit react-redux

这一步骤的代码参考

4. 集成Jest单元测试

# jest 测试框架
# @types/jest Jest 类型声明包  TS 声明类型包的大版本最好和 jest 一样。
# ts-jest 转译器 利用 tsc 来转译 TypeScript  
# ts-node  写完代码之后要用 tsc 作编译,之后再用 Node.js 来跑,这样比较麻烦,所以我们会用 ts-node 来直接跑 ts 代码,省去了编译阶段。
# jest-environment-jsdom dom操作

pnpm add -D jest @types/jest ts-jest ts-node jest-environment-jsdom @testing-library/react @testing-library/user-event @testing-library/jest-dom @types/testing-library__jest-dom identity-obj-proxy @testing-library/dom @types/node

# 初始化jest 配置
npx jest --init

接着我们开始配置 jest.config.ts

// jest.config.ts
import type { Config } from 'jest'

const config: Config = {
  bail: 0, // 有测试错误后就停止错误
  // 多于一个测试文件运行时不展示每个测试用例测试通过情况
  verbose: true,
  // 测试用例运行在一个类似于浏览器的环境里,可以调用浏览器的 API
  testEnvironment: 'jsdom',
  // 转译下列模块为 Jest 能识别的代码
  preset: 'ts-jest',
  moduleNameMapper: { 
    // 模块alias  例如我们在测试文件中导入文件 import xxx from '@/components/xxx' 其中 '@/components/xxx' 会对应到<rootDir/src/components/xxx 模块。
    '^@/(.*)$': '<rootDir>/src/$1',
    // identity-obj-proxy 会mock 样式相关的
    '\\.(css|less|sass|scss)$': 'identity-obj-proxy',
  },
  // 以 <rootDir>/src 这个目录做为根目录来搜索测试文件(模块)
  roots: ['<rootDir>'],

  // 在测试环境准备好之后执行前的钩子函数,每个测试文件执行之前运行下述文件, 一些环境的兼容的代码我们可以写在这里
  setupFilesAfterEnv: ['<rootDir>/tests/jest.setup.ts'],
}

export default config

扩展 Jest 的 expect API,以便在测试中使用 Jest DOM 的断言函数

tests/jest.setup.ts

import '@testing-library/jest-dom/extend-expect'

既然我们在 jest 配置了导入模块 alias。 同样的我们也需要在 typescript 的配置中加入相应的 alias, 要不然 typescript 不能解析 jest 的测试代码。

同时我们在tsconfig.json 中加上 jesttypescript 类型声明。 修改如下:

{
  "compilerOptions": {
    // ...
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },
    "types": ["vite/client", "jest", "@testing-library/jest-dom"] 
  },
  // ...
}

并且还需要在 vite.config.ts 中加上相应的alias配置.

import path from 'path'
// ... 代码
export default defineConfig({
  // ... 代码
  resolve: {
    alias: {
      '@': path.resolve(__dirname, '/src'),
    }
  }
  // ... 代码
})

好了,现在 jest 基本上已经配置完成了, 我们写个小例子来测试一下。示例代码

现在添加一个React组件的测试 示例代码

安装依赖如下:

pnpm add axios
pnpm add -D classnames msw

5. 集成代码规范相关的工具 eslint stylelint prettier

pnpm add -D eslint prettier stylelint  eslint-plugin-react@latest @typescript-eslint/eslint-plugin@latestes @typescript-eslint/parser lint-config-prettier eslint-plugin-prettier stylelint-config-prettier stylelint-config-standard stylelint-order

配置 prettier 规则, 在根目录下新建一个 .prettierrc.cjs 配置文件, 内容如下:

module.exports = {
  // 一行最多 120 字符..
  printWidth: 80,
  // 使用 2 个空格缩进
  tabWidth: 2,
  // 不使用缩进符,而使用空格
  useTabs: false,
  // 行尾需要有分号
  semi: false,
  // 使用单引号
  singleQuote: true,
  // 对象的 key 仅在必要时用引号
  quoteProps: "as-needed",
  // jsx 不使用单引号,而使用双引号
  jsxSingleQuote: false,
  // 末尾不需要有逗号 none es5 all
  trailingComma: "es5",
  // 大括号内的首尾需要空格
  bracketSpacing: true,
  // jsx 标签的反尖括号需要换行
  jsxBracketSameLine: false,
  // 箭头函数,只有一个参数的时候,不需要括号 always avoid
  arrowParens: "always",
  // 每个文件格式化的范围是文件的全部内容
  rangeStart: 0,
  rangeEnd: Infinity,
  // 不需要写文件开头的 @prettier
  requirePragma: false,
  // 不需要自动在文件开头插入 @prettier
  insertPragma: false,
  // 使用默认的折行标准
  proseWrap: "preserve",
  // 根据显示样式决定 html 要不要折行
  htmlWhitespaceSensitivity: "css",
  // vue 文件中的 script 和 style 内不用缩进
  vueIndentScriptAndStyle: false,
  // 换行符使用 lf
  endOfLine: "lf",
}

再配置 eslint, 在根目录下创建 .eslintrc 配置文件, 内容如下:

{
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": [
        "eslint:recommended",
        "plugin:react/recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:prettier/recommended"
    ],
    "overrides": [],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "ecmaVersion": "latest",
        "sourceType": "module"
    },
    "plugins": [
        "react",
        "@typescript-eslint",
        "prettier"
    ],
    "settings": {
        "react": {
            "version": "detect"
        }
    },
    "rules": {
        "prettier/prettier": "error",
        "arrow-body-style": "off",
        "prefer-arrow-callback": "off"
    }
}

最后配置一个样式的规则, 创建一个 .stylelintrc.json, 内容如下:

{
    "extends": [
        "stylelint-config-standard",
        "stylelint-config-prettier"
    ],
    "plugins": [
        "stylelint-order"
    ]
}

接下来在 package.jsonscript 中添加命令。

{
    "script": {
        "lint": "eslint --ext .js,.jsx,.ts,.tsx --fix --quiet ./"
    }
}

6. husky + commitlint +lint-staged

pnpm add -D husky lint-staged @commitlint/cli @commitlint/config-conventional

在 package.json 添加 prepare 命令并运行

{
  "script": {
    // ...,
    "prepare": "husky install"
  }
}
yarn prepare

给 Husky 添加一个 Hook, 这样每次 git commit 之前都会先运行 npm run lint, 通过之后才会提交代码

npx husky add .husky/pre-commit "npm run lint"

我们可以通过 lint-staged 只对暂存区的代码进行检验。在级 package.json 添加一个 lint-staged 的配置

{
  "lint-staged": {
    "*.{js,jsx,tsx,ts}": [
    "npm run lint"
    ]
  }
}

并在 .husky/pre-commit 中替换 npx lint-staged。。现在我们每次 git commit 前都会对改动的文件进行 Lint 检查了。

commitlint 配置

在根目录下创建配置文件 .commitlintrc.cjs

module.exports = {
  extends: ["@commitlint/config-conventional"]
}

然后给 husky 添加一个 commit-msg hook,

npx husky add .husky/commit-msg "npx --no-install commitlint -e $HUSKY_GIT_PARAMS"

现在提交信息不规范就会被拦截导致提交失败,规范可见 commitlint ,当然你也可以根据需要修改提交信息规范。

文档参考


无尘
97 声望1 粉丝