Skip to content

Conversation

@pesnik
Copy link

@pesnik pesnik commented Jan 27, 2026

Fix: Add custom base path support for subpath deployments

Description

Fixes #5200

This PR adds comprehensive support for deploying Plane on custom base paths (e.g., mydomain.com/plane), enabling reverse proxy deployments on subpaths. Previously, static assets and internal links failed when deploying on a subpath.

Problem

When users deploy Plane on a subpath using reverse proxies, multiple issues occurred:

  1. Static assets 404: Assets served without base path prefix

    • ❌ Expected: /plane/assets/file.js
    • ❌ Actual: /assets/file.js → 404 errors
  2. Broken manifest links: PWA manifests referenced with absolute paths

    • ❌ Hardcoded /site.webmanifest.json instead of relative paths
  3. Hydration mismatches: Server/client rendering differences in fallback components

  4. Admin app redirects: "Redirect to Plane" and workspace links pointed to wrong URLs

The space and admin apps already supported base paths via VITE_SPACE_BASE_PATH and VITE_ADMIN_BASE_PATH, but the web app was missing this feature, and cross-app navigation was broken.

Solution

1. Web App Base Path Support

Added VITE_WEB_BASE_PATH configuration following the same pattern as other apps:

  • Updated vite.config.ts to use joinUrlPath utility and set Vite's base option
  • Modified Dockerfile.web to accept VITE_WEB_BASE_PATH build argument

2. Manifest Path Fixes

Fixed hardcoded manifest paths across all apps to support subpaths:

  • Changed absolute paths (/site.webmanifest.json) to use joinUrlPath() with base path
  • Updated icon paths in manifest JSON files to be relative (removed leading /)

3. Hydration Fixes

Resolved React hydration mismatches in HydrateFallback components:

  • Added mounted state checks to ensure server/client render the same initial content
  • Applied fix to web, admin, and space apps

4. Admin App Cross-Navigation

Fixed admin app links to respect web app's custom base path:

  • Updated "Redirect to Plane" button to use WEB_URL (includes base path)
  • Fixed workspace list links to include base path
  • Updated workspace creation form URL preview

5. Configuration & Documentation

  • Added BASE_URL to turbo.json globalEnv for linting
  • Updated all .env.example files with VITE_WEB_BASE_PATH documentation
  • Added helpful comments for backend APP_BASE_PATH configuration

Changes

Core Files Modified

Web App:

  • apps/web/vite.config.ts - Base path configuration
  • apps/web/Dockerfile.web - Build argument support
  • apps/web/app/root.tsx - Manifest path fix, hydration fix, React import
  • apps/web/app/layout.tsx - Manifest path fix, base path support
  • apps/web/public/manifest.json - Relative icon paths, relative start_url
  • apps/web/public/site.webmanifest.json - Relative icon paths
  • apps/web/.env.example - Documentation

Admin App:

  • apps/admin/app/root.tsx - Manifest path fix, hydration fix, React import
  • apps/admin/app/(all)/(dashboard)/sidebar-help-section.tsx - Use WEB_URL for redirect
  • apps/admin/app/(all)/(dashboard)/workspace/create/form.tsx - Use WEB_URL for preview
  • apps/admin/core/components/workspace/list-item.tsx - Use WEB_URL for links
  • apps/admin/public/site.webmanifest.json - Relative icon paths
  • apps/admin/.env.example - Documentation

Space App:

  • apps/space/app/root.tsx - Hydration fix, React import
  • apps/space/public/site.webmanifest.json - Relative icon paths
  • apps/space/.env.example - Documentation

Configuration:

  • turbo.json - Added BASE_URL to globalEnv
  • packages/constants/src/endpoints.ts - Already had WEB_URL support
  • apps/api/.env.example - Documentation for backend base path

Testing

Local Development Test:

# Set base path for web app
VITE_WEB_BASE_PATH=/plane/ pnpm dev --port 3000

# Set base path for admin app (to know where web app is)
VITE_WEB_BASE_PATH=/plane/ pnpm dev --port 3001

# Start backend with base path awareness
# Edit apps/api/.env:
# APP_BASE_PATH="/plane"
# WEB_URL="http://localhost:3000/plane"
docker compose -f docker-compose-local.yml up -d

Production Build Test:

docker build -f apps/web/Dockerfile.web \
  --build-arg VITE_WEB_BASE_PATH="/plane" \
  -t plane-web-test .

Verification:

  1. ✅ Static assets load from /plane/assets/...
  2. ✅ PWA manifests accessible at /plane/site.webmanifest.json
  3. ✅ No hydration warnings in console
  4. ✅ "Redirect to Plane" button in admin points to /plane/
  5. ✅ Workspace links include /plane/ prefix

Backward Compatibility

Not a breaking change

  • Default VITE_WEB_BASE_PATH is / (root path)
  • Existing deployments continue to work without modification
  • All changes are additive or fix existing bugs

Checklist

  • Code follows project coding guidelines
  • Changes match existing patterns (space/admin apps)
  • Default values maintain backward compatibility
  • Hydration issues resolved
  • Cross-app navigation works with custom paths
  • Documentation updated (.env.example files)
  • Commit messages follow contributing guidelines
  • References issue [bug]: APP_BASE_URL does not change static paths #5200

Related

Summary by CodeRabbit

  • New Features

    • Support for configurable base paths so apps can be deployed under custom URL prefixes.
  • Bug Fixes

    • Web manifest and icon paths updated to use relative paths for correct resolution.
    • Hydration guard improved to stabilize client rendering after server-side render.
  • Chores

    • Environment examples and Docker build updated to expose base-path settings.
    • Build tooling and app configs updated to honor the new base path.

