feat: 配置环境变量
This commit is contained in:
parent
deab8f583b
commit
fc2d8691e3
18
Dockerfile
18
Dockerfile
@ -13,15 +13,23 @@ RUN pnpm run build
|
||||
FROM node:18-alpine
|
||||
|
||||
WORKDIR /app
|
||||
# 只拷贝生产需要的文件,保持镜像最小
|
||||
COPY package.json package-lock.json pnpm-lock.yaml ./
|
||||
RUN npm ci --omit=dev && npm cache clean --force
|
||||
|
||||
# 拷贝 Express 服务代码
|
||||
COPY server/ ./server/
|
||||
|
||||
# 从构建阶段拷贝前端产物
|
||||
COPY --from=builder /app/dist ./dist
|
||||
COPY --from=builder /app/server ./server
|
||||
COPY --from=builder /app/package*.json ./
|
||||
COPY --from=builder /app/pnpm-lock.yaml ./
|
||||
RUN npm install -g pnpm && pnpm install --prod --frozen-lockfile
|
||||
|
||||
|
||||
# 暴露端口(与 Express 监听端口一致)
|
||||
EXPOSE 3000
|
||||
|
||||
# 环境变量
|
||||
ENV NODE_ENV=production
|
||||
ENV VITE_SERVICE_PORT=3000
|
||||
|
||||
# 启动 Express 服务(使用 pnpm start 或 node server/index.js)
|
||||
CMD ["pnpm", "start"]
|
||||
# 或直接 CMD ["node", "server/index.js"]
|
||||
@ -10,7 +10,7 @@ services:
|
||||
- "3000:3000" # 映射端口
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- PORT=3000 # 传给 Express 的环境变量
|
||||
- VITE_SERVICE_PORT=3000 # 传给 Express 的环境变量
|
||||
restart: unless-stopped # 容器意外停止后自动重启
|
||||
# 如果需要挂载日志或配置,可以加 volumes
|
||||
# volumes:
|
||||
|
||||
@ -7,9 +7,9 @@
|
||||
"dev": "concurrently \"npm run dev:server\" \"npm run dev:client\"",
|
||||
"dev:client": "vite",
|
||||
"dev:server": "node server/index.js",
|
||||
"start": "node server/index.js",
|
||||
"start": "cross-env NODE_ENV=production node server/index.js",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
"preview": "npm run build && cross-env NODE_ENV=production node server/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.2",
|
||||
@ -17,6 +17,7 @@
|
||||
"@grpc/proto-loader": "^0.8.1",
|
||||
"concurrently": "^10.0.3",
|
||||
"cors": "^2.8.6",
|
||||
"dotenv": "^17.4.2",
|
||||
"element-plus": "^2.14.2",
|
||||
"express": "^5.2.1",
|
||||
"fast-glob": "^3.3.3",
|
||||
@ -27,6 +28,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^6.0.7",
|
||||
"cross-env": "^10.1.0",
|
||||
"sass": "^1.101.0",
|
||||
"unplugin-auto-import": "^21.0.0",
|
||||
"unplugin-vue-components": "^32.1.0",
|
||||
|
||||
71
pnpm-lock.yaml
generated
71
pnpm-lock.yaml
generated
@ -23,6 +23,9 @@ importers:
|
||||
cors:
|
||||
specifier: ^2.8.6
|
||||
version: 2.8.6
|
||||
dotenv:
|
||||
specifier: ^17.4.2
|
||||
version: 17.4.2
|
||||
element-plus:
|
||||
specifier: ^2.14.2
|
||||
version: 2.14.2(vue@3.5.38)
|
||||
@ -48,6 +51,9 @@ importers:
|
||||
'@vitejs/plugin-vue':
|
||||
specifier: ^6.0.7
|
||||
version: 6.0.7(vite@8.1.0(@types/node@26.0.0)(sass@1.101.0)(yaml@2.9.0))(vue@3.5.38)
|
||||
cross-env:
|
||||
specifier: ^10.1.0
|
||||
version: 10.1.0
|
||||
sass:
|
||||
specifier: ^1.101.0
|
||||
version: 1.101.0
|
||||
@ -125,6 +131,9 @@ packages:
|
||||
'@emnapi/wasi-threads@1.2.2':
|
||||
resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==}
|
||||
|
||||
'@epic-web/invariant@1.0.0':
|
||||
resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==}
|
||||
|
||||
'@floating-ui/core@1.7.5':
|
||||
resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==}
|
||||
|
||||
@ -709,6 +718,15 @@ packages:
|
||||
resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==}
|
||||
engines: {node: '>= 0.10'}
|
||||
|
||||
cross-env@10.1.0:
|
||||
resolution: {integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==}
|
||||
engines: {node: '>=20'}
|
||||
hasBin: true
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
css-select@4.3.0:
|
||||
resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
|
||||
|
||||
@ -844,6 +862,10 @@ packages:
|
||||
domutils@3.2.2:
|
||||
resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
|
||||
|
||||
dotenv@17.4.2:
|
||||
resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
dunder-proto@1.0.1:
|
||||
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -1314,6 +1336,9 @@ packages:
|
||||
isarray@2.0.5:
|
||||
resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
|
||||
|
||||
isexe@2.0.0:
|
||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||
|
||||
isobject@2.1.0:
|
||||
resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -1616,6 +1641,10 @@ packages:
|
||||
resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
path-key@3.1.1:
|
||||
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
path-to-regexp@8.4.2:
|
||||
resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==}
|
||||
|
||||
@ -1861,6 +1890,14 @@ packages:
|
||||
setprototypeof@1.2.0:
|
||||
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
shebang-regex@3.0.0:
|
||||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
shell-quote@1.8.4:
|
||||
resolution: {integrity: sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -2247,6 +2284,11 @@ packages:
|
||||
resolution: {integrity: sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
which@2.0.2:
|
||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||
engines: {node: '>= 8'}
|
||||
hasBin: true
|
||||
|
||||
wrap-ansi@7.0.0:
|
||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||
engines: {node: '>=10'}
|
||||
@ -2342,6 +2384,8 @@ snapshots:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@epic-web/invariant@1.0.0': {}
|
||||
|
||||
'@floating-ui/core@1.7.5':
|
||||
dependencies:
|
||||
'@floating-ui/utils': 0.2.11
|
||||
@ -2913,6 +2957,17 @@ snapshots:
|
||||
object-assign: 4.1.1
|
||||
vary: 1.1.2
|
||||
|
||||
cross-env@10.1.0:
|
||||
dependencies:
|
||||
'@epic-web/invariant': 1.0.0
|
||||
cross-spawn: 7.0.6
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
shebang-command: 2.0.0
|
||||
which: 2.0.2
|
||||
|
||||
css-select@4.3.0:
|
||||
dependencies:
|
||||
boolbase: 1.0.0
|
||||
@ -3067,6 +3122,8 @@ snapshots:
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
|
||||
dotenv@17.4.2: {}
|
||||
|
||||
dunder-proto@1.0.1:
|
||||
dependencies:
|
||||
call-bind-apply-helpers: 1.0.2
|
||||
@ -3644,6 +3701,8 @@ snapshots:
|
||||
|
||||
isarray@2.0.5: {}
|
||||
|
||||
isexe@2.0.0: {}
|
||||
|
||||
isobject@2.1.0:
|
||||
dependencies:
|
||||
isarray: 1.0.0
|
||||
@ -3918,6 +3977,8 @@ snapshots:
|
||||
|
||||
pascalcase@0.1.1: {}
|
||||
|
||||
path-key@3.1.1: {}
|
||||
|
||||
path-to-regexp@8.4.2: {}
|
||||
|
||||
pathe@0.2.0: {}
|
||||
@ -4223,6 +4284,12 @@ snapshots:
|
||||
|
||||
setprototypeof@1.2.0: {}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
dependencies:
|
||||
shebang-regex: 3.0.0
|
||||
|
||||
shebang-regex@3.0.0: {}
|
||||
|
||||
shell-quote@1.8.4: {}
|
||||
|
||||
side-channel-list@1.0.1:
|
||||
@ -4714,6 +4781,10 @@ snapshots:
|
||||
gopd: 1.2.0
|
||||
has-tostringtag: 1.0.2
|
||||
|
||||
which@2.0.2:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
wrap-ansi@7.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
|
||||
@ -5,6 +5,7 @@ import grpc from '@grpc/grpc-js'
|
||||
import protoLoader from '@grpc/proto-loader'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import 'dotenv/config';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
@ -241,8 +242,27 @@ app.post('/api/agv/stopRobot', async (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
// ========== 启动 ==========
|
||||
const PORT = 3000
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
const PORT = process.env.VITE_SERVICE_PORT || 3000;
|
||||
|
||||
// ============ 生产环境:托管 Vite 构建产物 ============
|
||||
if (isProd) {
|
||||
const distPath = resolve(__dirname, '../dist');
|
||||
|
||||
// 托管静态文件
|
||||
app.use(express.static(distPath));
|
||||
|
||||
// SPA 回退:所有非 API 请求返回 index.html
|
||||
app.get('*', (req, res) => {
|
||||
res.sendFile(resolve(distPath, 'index.html'));
|
||||
});
|
||||
|
||||
app.post('*', (req, res) => {
|
||||
res.sendFile(resolve(distPath, 'index.html'));
|
||||
});
|
||||
}
|
||||
|
||||
// ========== 启动 =========
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`gRPC 桥接服务已启动: http://localhost:${PORT}`)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
@ -6,7 +6,10 @@ import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
|
||||
import path from 'path'
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
export default defineConfig(({ mode, command }) => {
|
||||
const env = loadEnv(mode, process.cwd())
|
||||
const { VITE_SERVICE_PORT } = env
|
||||
return {
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, 'src')
|
||||
@ -32,7 +35,7 @@ export default defineConfig({
|
||||
port: 5173,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:3001',
|
||||
target: `http://localhost:${VITE_SERVICE_PORT}`,
|
||||
changeOrigin: true
|
||||
}
|
||||
}
|
||||
@ -45,4 +48,5 @@ export default defineConfig({
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Loading…
Reference in New Issue
Block a user