项目预置代码仓库
(1)TypeScript处理;
(2)Scss/css及模块化处理;
(3)Jsx/Tsx处理;
(4)Png/svg处理;
(5)ContextProvider
(6)Router-v6
(7)Axios-模块;
(8)emnu/type/interface;
(9)@路径别名配置;
(9)合并清理无效代码;
具体实现步骤如下:
(1)cd 项目根目录
(2)npm init -y
(3)npm i webpack webpack-cli -D
(4)创建 webpack.config.js
🔩配置开发模式以及出入口:
mode: "production",
entry: ["react-hot-loader/patch", "./src/index.tsx"],
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
},
🔩配置rules及安装各种loader;
(1)babel-loader
(2)ts-loader
(3)css-loader
(4)sass-loader
(5)file-loader
(6)url-loader
rules: [
{
test: /\.(js|jsx)$/,
use: "babel-loader",
exclude: /node_modules/,
},
{
test: /\.ts(x)?$/,
loader: "ts-loader",
exclude: /node_modules/,
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
{
test: /(\.module)?.(sass|scss)$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: {
localIdentName: "[path][name]__[local]--[hash:base64:5]",
},
sourceMap: true,
},
},
"sass-loader",
],
},
{
test: /\.svg$/,
use: "file-loader",
},
{
test: /\.png$/,
use: [
{
loader: "url-loader",
options: {
mimetype: "image/png",
},
},
],
},
],
},
🔩安装三个插件
(1)HtmlWebpackPlugin;
(2)BundleAnalyzerPlugin;
(3)MiniCssExtractPlugin;
plugins: [
new HtmlWebpackPlugin({
templateContent: ({ htmlWebpackPlugin }) =>
'<!DOCTYPE html><html><head><meta charset="utf-8"><title>' +
htmlWebpackPlugin.options.title +
'</title></head><body><div id="app"></div></body></html>',
filename: "index.html",
}),
new BundleAnalyzerPlugin({
analyzerMode: "static",
openAnalyzer: false,
}),
new MiniCssExtractPlugin(),
],
🔩别名配置:
(1)tsconfig.json:
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
},
(2)webpack.config.js:
resolve: {
extensions: [".tsx", ".ts", ".js"],
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
🔩语法识别,可减少导入和支持通用的写法;
tsconfig.json:
"jsx": "react-jsx",
🔩css及scss模块隔离配置:
src下创建style.d.ts,手动让Ts识别
import styles from "./UserInfo.module.scss"这种写法;
style.d.ts内部:
declare module '*.css' {
const styles: { readonly [key: string]: string };
export default styles;
}
declare module '*.scss' {
const styles: { readonly [key: string]: string };
export default styles;
}
🔩Context配置
创建ContextProvider.tsx,⚠️⚠️需要注意是tsx不是ts
import { useReducer } from "react";
import { createContext } from "react"
interface ContentProps{
children:JSX.Element|JSX.Element[]
}
export const ContentContext=createContext<any>({}as any)
const reducer = (state:any, action:any) => {
switch (action.type) {
case "changeToRed":
return {
...state,
colorValue: action.color,
};
case "changeToOrange":
return {
...state,
colorValue: action.color,
};
default:
return state;
}
};
export const ContextProvider=({children}:ContentProps)=>{
const [state, dispatch] = useReducer(reducer,{
colorValue:"",
});
return (
<ContentContext.Provider value={{state,dispatch}}>
{children}
</ContentContext.Provider>
)
}
🔩包裹根组件:
<ContextProvider>
<Router>
<App name="DingDang"/>
</Router>
</ContextProvider>,
🔩组件使用:
const { state, dispatch } = useContext(ContentContext);
dispatch({ type: "changeToRed", color: "red" });
🔩Axios拦截:
import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
axios.interceptors.request.use((config:AxiosRequestConfig) => {
console.log("拦截请求", config);
if(!config)return;
if(localStorage.getItem("token")) {
config.headers!.Authorization = localStorage.getItem("token")??"";
}
return config;
});
axios.interceptors.response.use(
(res: AxiosResponse<any, any>) => {
return res.data;
},
(error) => {
console.log("响应错误结果",error);
if (error && error.response && error.response.status) {
switch (error.response.status) {
case 401:
throw new Error("身份认证失败,请检查权限");
case 404:
throw new Error("未找到该资源");
case 500:
throw new Error("服务器内部错误");
default:
throw new Error("请求失败");
}
} else {
throw new Error("内部错误");
}
}
);
在项目index.js中引入:
axios.defaults.baseURL = "https://api.apiopen.top";
import "./http/axios";
🔩Router使用:
<Routes>
<Route path="/" element={<Home />} />
//默认;
<Route path="/home/*" element={<Home />} />
//带二级路由;
<Route path="/description:id" element={<Description />} />
//带路由参数;
<Route path="/system" element={isAdmin ? <System /> : <p style={{background:"#9b2723",color:"white",height:"70px",lineHeight:"70px",padding:"5px"}}>对不起您无权访问改页面!</p>} />
//带路由权限;
<Route path="*" element={<p>ERROR-PAGE</p>} />
//错误页;
</Routes>
二级路由页面(/home/password):
<Routes>
<Route path="password" element={<Password />} />
</Routes>
接收路由参数:
let {id} =useParams()
console.log("路由传递参数",id);
传递路由参数:
let navigate = useNavigate();
navigate("/description" + 2190867637637);
注意路由模式使用Hash,开启webpack:historyApiFallback:true,
(1)enum
export enum StatusOptions {
Fine = 10,
Urgent = 100,
}
export const StatusLevelValueSet = new Set([StatusOptions.Fine, StatusOptions.Urgent]);
(2)interface
interface Props {
title: string;
value?: string | ComponentType<IconProps> | undefined;
isVisible?: boolean | undefined;
onPress?: (isVisible?: boolean) => void;
}
(3)type
export type UserInfoType = {
id: number;
name: string;
age: number;
adress: string;
};
🔩性能优化(合并清理压缩模块):
optimization: {
usedExports: true,
minimize: true,
concatenateModules: true
},
🔩减少无效代码打包;
package.json:
(1)所有均配置shaking;
"sideEffects": false,
(2)单独保留不进行shaking;
"sideEffects": ["./src/key.js"]
如果一个包中的代码具有一些全局的副作用,不进行shaking操作,进行打包;
如果一个包中的代码是独立无副作用的,进行shaking,打包使用到的部分代码;
🔩运行项目:
npm install
npm start/yarn start
打包项目:
npx webpack