赞
踩
create-react-app脚手架创建typescript项目
$ npx create-react-app my-react --template typescript
安装craco
$ yarn add @craco/craco
项目根目录创建craco配置文件: craco.config.js 或者.cracorc
// 配置内容 const { whenProd, loaderByName } = require('@craco/craco'); const path = require('path'); const CracoLessPlugin = require('craco-less'); // 加载less const sassResourcesLoader = require('craco-sass-resources-loader'); // 全局加载sass文件 const WebpackBar = require('webpackbar'); // 打包进度条 const TerserPlugin = require('terser-webpack-plugin'); // 代码压缩: 清除日志|特定函数等 module.exports = { webpack: { alias: { '@': path.resolve(__dirname, 'src'), '@api': path.resolve(__dirname, 'src/api'), '@hooks': path.resolve(__dirname, 'src/hooks'), '@pages': path.resolve(__dirname, 'src/pages'), '@common': path.resolve(__dirname, 'src/common'), '@component': path.resolve(__dirname, 'src/components'), }, plugins: [ new WebpackBar(), ...whenProd( () => [ new TerserPlugin({ terserOptions: { sourceMap: true, compress: { drop_console: whenProd(() => true), // 生产环境中清除console.*这些函数的调用 drop_debugger: whenProd(() => true), // 生产环境中清除debugger pure_funcs: ['console.log'], // 干掉特定的函数比如console.info,那用pure_funcs来处理 }, format: { comments: false, //删除注释 }, }, }), ], [] ), ], }, plugins: [ { plugin: CracoLessPlugin, options: { lessLoaderOptions: { lessOptions: { modifyVars: {}, // 定义变量 javascriptEnabled: true, }, }, modifyLessModuleRule(lessModuleRule, context) { lessModuleRule.test = /\.module\.(less)$/; const cssLoader = lessModuleRule.use.find(loaderByName('css-loader')); cssLoader.options.importLoaders = 4; cssLoader.options.modules = { localIdentName: '[local]_[hash:base64:5]', }; return lessModuleRule; }, }, }, { plugin: sassResourcesLoader, options: { resources: [ './src/common/scss/public.scss', './src/common/scss/variable.scss', ], }, }, ], devServer: (devServerConfig) => { return { ...devServerConfig, proxy: { '/api': { target: 'http://xxx.cn', changeOrigin: true, pathRewrite: { '^/api': '', }, }, }, }; }, };
配置启动命令(package.json):
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject"
},
配置alias(路径别名)
// .cracorc.js webpack: { alias: { '@': path.resolve(__dirname, 'src'), '@pages': path.resolve(__dirname, 'src/pages'), '@common': path.resolve(__dirname, 'src/common'), '@component': path.resolve(__dirname, 'src/components'), }, } // tsconfig.json { "compilerOptions": { "target": "es5", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx" }, "extends": "./path.tsconfig.json", // 添加路径别名配置 "include": ["src"] } // path.tsconfig.json { "compilerOptions": { "baseUrl": "./", "paths": { "@/*": ["src/*"], "@pages/*": ["src/pages/*"], "@common/*": ["src/common/*"], "@component/*": ["src/components"] } } }
配置打包进度条(webpackbar)
// .cracorc.js
const WebpackBar = require('webpackbar'); // 打包进度条
module.exports = {
webpack: {
plugins: [new WebpackBar()],
}
}
安装插件terser-webpack-plugin:
$ yarn add terser-webpack-plugin -D
配置日志打印
// .cracorc.js const TerserPlugin = require('terser-webpack-plugin'); // 清除日志|特定函数等 module.exports = { webpack: { plugins: [ new TerserPlugin({ terserOptions: { sourceMap: true, compress: { drop_console: whenProd(() => true), // 干生产环境中清除console.*这些函数的调用 drop_debugger: whenProd(() => true), // 生产环境中清除debugger pure_funcs: ['console.log'], // 干掉特定的函数比如console.info,那用pure_funcs来处理 }, format: { comments: false, //删除注释 }, }, }), ], } }
安装eslint
$ yarn add eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin -D
创建.eslintrc.js配置文件
module.exports = { parser: '@typescript-eslint/parser', extends: ['plugin:@typescript-eslint/recommended', 'prettier'], plugins: ['@typescript-eslint', 'react', 'prettier'], rules: { // // hooks依赖项不能为空 'react-hooks/exhaustive-deps': 'off', 'no-console': 'warn', // 缩进2 indent: 'off', // 使用 === 替代 == eqeqeq: [2, 'allow-null'], 'no-unused-vars': 'off', }, };
安装prettier
$ yarn add prettier eslint-config-prettier eslint-plugin-prettier -D
创建.prettierrc文件
{
"semi": true,
"singleQuote": true,
"tabWidth": 2
}
$ yarn add sass-loader node-sass
使用craco引入全局scss
安装sass
$ yarn add -D craco-sass-resources-loader
// .cracorc.js
const sassResourcesLoader = require('craco-sass-resources-loader');
plugins: [
{
plugin: sassResourcesLoader,
options: {
resources: [
'./src/common/scss/public.scss', // 全局样式
'./src/common/scss/variable.scss', // 全局变量
],
},
},
]
安装less
$ yarn add craco-less -S
$ yarn add less less-loader -D
craco配置less (注意: 将less配置放在sass)
注意: 将less配置放置于sass配置前, 使用antd的情况下控制台报错: Failed to parse source map: ‘webpack://antd/./components/time-picker/style/index.less’ URL is not supported,
猜测可能是sass-loader与less(因为antd使用less样式,自己想使用sass,所以都安装了)起了冲突
// .cracorcjs module.exports = { webpack: {}, plugins: [ { plugin: CracoLessPlugin, options: { lessLoaderOptions: { lessOptions: { modifyVars: {}, // 定义变量 javascriptEnabled: true, }, }, modifyLessModuleRule(lessModuleRule, context) { lessModuleRule.test = /\.module\.(less)$/; const cssLoader = lessModuleRule.use.find(loaderByName('css-loader')); cssLoader.options.importLoaders = 4; cssLoader.options.modules = { localIdentName: '[local]_[hash:base64:5]', }; return lessModuleRule; }, }, }, { plugin: sassResourcesLoader, options: { resources: [ './src/common/scss/public.scss', './src/common/scss/variable.scss', ], }, }, ], }
安装axios
$ yarn add axios
配置跨域
// .cracorc.js devServer: (devServerConfig) => { return { ...devServerConfig, proxy: { '/api': { target: 'http://xxx.cn', changeOrigin: true, pathRewrite: { '^/api': '', }, }, }, }; } // 请求接口 axios.get('api/manage/code') 实际访问地址: http://xxx.cn/manage/code
安装ant design
$ yarn add antd
引入样式文件
// index.tsx import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; import { ConfigProvider } from 'antd'; // antd全局配置插件 import zhCN from 'antd/es/locale/zh_CN'; // antd中文包 import 'moment/locale/zh-cn'; // 日期选择中文 import 'antd/dist/antd.css'; // antd通用样式 // import { Button } from 'antd'; // 按需引入插件 const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement ); root.render( <React.StrictMode> <ConfigProvider locale={zhCN}> <App /> </ConfigProvider> </React.StrictMode> );
安装react-router-dom
$ yarn add react-router-dom
根组件index.tsx引入路由
import React from 'react'; import ReactDOM from 'react-dom/client'; import { BrowserRouter, Route, Routes } from 'react-router-dom'; import App from './App'; import reportWebVitals from './reportWebVitals'; import { ConfigProvider } from 'antd'; import zhCN from 'antd/es/locale/zh_CN'; import 'moment/locale/zh-cn'; // 日期选择中文 import 'antd/dist/antd.css'; import Test from './pages/test'; import Home from './pages/home'; const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement ); root.render( // <React.StrictMode> <ConfigProvider locale={zhCN}> <BrowserRouter> <Routes> <Route path="/" element={<App />}> <Route path="test" element={<Test />} /> <Route path="home" element={<Home />} /> </Route> <Route path="/system" element={<System />} /> {/* 当匹配到/redirect-path路由时,重定向到/system */} <Route path="/redirect-path" element={<Navgate to={'/system'} />} /> </Routes> </BrowserRouter> </ConfigProvider> // </React.StrictMode> ); // 注意: 不要在存在子路由的路由中使用重定向,否则会无限循环匹配而错误,如: // 当匹配到路由/root时,重定向到/other, 但是/root/test也会被匹配从而重定向 <Route path="/root" element={<Navgate to={'/other'} />}> <Route path="test" element={<Test />} /> <Route path="home" element={<Home />} /> </Route> <Route path="/other" element={<Other />} />
安装redux:
yarn add @reduxjs/toolkit
yarn add react-redux
创建store
src/store/login/loginSlice.ts
import { createSlice } from '@reduxjs/toolkit'; const { actions, reducer: LoginReducer } = createSlice({ // 命名空间,作为action type前缀 name: 'login', // 初始化状态数据 initialState: { token: 'test.token', userInfo: {}, // 用户信息 routeList: [], // 用户路由 }, // reducer更新函数 dispatch使用的action函数 reducers: { setToken: (state, { payload }) => { state.token = payload; }, }, }); // 异步操作 export const asyncOption = (payload: any) => { return async (dispatch: any, getState: any) => { setTimeout(() => { dispatch(setToken(payload)); }, 3000); }; }; // 导出action函数 export const { setToken } = actions; // 导出reducer, 创建store export default LoginReducer;
src/store/index.ts
// 创建store
import { configureStore } from '@reduxjs/toolkit';
import LoginReducer from '@/store/login/loginSlice';
export const store = configureStore({
reducer: {
login: LoginReducer,
},
});
// 使用redux状态 import React from 'react'; import { Button } from 'antd'; import { setToken } from '@/store/login/loginSlice'; import { useDispatch, useSelector } from 'react-redux'; import './index.scss'; export default function Test() { const dispatch = useDispatch(); const { token } = useSelector((state: any) => state.login); return ( <div className="box"> token: {token} <Button type="primary" onClick={() => dispatch(setToken(new Date().getTime()))} > antd Button </Button> </div> ); }
安装dayjs
$ yarn add dayjs
使用dayjs
import dayjs from 'dayjs';
// 获取时间戳
const date = dayjs('2022-08-16 22:32:45').format('YYYY-MM-DD'); // 2022-08-16
cosnt prevWeek = dayjs(date).subtract(1, 'week'); // 2022-08-09
const dateTime = dayjs(prevWeek).valueOf(); // 获取指定日期的时间戳(13位) 1660003200000
安装lodash
$ yarn add lodash
简单实用
import { useEffect, useRef } from 'react'; import _ from 'lodash'; export default function Test() { const complexObj = useRef<any>({ age: 18, date: new Date(), }); useEffect(() => { const cloneObj = JSON.parse(JSON.stringify(complexObj.current)); // 使用JSON方式深拷贝数据, date被转化为字符串 const lodashObj = _.cloneDeep(complexObj.current); // 使用lodash深拷贝数据 date值与源数据一致(Date类型) console.log(cloneObj, lodashObj, complexObj.current); }, []); return ( <div className="box"> <div className="inner">Test page!</div> </div> ); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。