i want to deploy two apps(admin, interview) on same container, same origin. and it has own contextpath '/admin', '/interview'. in case of admin app,on first landing it supposed to redirect '/login' page. it works when i run on my local.
i tried following this article.
when i tried, its seem react apps build correctly in container. also when its browsed by chrome i checked browser network tab and its seem request access to path of static build files.
here is request initiator chain
http://localhost/admin
> http://localhost/admin/
> http://localhost/admin/static/js/main.44b88a4b.js
http://localhost/admin/static/css/main.1270f831.css
but preview tab saying 'You need to enable JavaScript to run this app.' and app throw below html. i check browser setting for javascript, its enabled.
<!doctype html>
<html lang="en">
<head>
<title></title>
<meta property="description" content="" data-id="description"/>
<meta name="keywords" content=""/>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
<meta name="theme-color" content="#000000"/>
<meta property="og:site_name" content=""/>
<meta property="og:description" content="" data-id="og:description"/>
<meta property="og:title" content="" data-id="og:title"/>
<meta property="og:url" content=""/>
<meta property="og:type" content="website"/>
<meta property="og:locale:alternate" content="ko_KR"/>
<meta property="og:image" content="/admin/kakao_thumbnail.png"/>
<meta name="naver-site-verification" content=""/>
<link rel="icon" href="/admin/favicon.ico"/>
<link rel="shortcut icon" href="/admin/android-chrome-192x192"/>
<link rel="apple-touch-icon" href="/admin/apple-touch-icon.png"/>
<link rel="/manifest" href="/admin/manifest.json"/>
<link rel="canonical" data-id="canonical-link" data-rh="true"/>
<script defer="defer" src="/admin/static/js/main.44b88a4b.js"></script>
<link href="/admin/static/css/main.1270f831.css" rel="stylesheet">
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
here is my settings. please let me know if some of these are wrong or missed. each package.json of apps has definition like "homepage": "/admin", and "homepage": "/interview",
directories
>admin
- app source
- Dockerfile
- package.json
>inerview
- app source
- Dockerfile
- package.json
>nginx
- nginx.conf
- site.conf
docker-compose-test.yml
docker-compose-test.yml
version: '3.8'
services:
nginx:
image: nginx
ports:
- "80:80"
restart: always
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/site.conf:/etc/nginx/conf.d/default.conf
- admin:/usr/share/nginx/html/admin
- interview:/usr/share/nginx/html/interview
admin:
build:
context: admin
dockerfile: Dockerfile
volumes:
- admin:/app/server/client
interview:
build:
context: interview
dockerfile: Dockerfile
volumes:
- interview:/app/build
volumes:
admin:
interview:
Dockerfile (each directory of apps has same Dockerfile)
# build environment
FROM node:lts-alpine
WORKDIR /app
COPY . ./
RUN npm install
RUN npm run build
nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
}
site.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
location /admin {
root /usr/share/nginx/html/;
index index.html;
try_files $uri $uri/ /admin/index.html;
}
location /interview {
root /usr/share/nginx/html/;
index index.html;
try_files $uri $uri/ /interview/index.html;
}
}
admin's App.tsx return
<BrowserRouter>
<Helmet
titleTemplate=""
defaultTitle=""
htmlAttributes={{ lang: i18n.language }}
>
<meta name="keywords" content="" />
</Helmet>
<ThemeConfig>
<GlobalStyles />
<Router />
</ThemeConfig>
</BrowserRouter>
admin's routes.tsx
const CatchAllRoutes: any[] = [
{
path: '/404',
element: <Page404 />,
},
{ path: '*', element: <Navigate to="/404" replace /> },
{ path: '/test', element: <SurveyServiceListPage /> },
];
const AuthRoute = {
path: '/',
element: <AuthLayout />,
children: [
{ path: '/', element: <Navigate to="/login" /> },
{ path: 'login', element: <LoginPage /> },
{ path: 'account-retrieval/:mode', element: <AccountRetrievalPage /> },
],
};
...
export default function Router() {
const { accessToken } = useRecoilValue(authState);
const { state, contents: user } = useRecoilValueLoadable(userState);
let routes: any[] = [];
if (state === 'loading' && !(user as any)?.id) {
routes = [{ path: '*', element: <Spinner loading={true} /> }];
} else {
routes = getUserRoutes(user, accessToken);
}
return useRoutes(routes);
}
function getUserRoutes(user, token) {
if (!user?.id && !token) {
return LoggedOutRoutes.concat(CatchAllRoutes);
}
if ([UserType.SUB_ADMIN, UserType.SUPER_ADMIN].includes(user?.type)) {
return AdminLoggedInRoutes.concat(CatchAllRoutes);
}
if (user?.type === UserType.CUSTOMER_MANAGER) {
return CustomerManagerLoggedInRoutes.concat(CatchAllRoutes);
}
if (user?.type === UserType.CUSTOMER_STAFF) {
return CustomerStaffLoggedInRoutes.concat(CatchAllRoutes);
}
return AdminLoggedInRoutes.concat(CatchAllRoutes);
}
interview's App.tsx return
<ChakraProvider resetCSS={true} theme={theme}>
<BrowserRouter>
<Helmet titleTemplate="" defaultTitle="">
<meta name="keywords" content="" />
</Helmet>
<Router />
</BrowserRouter>
</ChakraProvider>
interview's routes.tsx
export default function Router() {
const routes = [
{ path: '/selfcheck', element: <WelcomePage /> },
{ path: '/symptom', element: <SymptomPage /> },
{ path: '/noCombination', element: <NoCombinationPage /> },
{ path: '/:symptomId', element: <LandingPage /> },
{ path: '/start', element: <StartPage /> },
{ path: '/finish', element: <FinishPage /> },
{ path: '/expired', element: <ExpiredPage /> },
{ path: '/completed', element: <CompletedPage /> },
{ path: '/orthopedy', element: <MultisurveyLandingPage /> },
{ path: '/selectSymptom', element: <SelectSymptomPage /> },
{ path: '/surveyList', element: <SurveyListPage /> },
{
path: '/questionaire/:symptomId',
element: <QuestionairePage />,
},
{ path: '/404/', element: <Page404 /> },
{ path: '*', element: <Navigate to="/404/" replace /> },
];
return useRoutes(routes);