Skip to content
This repository was archived by the owner on Jan 17, 2025. It is now read-only.

Commit a53ae4b

Browse files
committed
Optimize docker build image size
1 parent 322b30a commit a53ae4b

File tree

10 files changed

+135
-77
lines changed

10 files changed

+135
-77
lines changed

Dockerfile

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
1-
FROM node:lts-alpine
1+
FROM node:lts-alpine as builder
22

33
WORKDIR /app
44

55
COPY ./.* ./
66
COPY ./*.js* ./
77
COPY ./src ./src
88
COPY ./public ./public
9+
10+
RUN npm install && npm run build
11+
12+
FROM nginx:stable-alpine
13+
914
COPY entrypoint.sh /entrypoint.sh
15+
RUN rm -rf /etc/nginx/conf.d/default.conf /usr/share/nginx/html/* \
16+
&& chmod +x /entrypoint.sh
1017

11-
RUN apk add --no-cache nginx \
12-
&& chmod +x /entrypoint.sh \
13-
&& npm install
18+
COPY nginx.conf /etc/nginx/conf.d/default.conf
19+
COPY --from=builder /app/build /usr/share/nginx/html
1420

1521
EXPOSE 8080
22+
VOLUME [ "/etc/nginx" ]
23+
VOLUME [ "/usr/share/nginx/html" ]
1624
ENTRYPOINT [ "sh", "-c", "/entrypoint.sh" ]

README.md

+17-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ $ npm run build
127127

128128
### 若使用 Docker 部署
129129

130-
若使用 Docker 部署,可透过以下步骤保持更新:
130+
若是使用传统 `docker run` 指令部署的版本,可透过以下步骤保持更新:
131131

132132
1. 删除旧容器
133133
```bash
@@ -147,6 +147,22 @@ $ docker run -d \
147147
ghcr.io/bclswl0827/chatgemini
148148
```
149149

150+
若是使用 `docker-compose` 指令部署的版本,可透过以下步骤保持更新:
151+
152+
1. 进入 `docker-compose.yml` 所在目录
153+
2. 拉取最新镜像
154+
```bash
155+
$ docker-compose pull
156+
```
157+
3. 重启容器
158+
```bash
159+
$ docker-compose up -d --remove-orphans
160+
```
161+
1. 移除旧镜像(可选)
162+
```bash
163+
$ docker image prune
164+
```
165+
150166
### 若使用 Vercel 部署
151167

152168
使用 Vercel 部署的项目,平台会在用户 GitHub 仓库创建一个新仓库,而不是 Fork 本仓库,因此无法正确检测更新。请按照下列步骤手动更新:

entrypoint.sh

+9-41
Original file line numberDiff line numberDiff line change
@@ -8,50 +8,18 @@ fi
88
# Create Nginx config
99
if [ "x${REACT_APP_GEMINI_API_URL}" = "x__use_nginx__" ]; then
1010
REACT_APP_GEMINI_API_URL="/api"
11-
cat << EOF > /etc/nginx/http.d/default.conf
12-
server {
13-
listen 8080 default_server;
14-
listen [::]:8080 default_server;
15-
16-
location / {
17-
root /app/build;
18-
index index.html index.htm;
19-
}
20-
21-
location /api {
22-
proxy_http_version 1.1;
23-
proxy_read_timeout 86400s;
24-
proxy_cache off;
25-
proxy_buffering off;
26-
proxy_pass https://generativelanguage.googleapis.com/;
27-
}
28-
}
29-
EOF
30-
else
31-
cat << EOF > /etc/nginx/http.d/default.conf
32-
server {
33-
listen 8080 default_server;
34-
listen [::]:8080 default_server;
35-
36-
location / {
37-
root /app/build;
38-
index index.html index.htm;
39-
}
40-
}
41-
EOF
4211
fi
4312

44-
# Set up env variables
45-
cat << EOF > .env
46-
REACT_APP_TITLE_SITE="${REACT_APP_TITLE_SITE}"
47-
REACT_APP_TITLE_HEADER="${REACT_APP_TITLE_HEADER}"
48-
REACT_APP_GEMINI_API_SSE="${REACT_APP_GEMINI_API_SSE}"
49-
REACT_APP_GEMINI_API_KEY="${REACT_APP_GEMINI_API_KEY}"
50-
REACT_APP_GEMINI_API_URL="${REACT_APP_GEMINI_API_URL}"
51-
REACT_APP_PASSCODE_MD5="${REACT_APP_PASSCODE_MD5}"
13+
tee /usr/share/nginx/html/env.json << EOF
14+
{
15+
"REACT_APP_PASSCODE_MD5": "${REACT_APP_PASSCODE_MD5}",
16+
"REACT_APP_TITLE_SITE": "${REACT_APP_TITLE_SITE}",
17+
"REACT_APP_TITLE_HEADER": "${REACT_APP_TITLE_HEADER}",
18+
"REACT_APP_GEMINI_API_SSE": "${REACT_APP_GEMINI_API_SSE}",
19+
"REACT_APP_GEMINI_API_KEY": "${REACT_APP_GEMINI_API_KEY}",
20+
"REACT_APP_GEMINI_API_URL": "${REACT_APP_GEMINI_API_URL}"
21+
}
5222
EOF
5323

54-
# Build and start Nginx
55-
npm run build
5624
echo "Nginx started."
5725
nginx -g 'daemon off;'

nginx.conf

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
server {
2+
listen 8080 default_server;
3+
listen [::]:8080 default_server;
4+
5+
location / {
6+
root /usr/share/nginx/html;
7+
index index.html index.htm;
8+
}
9+
10+
location /api {
11+
proxy_http_version 1.1;
12+
proxy_read_timeout 86400s;
13+
proxy_cache off;
14+
proxy_buffering off;
15+
proxy_pass https://generativelanguage.googleapis.com/;
16+
}
17+
}

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "chatgemini",
3-
"version": "0.4.6",
3+
"version": "0.4.7",
44
"homepage": ".",
55
"private": true,
66
"dependencies": {

public/index.html

+42-4
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,55 @@
33
<head>
44
<meta charset="utf-8" />
55
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6-
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
76
<meta
8-
name="description"
9-
content="ChatGemini is a chatbot that uses Google's Generative AI to generate responses to your messages."
7+
name="viewport"
8+
content="width=device-width, initial-scale=1, user-scalable=no"
109
/>
1110
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
1211
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
13-
<title>ChatGemini</title>
12+
<style>
13+
.loading {
14+
width: 100%;
15+
height: 100%;
16+
display: flex;
17+
position: fixed;
18+
align-items: center;
19+
flex-direction: column;
20+
justify-content: center;
21+
}
22+
23+
.loading span {
24+
color: #1f2937;
25+
margin-top: 20px;
26+
font-weight: 500;
27+
}
28+
29+
.loading svg {
30+
animation: rotate 2s linear infinite;
31+
}
32+
33+
@keyframes rotate {
34+
100% {
35+
transform: rotate(360deg);
36+
}
37+
}
38+
</style>
1439
</head>
1540
<body>
1641
<noscript>You need to enable JavaScript to run this app.</noscript>
42+
<div class="loading">
43+
<svg
44+
xmlns="http://www.w3.org/2000/svg"
45+
viewBox="0 0 512 512"
46+
fill="#6b21a8"
47+
width="60px"
48+
>
49+
<path
50+
d="M304 48a48 48 0 1 0 -96 0 48 48 0 1 0 96 0zm0 416a48 48 0 1 0 -96 0 48 48 0 1 0 96 0zM48 304a48 48 0 1 0 0-96 48 48 0 1 0 0 96zm464-48a48 48 0 1 0 -96 0 48 48 0 1 0 96 0zM142.9 437A48 48 0 1 0 75 369.1 48 48 0 1 0 142.9 437zm0-294.2A48 48 0 1 0 75 75a48 48 0 1 0 67.9 67.9zM369.1 437A48 48 0 1 0 437 369.1 48 48 0 1 0 369.1 437z"
51+
/>
52+
</svg>
53+
<span>Loading...</span>
54+
</div>
1755
<div id="root"></div>
1856
</body>
1957
</html>

src/App.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ const App = () => {
196196
};
197197

198198
useEffect(() => {
199+
document.querySelector(".loading")?.remove();
199200
if (!hasLogined && !!passcodes.length) {
200201
document.title = `登入 - ${site}`;
201202
}

src/config/global.tsx

+32-22
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,42 @@
1-
const {
2-
REACT_APP_PASSCODE_MD5,
3-
REACT_APP_TITLE_SITE,
4-
REACT_APP_TITLE_HEADER,
5-
REACT_APP_GEMINI_API_KEY,
6-
REACT_APP_GEMINI_API_URL,
7-
REACT_APP_GEMINI_API_SSE,
8-
} = process.env;
1+
const env = Object.keys(process.env)
2+
.filter((key) => key.startsWith("REACT_APP_"))
3+
.reduce((env: Record<string, string | null>, key) => {
4+
env[key] = process.env[key] ?? null;
5+
return env;
6+
}, {});
97

10-
const keys = REACT_APP_GEMINI_API_KEY
11-
? REACT_APP_GEMINI_API_KEY.split("|").map((v) => v.trim())
12-
: [""];
13-
const passcodes = REACT_APP_PASSCODE_MD5
14-
? REACT_APP_PASSCODE_MD5?.split("|").map((v) =>
15-
v.trim().toLocaleLowerCase()
16-
)
17-
: [];
8+
if (!Object.keys(env).length) {
9+
const xhr = new XMLHttpRequest();
10+
xhr.open("GET", "/env.json", false);
11+
try {
12+
xhr.send();
13+
const data = JSON.parse(xhr.responseText);
14+
Object.assign(env, data);
15+
} catch (e) {
16+
Object.assign(env, {});
17+
}
18+
}
19+
20+
const keys = env["REACT_APP_GEMINI_API_KEY"]
21+
?.split("|")
22+
.map((v) => v.trim()) ?? [""];
23+
const passcodes =
24+
env["REACT_APP_PASSCODE_MD5"]
25+
?.split("|")
26+
.filter((v) => !!v.length)
27+
.map((v) => v.trim().toLocaleLowerCase()) ?? [];
1828

1929
export const globalConfig = {
2030
passcodes,
2131
keys,
2232
title: {
23-
site: !!REACT_APP_TITLE_SITE?.length
24-
? REACT_APP_TITLE_SITE
33+
site: !!env["REACT_APP_TITLE_SITE"]?.length
34+
? env["REACT_APP_TITLE_SITE"]
2535
: "ChatGemini",
26-
header: !!REACT_APP_TITLE_HEADER?.length
27-
? REACT_APP_TITLE_HEADER
36+
header: !!env["REACT_APP_TITLE_HEADER"]?.length
37+
? env["REACT_APP_TITLE_HEADER"]
2838
: "Gemini Pro",
2939
},
30-
api: REACT_APP_GEMINI_API_URL,
31-
sse: REACT_APP_GEMINI_API_SSE === "false" ? false : true,
40+
api: env["REACT_APP_GEMINI_API_URL"],
41+
sse: env["REACT_APP_GEMINI_API_SSE"] === "false" ? false : true,
3242
};

src/helpers/createAiObj.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { GoogleGenerativeAI as OfficalGoogleGenerativeAI } from "@google/generative-ai";
22
import { GoogleGenerativeAI as thirdPartyGoogleGenerativeAI } from "@fuyun/generative-ai";
33

4-
export const createAiObj = (key: string, api?: string) => {
5-
if (api) {
4+
export const createAiObj = (key: string, api: string | null) => {
5+
if (api !== null) {
66
const ai = new thirdPartyGoogleGenerativeAI(key, api) as unknown;
77
return ai as OfficalGoogleGenerativeAI;
88
}

0 commit comments

Comments
 (0)