7th_fix port
This commit is contained in:
@@ -15,8 +15,8 @@ NEXT_PUBLIC_APP_VERSION="1.0.0"
|
||||
# ===========================================
|
||||
|
||||
# 後端 API 基本網址
|
||||
NEXT_PUBLIC_API_URL=http://localhost:5000
|
||||
NEXT_PUBLIC_BACKEND_URL=http://localhost:5000
|
||||
NEXT_PUBLIC_API_URL=http://localhost:12011
|
||||
NEXT_PUBLIC_BACKEND_URL=http://localhost:12011
|
||||
|
||||
# API 版本
|
||||
NEXT_PUBLIC_API_VERSION=v1
|
||||
@@ -146,7 +146,7 @@ NEXT_PUBLIC_REACT_QUERY_DEVTOOLS=true
|
||||
# ===========================================
|
||||
|
||||
# CORS 設定 (僅供參考,實際由後端控制)
|
||||
NEXT_PUBLIC_ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5000
|
||||
NEXT_PUBLIC_ALLOWED_ORIGINS=http://localhost:12012,http://localhost:12011
|
||||
|
||||
# CSP 設定提示
|
||||
NEXT_PUBLIC_CSP_ENABLED=false
|
||||
|
@@ -15,8 +15,8 @@ NEXT_PUBLIC_APP_VERSION="1.0.0"
|
||||
# ===========================================
|
||||
|
||||
# 後端 API 基本網址
|
||||
NEXT_PUBLIC_API_URL=http://localhost:5000
|
||||
NEXT_PUBLIC_BACKEND_URL=http://localhost:5000
|
||||
NEXT_PUBLIC_API_URL=http://localhost:12011
|
||||
NEXT_PUBLIC_BACKEND_URL=http://localhost:12011
|
||||
|
||||
# API 版本
|
||||
NEXT_PUBLIC_API_VERSION=v1
|
||||
@@ -146,7 +146,7 @@ NEXT_PUBLIC_REACT_QUERY_DEVTOOLS=true
|
||||
# ===========================================
|
||||
|
||||
# CORS 設定 (僅供參考,實際由後端控制)
|
||||
NEXT_PUBLIC_ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5000
|
||||
NEXT_PUBLIC_ALLOWED_ORIGINS=http://localhost:12012,http://localhost:12011
|
||||
|
||||
# CSP 設定提示
|
||||
NEXT_PUBLIC_CSP_ENABLED=false
|
||||
|
@@ -35,9 +35,9 @@ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
EXPOSE 12012
|
||||
|
||||
ENV PORT 3000
|
||||
ENV PORT 12012
|
||||
ENV HOSTNAME "0.0.0.0"
|
||||
|
||||
CMD ["node", "server.js"]
|
@@ -1,16 +1,59 @@
|
||||
const crypto = require('crypto')
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
swcMinify: true,
|
||||
output: 'standalone',
|
||||
env: {
|
||||
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:5000',
|
||||
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:12011',
|
||||
},
|
||||
webpack: (config, { dev, isServer }) => {
|
||||
// 在生產環境中禁用 HMR 相關功能
|
||||
if (!dev && !isServer) {
|
||||
config.optimization = {
|
||||
...config.optimization,
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
cacheGroups: {
|
||||
default: false,
|
||||
vendors: false,
|
||||
framework: {
|
||||
chunks: 'all',
|
||||
name: 'framework',
|
||||
test: /(?<!node_modules.*)[\\/]node_modules[\\/](react|react-dom|scheduler|prop-types|use-subscription)[\\/]/,
|
||||
priority: 40,
|
||||
enforce: true,
|
||||
},
|
||||
lib: {
|
||||
test(module) {
|
||||
return module.size() > 160000 && /node_modules[/\\]/.test(module.identifier())
|
||||
},
|
||||
name(module) {
|
||||
const hash = crypto.createHash('sha1')
|
||||
hash.update(module.identifier())
|
||||
return hash.digest('hex').substring(0, 8)
|
||||
},
|
||||
priority: 30,
|
||||
minChunks: 1,
|
||||
reuseExistingChunk: true,
|
||||
},
|
||||
commons: {
|
||||
name: 'commons',
|
||||
minChunks: 2,
|
||||
priority: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
return config
|
||||
},
|
||||
async rewrites() {
|
||||
return [
|
||||
{
|
||||
source: '/api/:path*',
|
||||
destination: `${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:5000'}/api/:path*`,
|
||||
destination: `${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:12011'}/api/:path*`,
|
||||
},
|
||||
]
|
||||
},
|
||||
|
@@ -3,9 +3,9 @@
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"dev": "next dev -p 12012",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"start": "next start -p 12012",
|
||||
"lint": "next lint",
|
||||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import type { Metadata, Viewport } from 'next';
|
||||
import { Inter } from 'next/font/google';
|
||||
import { Providers } from '@/providers';
|
||||
import EnvironmentWrapper from '@/components/EnvironmentWrapper';
|
||||
import './globals.css';
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] });
|
||||
@@ -31,9 +32,11 @@ export default function RootLayout({
|
||||
return (
|
||||
<html lang="zh-TW" suppressHydrationWarning>
|
||||
<body className={inter.className}>
|
||||
<Providers>
|
||||
{children}
|
||||
</Providers>
|
||||
<EnvironmentWrapper>
|
||||
<Providers>
|
||||
{children}
|
||||
</Providers>
|
||||
</EnvironmentWrapper>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
77
frontend/src/components/EnvironmentWrapper.tsx
Normal file
77
frontend/src/components/EnvironmentWrapper.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect } from 'react'
|
||||
|
||||
interface EnvironmentWrapperProps {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
export default function EnvironmentWrapper({ children }: EnvironmentWrapperProps) {
|
||||
useEffect(() => {
|
||||
// 在生產環境中禁用 HMR 和開發工具
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
// 禁用 React DevTools 提示
|
||||
if (typeof window !== 'undefined') {
|
||||
const consoleWarn = console.warn
|
||||
const consoleLog = console.log
|
||||
|
||||
console.warn = (...args: any[]) => {
|
||||
const message = args[0]
|
||||
if (typeof message === 'string' &&
|
||||
(message.includes('Download the React DevTools') ||
|
||||
message.includes('React DevTools'))) {
|
||||
return
|
||||
}
|
||||
consoleWarn.apply(console, args)
|
||||
}
|
||||
|
||||
console.log = (...args: any[]) => {
|
||||
const message = args[0]
|
||||
if (typeof message === 'string' &&
|
||||
(message.includes('Download the React DevTools') ||
|
||||
message.includes('React DevTools'))) {
|
||||
return
|
||||
}
|
||||
consoleLog.apply(console, args)
|
||||
}
|
||||
}
|
||||
|
||||
// 阻止 HMR WebSocket 連接嘗試
|
||||
if (typeof window !== 'undefined') {
|
||||
const originalWebSocket = window.WebSocket
|
||||
window.WebSocket = class extends WebSocket {
|
||||
constructor(url: string | URL, protocols?: string | string[]) {
|
||||
const urlString = url.toString()
|
||||
|
||||
// 阻止 HMR 相關的 WebSocket 連接
|
||||
if (urlString.includes('_next/webpack-hmr') ||
|
||||
urlString.includes('sockjs-node') ||
|
||||
urlString.includes('hot-update')) {
|
||||
console.warn('HMR WebSocket connection blocked in production environment')
|
||||
// 創建一個假的 WebSocket 以避免錯誤
|
||||
super('ws://localhost:1')
|
||||
this.close()
|
||||
return this
|
||||
}
|
||||
|
||||
super(url, protocols)
|
||||
}
|
||||
} as any
|
||||
}
|
||||
}
|
||||
|
||||
// 環境檢查和警告
|
||||
if (process.env.NODE_ENV === 'development' && typeof window !== 'undefined') {
|
||||
console.info('🔧 Development mode detected')
|
||||
console.info('📍 Frontend running on port:', window.location.port)
|
||||
console.info('🔗 API URL:', process.env.NEXT_PUBLIC_API_URL)
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'production' && typeof window !== 'undefined') {
|
||||
console.info('🚀 Production mode detected')
|
||||
console.info('✅ HMR and dev tools have been disabled')
|
||||
}
|
||||
}, [])
|
||||
|
||||
return <>{children}</>
|
||||
}
|
Reference in New Issue
Block a user