From 9a7852c8a2624b21ea76b2a1ca99b31aa1fafc8e Mon Sep 17 00:00:00 2001 From: Aravind Date: Mon, 17 Aug 2026 21:01:49 +0530 Subject: [PATCH] Revert the self-hosted deploy fix Restores the tree to 3b16d50, reverting: 3c649fc Fix blank page on self-hosted deploys The earlier public-route commits were already reverted by 0ddbd35 and a51ab4a, so this returns the working tree exactly to the state at 3b16d50. Co-Authored-By: Claude Opus 5 --- .dockerignore | 6 +---- Dockerfile | 26 -------------------- nginx.conf | 22 ----------------- src/App.jsx | 40 ++++++++---------------------- src/api/base44Client.js | 7 +----- src/lib/AuthContext.jsx | 7 ++---- src/lib/ErrorBoundary.jsx | 52 --------------------------------------- src/lib/app-params.js | 10 +------- 8 files changed, 15 insertions(+), 155 deletions(-) delete mode 100644 src/lib/ErrorBoundary.jsx diff --git a/.dockerignore b/.dockerignore index 11c8dbe..f8da17c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -9,14 +9,10 @@ lerna-debug.log* node_modules -# The local dist/ is a developer's last build, not part of the source. Shipping it -# into the build context only slows the upload and risks a stale artifact being -# picked up if `npm run build` ever fails to overwrite a file. -dist +# dist !sdk/dist dist-ssr *.local -.git # Editor directories and files .vscode/* diff --git a/Dockerfile b/Dockerfile index 1529b4d..e822330 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,31 +9,13 @@ WORKDIR /app # the server. Raise this only if the host gets more RAM. ENV NODE_OPTIONS=--max-old-space-size=1024 -# Vite inlines VITE_* vars into the bundle at build time, so these have to be -# present here — setting them as runtime env vars in Dokploy does nothing, the -# JS is already compiled by then. .env.* is gitignored, so a build from the repo -# has no other source for them: without these the app boots with a null app id, -# every API call resolves against our own origin, nginx answers with index.html -# and the browser shows a blank page. Defaults match this app so a plain -# `docker build` works; override via Dokploy's build args to point elsewhere. -ARG VITE_BASE44_APP_ID=68fc6cf01386035c266e7a5d -ARG VITE_BASE44_BACKEND_URL=https://base44.app -ENV VITE_BASE44_APP_ID=$VITE_BASE44_APP_ID -ENV VITE_BASE44_BACKEND_URL=$VITE_BASE44_BACKEND_URL - # Install deps from the lockfile first so this layer is reused when only src changes COPY package.json package-lock.json ./ RUN npm ci --no-audit --no-fund COPY . . - -# Fail loudly here rather than shipping an image that serves an empty page. -RUN test -n "$VITE_BASE44_APP_ID" || (echo "VITE_BASE44_APP_ID is empty — the build would produce a blank app" && exit 1) RUN npm run build -# The build is only useful if it actually emitted an entry point. -RUN test -f dist/index.html || (echo "vite build produced no dist/index.html" && exit 1) - # ---- Runtime stage ---- FROM nginx:alpine @@ -45,14 +27,6 @@ COPY --from=build /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/nginx.conf -# Catch a broken config at build time instead of at container start, where -# Dokploy would report the deploy as successful and then serve nothing. -RUN nginx -t - EXPOSE 80 3000 -# Gives Dokploy a real signal that the container is serving, not just running. -HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ - CMD wget -q --spider http://127.0.0.1/health || exit 1 - CMD ["nginx", "-g", "daemon off;"] diff --git a/nginx.conf b/nginx.conf index 1ad25cb..29af0b4 100644 --- a/nginx.conf +++ b/nginx.conf @@ -49,29 +49,12 @@ http { root /usr/share/nginx/html; index index.html; - # Container liveness for Dokploy/Docker. Kept above the SPA fallback so it - # answers with a real status instead of 200-plus-index.html, which would - # make any health check pass even with the app completely broken. - location = /health { - access_log off; - add_header Content-Type text/plain; - return 200 "ok\n"; - } - # Vite writes content-hashed filenames here, so they can be cached forever. # Only add_header is used — combining it with `expires` emits two # conflicting Cache-Control headers. - # - # try_files ending in =404 is deliberate: without it a stale index.html - # asking for an asset from a previous deploy would fall through to the - # SPA rule below and receive index.html with a 200 and a text/html type. - # The browser refuses to execute that as a module and the page renders - # empty with only a MIME error in the console — a real 404 is far easier - # to diagnose and lets a reload recover. location /assets/ { add_header Cache-Control "public, max-age=31536000, immutable"; access_log off; - try_files $uri =404; } # index.html must be revalidated every time or deploys won't take effect @@ -82,11 +65,6 @@ http { location / { # This line forces Nginx to pass routing back to React Router try_files $uri $uri/ /index.html; - - # The fallback is served under the requested path, so the `= /index.html` - # rule above never applies to it. Without this a proxy or browser can - # cache the old HTML and keep loading assets that no longer exist. - add_header Cache-Control "no-cache"; } } } diff --git a/src/App.jsx b/src/App.jsx index b52371d..f637a4d 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -9,8 +9,6 @@ import { BrowserRouter as Router, Route, Routes, useLocation } from 'react-route import { setupIframeMessaging } from './lib/iframe-messaging'; import PageNotFound from './lib/PageNotFound'; import { AuthProvider, useAuth } from '@/lib/AuthContext'; -import ErrorBoundary from '@/lib/ErrorBoundary'; -import { appParams } from '@/lib/app-params'; import UserNotRegisteredError from '@/components/UserNotRegisteredError'; import FeatureReport from './pages/FeatureReport'; import LandingPage from './pages/LandingPage'; @@ -72,22 +70,6 @@ const AuthenticatedApp = () => { navigateToLogin(); return null; } - - // Anything else (bad/missing app id, unreachable backend, network failure) - // used to fall straight through to the app, which then crashed on the empty - // data and left a blank page. Say what happened instead. - return ( -
-
-

