天将降大任于是人也,必先苦其心志,劳其筋骨,饿其体肤,空乏其身,行拂乱其所为。——《孟子·告子下》

首先是package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"name": "basic",
"private": true,
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"serve": "vite preview"
},
"dependencies": {
"antd": "^5.25.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.15.0"
},
"devDependencies": {
"@rollup/plugin-replace": "^5.0.2",
"@types/node": "18.x",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@vitejs/plugin-react": "^3.0.1",
"typescript": "^4.9.5",
"vite": "^4.0.4"
}
}

然后是vite.config.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import * as path from "path";
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import rollupReplace from "@rollup/plugin-replace";

// https://vitejs.dev/config/
export default defineConfig({
base: "/", // 如果部署在子路径中,如 "/my-app",请更改为子路径名
server: {
port: 8817,
},
build: {
outDir: "dist", // 确保构建输出到 dist 文件夹
},
plugins: [
rollupReplace({
preventAssignment: true,
values: {
"process.env.NODE_ENV": JSON.stringify("production"), // 确保生产环境变量
},
}),
react(),
],
resolve: process.env.USE_SOURCE
? {
alias: {
"react-router": path.resolve(
__dirname,
"../../packages/react-router/index.ts"
),
"react-router-dom": path.resolve(
__dirname,
"../../packages/react-router-dom/index.tsx"
),
},
}
: {},
});

以及tsconfig.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"compilerOptions": {
"baseUrl": ".",
"target": "ESNext",
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"noEmit": true,
"jsx": "react-jsx",
"importsNotUsedAsValues": "error"
},
"include": ["./src"]
}

接下来是index.html

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>hssw-dinnovation</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

然后是src/main.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import App from "./App";
import Buy from "./pages/Buy";
import Sell from "./pages/Sell";

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route path="buy" element={<Buy />} />
<Route path="sell" element={<Sell />} />
</Route>
</Routes>
</BrowserRouter>
</React.StrictMode>
);

以及src/App.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import React, { useState } from "react";
import { AppstoreOutlined, MailOutlined } from "@ant-design/icons";
import type { MenuProps } from "antd";
import { Menu } from "antd";
import { Outlet, useNavigate } from "react-router-dom";

type MenuItem = Required<MenuProps>["items"][number];

const items: MenuItem[] = [
{
label: "1",
key: "1",
icon: <MailOutlined />,
},
{
label: "2",
key: "2",
icon: <AppstoreOutlined />,
},
];

const App: React.FC = () => {
const [current, setCurrent] = useState("buy");
const navigate = useNavigate();

const onClick: MenuProps["onClick"] = (e) => {
setCurrent(e.key);
navigate(`/${e.key}`);
};

return (
<>
<Menu
onClick={onClick}
selectedKeys={[current]}
mode="horizontal"
items={items}
/>
<Outlet />
</>
);
};

export default App;

pages/Buy.tsx

1
2
3
4
5
6
7
8
9
10
const Buy = () => {
return (
<div>
<h1>买页面</h1>
<p>这里是买页面的内容。</p>
</div>
);
};

export default Buy;

以及pages/Sell.tsx

1
2
3
4
5
6
7
8
9
10
const Sell = () => {
return (
<div>
<h1>卖页面</h1>
<p>这里是卖页面的内容。</p>
</div>
);
};

export default Sell;

然后npm run build

ssh进入服务器,创建新用户和新目录,安装nginx

1
2
3
4
5
6
7
sudo adduser achao
# 修改权限
sudo usermod -aG sudo achao
# 切换用户
su - achao
# 创建目录
mkdir build

dist里的文件上传到build

1
2
achao@server:~$ ls ~/build/
assets index.html

安装nginx并修改权限?

1
2
3
4
sudo apt update
sudo apt install -y nginx
sudo chown -R www-data:www-data /home/achao/build
sudo chmod -R 755 /home/achao/build

配置nginx配置文件

1
vim nano /etc/nginx/sites-available/react-app

内容:

1
2
3
4
5
6
achao@server:~$ cat /etc/nginx/sites-available/react-app
server { listen 3000; server_name _; root /home/achao/build; index index.html; location / { try_files $uri /index.html;
}
location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg|otf|js)$ { expires 6M; access_log off; add_header Cache-Control "public";
}
}

测试配置文件,重启nginx

1
2
sudo nginx -t
sudo systemctl restart nginx

然后访问3000端口即可查看页面