✏️ Tip: You can customize this high-level summary in your review settings.

@CLAassistant
Copy link

CLAassistant commented Jan 27, 2026

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 27, 2026

📝 Walkthrough

Walkthrough

Introduces configurable base-path support (VITE_WEB_BASE_PATH / APP_BASE_PATH), switches manifest/static hrefs to joinUrlPath(WEB_BASE_PATH,…), normalizes manifest icon paths to relative, replaces WEB_BASE_URL with WEB_URL usages, and adds client-side mount guards to HydrateFallback across admin/space/web.

Changes

Cohort / File(s) Summary
Environment files
apps/admin/.env.example, apps/api/.env.example, apps/space/.env.example, apps/web/.env.example
Added VITE_WEB_BASE_PATH entries and APP_BASE_PATH (with comments) to support deployments on custom subpaths.
Build / Config
apps/web/Dockerfile.web, apps/web/vite.config.ts, turbo.json
Added build ARG/ENV VITE_WEB_BASE_PATH, set Vite base via joinUrlPath(process.env.VITE_WEB_BASE_PATH ?? "", "/"), and added BASE_URL to Turbo globalEnv.
Root / Hydration & Manifest
apps/admin/app/root.tsx, apps/space/app/root.tsx, apps/web/app/root.tsx, apps/web/app/layout.tsx
Introduced WEB_BASE_PATH (env-derived), used joinUrlPath(WEB_BASE_PATH, "...") for manifest links, and added isMounted mount guards in HydrateFallback to avoid SSR hydration mismatches.
URL constant updates
apps/admin/app/(all)/(dashboard)/sidebar-help-section.tsx, apps/admin/app/(all)/(dashboard)/workspace/create/form.tsx, apps/admin/core/components/workspace/list-item.tsx
Replaced WEB_BASE_URL import/usage with WEB_URL from @plane/constants and updated href construction accordingly.
Public manifest files
apps/admin/public/site.webmanifest.json, apps/space/public/site.webmanifest.json, apps/web/public/manifest.json, apps/web/public/site.webmanifest.json
Converted icon entries to expanded object syntax and removed leading slashes from src paths (relative paths); apps/web/public/manifest.json also sets start_url to ".".
Minor UI tweaks
apps/admin/core/components/workspace/list-item.tsx, apps/admin/app/(all)/(dashboard)/sidebar-help-section.tsx
Small className formatting consolidation and href resolution changes to use new WEB_URL constant.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰
I hop through envs and mend each path,
join slashes gently, spare the wrath.
Manifests now follow my small map,
icons wander true — no more mishap.
A bunny's stitch: stable routes on tap. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix/issue 5200 web base path' clearly summarizes the main change: adding web base path support to fix issue #5200.
Description check ✅ Passed The PR description is comprehensive and covers all template sections including description, type of change (bug fix), test scenarios, and references to issue #5200.
Linked Issues check ✅ Passed The PR fully addresses issue #5200's requirements: configurable base path support (VITE_WEB_BASE_PATH), fixed manifest/icon paths, hydration fixes, cross-app navigation updates, and backward compatibility.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing base path support and fixing related issues; no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@apps/admin/app/`(all)/(dashboard)/workspace/create/form.tsx:
- Line 40: The current line double-encodes WEB_URL and uses a fallback that
omits the app base path; update the workspaceBaseURL logic: stop calling
encodeURI on WEB_URL (use WEB_URL as-is) and build a fallback that preserves the
origin plus the app base path from window.location.pathname (e.g., reconstruct
origin + first path segment(s) so the base path isn't lost) when WEB_URL is
undefined; locate and change the workspaceBaseURL constant in form.tsx
(references: workspaceBaseURL, WEB_URL, window.location).

In `@apps/web/app/layout.tsx`:
- Line 63: The head contains two <link rel="manifest"> tags pointing to
different files (site.webmanifest.json and manifest.json) so the browser only
uses the first; pick one approach: either remove the duplicate link (delete the
extra <link rel="manifest"> that uses joinUrlPath(WEB_BASE_PATH, "...")
referencing the manifest you don't want) or merge the two manifest files into a
single consolidated manifest (combine icon entries and other fields, save as a
single filename) and update the remaining <link rel="manifest"> (the usage that
calls joinUrlPath and WEB_BASE_PATH) to point to the consolidated manifest;
ensure icon paths inside the chosen manifest are correct for the deployed
assets.
🧹 Nitpick comments (2)
turbo.json (1)

9-9: Addition of BASE_URL to globalEnv looks correct.

This ensures Turbo properly invalidates the build cache when the base URL configuration changes, which is necessary for the custom base path feature.

Nitpick: For consistency, consider placing BASE_URL in alphabetical order (after APP_VERSION, before DEV).

   "globalEnv": [
     "APP_VERSION",
+    "BASE_URL",
     "DEV",
     "LOG_LEVEL",
     "NODE_ENV",
-    "BASE_URL",
     "SENTRY_DSN",
apps/web/public/site.webmanifest.json (1)

10-19: LGTM on relative paths. Consider providing properly sized icons.

The switch to relative paths (plane-logos/plane-mobile-pwa.png) is correct for base path support.

However, both icon entries reference the same image file with different declared sizes (192x192 and 512x512). For optimal PWA quality, consider providing separate image files at each resolution to avoid browser scaling artifacts.

@pesnik pesnik force-pushed the fix/issue-5200-web-base-path branch from ea2077c to da879a3 Compare January 27, 2026 11:26
@pesnik pesnik marked this pull request as draft January 27, 2026 11:31
@pesnik pesnik marked this pull request as ready for review January 27, 2026 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug]: APP_BASE_URL does not change static paths

2 participants