Unable to load the app

-

{authError.message || 'The Base44 backend could not be reached.'}

-

- App ID: {String(appParams.appId)}
- Backend: {String(appParams.serverUrl)} -

-
-
- ); } // Render the main app @@ -144,18 +126,16 @@ const AuthenticatedApp = () => { function App() { return ( - - - - - - - - - - - - + + + + + + + + + + ) } diff --git a/src/api/base44Client.js b/src/api/base44Client.js index 3cc2ce1..7826ba5 100644 --- a/src/api/base44Client.js +++ b/src/api/base44Client.js @@ -3,15 +3,10 @@ import { appParams } from '@/lib/app-params'; const { appId, serverUrl, token, functionsVersion } = appParams; -// appBaseUrl is what the SDK prefixes onto its login/logout redirects. Left unset -// it normalises to "" and those redirects become relative — on a self-hosted -// domain that sends the browser to /login on our own nginx, which serves -// index.html, which bootstraps the app, which redirects again: a loop that shows -// as a blank page. Pointing it at Base44 sends auth where it actually lives. +//Create a client with authentication required export const base44 = createClient({ appId, serverUrl, - appBaseUrl: serverUrl, token, functionsVersion, requiresAuth: false diff --git a/src/lib/AuthContext.jsx b/src/lib/AuthContext.jsx index 69a6164..e7c8706 100644 --- a/src/lib/AuthContext.jsx +++ b/src/lib/AuthContext.jsx @@ -124,11 +124,8 @@ export const AuthProvider = ({ children }) => { }; const navigateToLogin = () => { - // redirectToLogin() posts to `${appBaseUrl}/login` with no app_id, so Base44 - // cannot tell which app is asking when the request comes from our own domain - // instead of a *.base44.app one. loginWithProvider() hits the same login flow - // but carries app_id in the query, which is what a self-hosted build needs. - base44.auth.loginWithProvider('google', window.location.href); + // Use the SDK's redirectToLogin method + base44.auth.redirectToLogin(window.location.href); }; return ( diff --git a/src/lib/ErrorBoundary.jsx b/src/lib/ErrorBoundary.jsx deleted file mode 100644 index de9017c..0000000 --- a/src/lib/ErrorBoundary.jsx +++ /dev/null @@ -1,52 +0,0 @@ -import React from 'react'; - -/** - * Catches render-time crashes so they surface as a readable message instead of a - * white screen. React unmounts the whole tree when an error escapes, which is - * indistinguishable from "the deploy didn't work" — this makes the difference - * visible without opening devtools, which matters most on a hosted build where - * the stack is minified and nobody is watching the console. - */ -class ErrorBoundary extends React.Component { - constructor(props) { - super(props); - this.state = { error: null }; - } - - static getDerivedStateFromError(error) { - return { error }; - } - - componentDidCatch(error, info) { - console.error('Application crashed:', error, info?.componentStack); - } - - render() { - if (!this.state.error) { - return this.props.children; - } - - return ( -
-
-

Something went wrong

-

- The application failed to render. The details below are also in the browser console. -

-
-            {String(this.state.error?.stack || this.state.error)}
-          
- -
-
- ); - } -} - -export default ErrorBoundary; diff --git a/src/lib/app-params.js b/src/lib/app-params.js index 77f4b20..9db8313 100644 --- a/src/lib/app-params.js +++ b/src/lib/app-params.js @@ -34,18 +34,10 @@ const getAppParamValue = (paramName, { defaultValue = undefined, removeFromUrl = return null; } -// Base44's own host. On a base44-hosted app these arrive as ?app_id=/?server_url= -// query params, but a self-hosted build (Docker/Dokploy on a custom domain) never -// gets them, so the build-time env vars below are the only source. If both are -// missing the SDK falls back to a null serverUrl, every request becomes a -// same-origin relative URL, nginx answers it with index.html, and the app renders -// a blank page — so serverUrl must never be allowed to end up null. -const DEFAULT_SERVER_URL = "https://base44.app"; - const getAppParams = () => { return { appId: getAppParamValue("app_id", { defaultValue: import.meta.env.VITE_BASE44_APP_ID }), - serverUrl: getAppParamValue("server_url", { defaultValue: import.meta.env.VITE_BASE44_BACKEND_URL }) || DEFAULT_SERVER_URL, + serverUrl: getAppParamValue("server_url", { defaultValue: import.meta.env.VITE_BASE44_BACKEND_URL }), token: getAppParamValue("access_token", { removeFromUrl: true }), fromUrl: getAppParamValue("from_url", { defaultValue: window.location.href }), functionsVersion: getAppParamValue("functions_version"),