Vite创建一个 React + TS 的项目

一、创建基础项目

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"
  }
}
相关推荐
lichenyang45311 小时前
从 Express 老项目到 NestJS + Docker:一次车辆管理系统的渐进式重构
前端
Momo__12 小时前
VueUse createReusableTemplate —— 单文件组件内的模板复用神器
前端·vue.js
程序员小富12 小时前
我开源了一个开发者专属的智能 JSON 工具,得到了媳妇高度认可
前端·vue.js·后端
小小小小宇12 小时前
程序员如何给 LLM 装工具以及看懂推理过程
前端
写代码的皮筏艇12 小时前
React中的forwardRef
前端·react.js·面试
槑有老呆12 小时前
花三个月工资请了个 AI 程序员,结果它连青岛啤酒股价都查不了
前端
风骏时光牛马12 小时前
Verilog开发常见问题汇总解析
前端
子兮曰12 小时前
AI Coding Method Map:一张图看懂 AI 编程的完整链路
前端·人工智能·后端
weedsfly12 小时前
语法糖褪去之后——Babel 转译产物中的 JavaScript 本貌
前端·javascript