一、创建基础项目
1、创建一个基础项目
lua
yarn create vite 项目名
ps:输入命令后会依次选择 框架,ts/js 即可(命令没有输入项目名,则输入命令后第一个选项是名称输入)
Project目录主要结构如下
file
|- public // 这个文件夹内放的东西不会被构建工具打包,一般用来放网站的图标或者全局配置文件。
|- src
|- App.tsx // 自定义的第一个组件
|- main.tsx // 项目主入口
|- vite-env.d.ts // ts声明文件
|- assets // 静态资源文件夹
|- index.html // 打包后,项目的主入口文件,也是react根节点挂在的文件
|- package.json // 项目的依赖配置文件,所有安装在依赖以及仓库配置
|- package-lock.json // 项目依赖锁定文件。防止依赖自动升级,导致项目无法启动
|- tsconfig.json // 项目的ts配置文件,针对src下面的所有ts文件生效。
|- tsconfig.node.json // 项目的ts配置文件,针对vite.config.ts文件。
|- vite.config.ts // vite构建工具的配置项,在这里可以使用一些第三方插件,做一些项目的配置。
|- .eslintrc.cjs // 代码格式化校验的配置项,使代码编写更加规范
|- gitignore // git提交时,忽略文件配置项
二、配置vite.config.ts
官方文档 : Vite官方中文文档
以及vite.config.js的配置项文档: Vite配置项
ts
// vite.config.ts
import { defineConfig, loadEnv } from 'vite';
import * as path from 'path';
import react from '@vitejs/plugin-react';
export default defineConfig(({ mode }) => {
// loadEnv中三个参数 (mode,dir,base) -> 返回一个包含环境变量的对象
// mode: Vite的运行模式,通常是development 或 production
// dir: 环境变量文件的查找目录,通常用 process.cwd() 获取当前工作目录
// base:环境变量文件的基础名称,通常为空字符串,表示默认的 '.env' 文件
const env = loadEnv(mode, process.cwd(), '');
return {
resolve: {
// ↓路径别名
// 如pages下Home页,可以用 '@/pages/Home/Home' 方式引入,及代表'src/pages/Home/Home'
alias: {
'@': path.resolve(__dirname, 'src')
}
},
build: {
// 类型: boolean | 'terser | 'esbuild'(默认)
// true | 'terser : 使用Terser作为 JavaScript 代码压缩器,两者效果一样。设置terser需要npm add -D terser
// false: 禁用 JavaScript 代码压缩, 构建输出的 JavaScript 文件将会保持未压缩状态
// esbuild: 使用 ESbuild作为 JavaScript 代码压缩器。比terser快 20-40倍,但构建后的文件相对更大
minify: 'terser',
// 用于配置 Terser 的对象
terserOptions: {
compress: {
// 构建时,去除 console.log 语句
drop_console: true
}
},
// 每次构建之前清空输出目录,及重新构建 dist 文件夹
emptyOutDir: true,
rollupOptions: {
output: {
// 静态资源文件输出到 assets 目录,子目录名称将根据文件扩展名([ext])而定,文件名使用原始文件名([name]),附加了哈希值([hash]),最后附加文件扩展名([extname])
assetFileNames: 'assets/[ext]/[name].[hash][extname]',
// 用于配置生产的代码分割 (chunk) 文件的命名规则
// assets/js目录下,文件扩展名(.js)。name和hash与上述等同
chunkFileNames: 'assets/js/[name].[hash].js'
},
}
},
// 初始化就有,代表Vite使用的插件是react
plugins: [react()],
server: {
// 允许从本地网络访问
host: '0.0.0.0',
proxy: {
'/api': {
// 代理目标地址,从环境变量中获取(在config第一行.env中阐述),也可以直接写成字符串 如:'http://127.0.0.1:8000' (IP和端口号根据情况定)
target: env.VITE_PROXY_API_URL,
// 改变源地址,用于支持跨域请求
changeOrigin: true
}
}
}
};
});
三、环境变量 .env
1、创建三个文件,分别对应 dev开发环境
,test测试环境
,prod生产环境
的 .env
文件
书写方式
env
# 根据实际使用情况配置
# ENV根据环境书写不同的值, dev、test、prod 方便在配置文件中动态使用
ENV='dev'
# 在配置 axios
VITE_BASE_API_URL='/api'
# 在 vite.config.ts 中替换proxy的target值,及实际请求地址
VITE_PROXY_API_URL='http://127.0.0.1:8000'
四、配置路由
1、安装路由
cmd
npm install --save react-router react-router-dom
src文件夹下,创建如下目录结构
file
|- router
|- modules
|- routes.tsx
|- useRoutes.tsx
|- index.tsx
配置路由的类型 routes.tsx
ts
// routes.tsx
import React from 'react';
export interface RouteType {
path?: string; // 对应路由
key: string; // key值
element?: React.ReactNode | null; // 对应的页面
// 根据情况使用
title: string,
icon?: React.ReactNode; // icon图标,如为 url路径 则为string类型
hidden?: boolean; // 可用于显示与否,根据情况使用
children?: RouteType[]; // 子路由数组
}
配置路由 useRoutes.tsx
tsx
// useRoutes.tsx
import { lazy } from 'react'
import RouteType from './routes'
// 利用路由懒加载
const Home = lazy(() => import('@/pages/Home/Home'))
const useRoutes: Array<RouteType> = [
// 配置路由...
{
title:"首页",
key:"/home",
path:"/home",
element:<Home/>,
}
]
export default useRoutes;
创建浏览器路由器实例 index.tsx
tsx
// index.tsx
import { createBrowserRouter, RouteObject } from "react-router-dom";
import useRoutes from "./modules/useRoutes";
const router = createBrowserRouter(useRoutes as RouteObject[])
export default router;
五、配置axios
官方文档 : Axios中文文档
javascript
// 引入axios
import axios { AxiosRequestConfig } from 'axios'
// 处理JSON 数据中大整数的插件
import JSONBIG from 'json-bigint';
// 根据需求安装,只是用于提供接口请求报错消息提醒
import { message } from 'antd';
// 请求的基础 URL,请求路径会和baseURL拼接,用于发送请求.
let baseURL;
if(process.env.ENV === 'dev') {
baseURL = 'xxx本地环境xxx';
} else if(process.env.ENV === 'prod') {
baseURL = 'xxx生产环境xxx';
}
const options:AxiosRequestConfig = {
baseURL: baseURL,
timeout: 30000
}
// 创建实例
const service = axios.create(options)
// 请求拦截器
service.interceptors.request.use(
config => {
// 判断是否具有 请求头 和 请求方法
if (!config?.headers || !config?.method) {
return Promise.reject(new Error('缺少重要参数!'));
}
// 传参数据转字符串
config.data = JSON.stringify(config.data);
// 设置 HTTP 请求的头部信息中的 Content-Type 字段为 application/json
// 用于指定请求的数据格式,告诉服务器请求的主体部分是以 JSON 格式提交的。
config.headers['Content-Type'] = 'application/json';
// 获取token
const token = localStorage.getItem('token');
if (token) {
// 设置请求头中用于 token 的键值
config.headers['access-token'] = token;
}
// 定义在接收到响应数据之前,对响应数据进行的自定义转换。
// 该选项允许你指定一个或多个转换函数,这些函数将在 Axios 处理响应数据之前执行。
config.transformResponse = [
function (data) {
// 使其在解析 JSON 时将大整数以字符串形式表示,以防止数值截断或转换为科学计数法。
const json = JSONBIG({
storeAsString: true
});
const res = json.parse(data);
return res;
}
];
return config;
},
error => {
return Promise.reject(error);
}
);
// 响应拦截器
service.interceptors.response.use(
response => {
const res = response.data;
const { code, msg } = res;
if (code !== 0) {
message.error(msg || 'Error');
if ([100001, 100002].includes(code)) {
localStorage.clear();
location.replace('/login');
}
return Promise.reject(res);
}
return res;
},
error => {
httpErrorStatusHandle(error);
return Promise.reject(error);
}
);
// 处理异常的函数
function httpErrorStatusHandle(error: any) {
// 处理被取消的请求
let msg = '';
if (error && error.response) {
switch (error.response.status) {
case 302:
msg = '接口重定向了!';
break;
case 400:
msg = '参数不正确!';
break;
case 401:
msg = '您未登录,或者登录已经超时,请先登录!';
break;
case 403:
msg = '您没有权限操作!';
break;
case 404:
msg = `请求地址出错: ${error.response.config.url}`;
break; // 在正确域名下
case 408:
msg = '请求超时!';
break;
case 409:
msg = '系统已存在相同数据!';
break;
case 500:
msg = '服务器内部错误!';
break;
case 501:
msg = '服务未实现!';
break;
case 502:
msg = '网关错误!';
break;
case 503:
msg = '服务不可用!';
break;
case 504:
msg = '服务暂时无法访问,请稍后再试!';
break;
case 505:
msg = 'HTTP版本不受支持!';
break;
default:
msg = '异常问题,请联系管理员!';
break;
}
}
if (error.message.includes('timeout')) msg = '网络请求超时!';
if (error.message.includes('Network'))
msg = window.navigator.onLine ? '服务端异常!' : '您断网了!';
message.error(msg || 'Error');
}
export default service;
六、package.json
配置package.json中scripts,用于启动和打包时,针对不同的环境
json
// 当前模块\包名称
"name": "react_project_demo",
// 表示这是一个私有项目
"private": true,
// 当前包的版本号
"version": "0.0.0",
"type": "module",
"scripts": {
//
"dev": "vite --mode dev",
//
"dev-prod": "vite --mode prod",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router": "^6.18.0",
"react-router-dom": "^6.18.0"
},
"devDependencies": {
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitejs/plugin-react": "^4.0.3",
"eslint": "^8.45.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"typescript": "^5.0.2",
"vite": "^4.4.5"
}
}