vite官网
# npm 6.x
npm init vite@latest vite-react-app --template react
# npm 7+, 需要额外的双横线:
npm init vite@latest vite-react-app -- --template react
react-router-dom
参考
安装 react-router-dom v6
npm i react-router-dom -S
在src/pages下创建页面组件
// Home/index.jsx
import React from 'react'
import { Outlet } from "react-router-dom";
import './index.less'
export default function Home() {
return <div className="layout-container">
<aside className="layout-left">
aside
</aside>
<article className="layout-right">
<header className="layout-header">
header
</header>
<div className="layout-main">
main
<Outlet />
</div>
</article>
</div>
}
// About/index.jsx
import React from 'react'
export default function About() {
return <div>
About
</div>
}
新建 src/router/index.js 配置路由数组
// router/index.js
import Home from '@/pages/Home'
import About from '@/pages/About'
import Blogs from '@/pages/Blogs'
import Login from '@/pages/Login'
import NotFound from '@/pages/NotFound'
const routes = [
{
path: "/",
element: <Home />,
children: [
{
path: "/about",
element: <About />
},
{
path: "/blogs",
element: <Blogs />
}
]
},
{
path: "/login",
element: <Login />
},
{
path: "*",
element: <NotFound />
}
]
export default routes
在 App.jsx 引入路由配置, 使用useRoutes解析配置路由数组
// App.jsx
import React, { useState } from 'react'
import { useRoutes } from "react-router-dom"
import routes from '../src/router'
export default function App() {
return (<>{useRoutes(routes)}</>)
}
BrowserRouter要在顶层,不能再App里面
// main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from "react-router-dom"
import App from './App'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
)
Ant Desigin 官网
安装antd 和 其icons
npm i antd @ant-design/icons -S
在main.jsx 添加样式
// main.jsx
import 'antd/dist/antd.css'
使用antd的组件
// Home/index.jsx
import React from 'react'
import { Button } from 'antd'
export default function Index() {
return <div>
<Button type='primary'>Index</Button>
</div>
}
安装vite-plugin-imp插件 和 less
npm i vite-plugin-imp less -D
在vite.config.js 配置文件
// vite.config.js
import { defineConfig } from 'vite'
import reactRefresh from '@vitejs/plugin-react-refresh'
import vitePluginImp from 'vite-plugin-imp'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
reactRefresh(),
vitePluginImp({
libList: [
{
libName: "antd",
style: (name) => `antd/lib/${name}/style/index.less`,
},
],
})
],
css: {
preprocessorOptions: {
less: {
javascriptEnabled: true, // 支持内联 JavaScript
}
}
},
})
可将 main.jsx 的 import ‘antd/dist/antd.css’ 去掉
npm i less-vars-to-js -D
配置vite.config.js
...
import path from 'path'
import fs from 'fs'
import lessToJS from 'less-vars-to-js' // less 样式转化为 json 键值对的形式
const themeVariables = lessToJS(
fs.readFileSync(path.resolve(__dirname, './src/css/variables.less'), 'utf8')
)
export default defineConfig({
...
css: {
preprocessorOptions: {
less: {
javascriptEnabled: true, // 支持内联 JavaScript
modifyVars: themeVariables, // 重写 ant design的 less 变量,定制样式
}
}
}
...
}
/* ./src/css/variables.less */
@primary-color: #00f; // 全局主色, 覆盖Ant Design的@primary-color
// packages.json
{
"scripts": {
"dev": "vite --mode dev",
"build:test": "vite build --mode test",
"build:prod": "vite build --mode prod",
"serve": "vite preview"
}
}
// config/index.js
const env = {
dev: {
cdn: './',
apiBaseUrl: '/api' // 开发环境接口请求,后用于 proxy 代理配置
},
test: {
cdn: '//a.xxx.com/vite-react-app/test', // 测试环境 cdn 路径
apiBaseUrl: '//www.test.xxx.com/v1' // 测试环境接口地址
},
prod: {
cdn: '//a.xxx.com/vite-react-app/prod', // 正式环境 cdn 路径
apiBaseUrl: '//www.test.com/v1' // 正式环境接口地址
}
}
const common = {
}
const config = {...common, ...env[import.meta.env.MODE]}
console.log('mode', import.meta.env.MODE)
console.log('config', config)
export default config
// vite.config.js
export default defineConfig({
...
resolve: {
alias: {
'~': path.resolve(__dirname, './'), // 根路径
'@': path.resolve(__dirname, 'src') // src 路径
}
},
server: {
port: 3000, // 开发环境启动的端口
proxy: {
'/api': {
// 当遇到 /api 路径时,将其转换成 target 的值
target: 'http://xxx.com/api/v1',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '') // 将 /api 重写为空
}
}
}
...
})
新建jsconfig.json配置路径跳转
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"~/*": ["/*"],
"@/*": ["src/*"],
},
"target": "ES6",
"module": "commonjs",
"allowSyntheticDefaultImports": true
},
"exclude": ["node_modules", "dist"]
}
使用别名
// router/index.js
import Index from '@/pages/Index'
import About from '@/pages/About'
// utils/index.js
import config from '~/config'
// App.jsx
import routes from '@/router'
npm i axios -S
// utils/http.js
import axios from 'axios'
import { message } from 'antd'
const http = axios.create()
// 添加请求拦截器
http.interceptors.request.use(function (config) {
// todo...
return config;
}, function (error) {
return Promise.reject(error);
});
// 添加响应拦截器
http.interceptors.response.use(function (response) {
const res = response.data
if (res.code === 9999) {
message.error(res.msg)
} else if (res.code === 401) {
}
return res;
}, function (error) {
message.error('系统错误')
return Promise.reject(error);
})
export default http