Skip to content

feat(docs): add DOCS_BASE_URL build arg for sub-path mounting#1684

Merged
yannickmonney merged 1 commit into
mainfrom
feat/docs-base-url
May 8, 2026
Merged

feat(docs): add DOCS_BASE_URL build arg for sub-path mounting#1684
yannickmonney merged 1 commit into
mainfrom
feat/docs-base-url

Conversation

@yannickmonney

@yannickmonney yannickmonney commented May 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Lets the docs app be deployed under a sub-path (e.g. /docs/) without breaking absolute asset URLs. The motivating use case is the temporary deploy on the ops droplet where docs.tale.dev DNS isn't set up yet, so both apps need to share a single hostname with web at / and docs at /docs.

The default of / keeps the existing docs.tale.dev deployment unchanged.

How it works

  • vite.config.ts reads process.env.DOCS_BASE_URL and uses it as Vite's base (defaults to /). Vite then prefixes every generated asset URL (CSS chunks, JS chunks, fonts, imported images) with that value.
  • index.html uses Vite's %BASE_URL% placeholder for the favicon <link> tags and the /llms.txt alternate link.
  • app/router.tsx + app/entry-server.tsx derive a TanStack Router basepath from import.meta.env.BASE_URL (stripping the trailing slash) so client-side and SSR routing both honour the prefix.
  • scripts/prerender.ts prefixes the URL passed to render() with the same basepath so memory-history-based SSR matches the same routes the client sees.
  • docs-footer.tsx swaps a hardcoded /llms.txt for ${import.meta.env.BASE_URL}llms.txt.
  • Dockerfile declares ARG DOCS_BASE_URL and exports it as ENV before vite build runs.
  • compose.docs.yml forwards DOCS_BASE_URL from the host env to the build args (defaults /).

Pre-PR checklist

  • Ran bun run checknot run by author; please verify locally
  • Updated services/platform/messages/{en,de,fr}.json — N/A (no UI strings changed)
  • Updated /docs/{en,de,fr}/ — N/A (deployment infra only)
  • Ran bun run --filter @tale/docs lint and bun run --filter @tale/docs testnot run by author; please verify locally
  • Updated README.md, README.de.md, README.fr.md — N/A

Test plan

  • Build with default: docker compose -f compose.docs.yml build — confirm the docs.tale.dev deployment is unaffected (assets still at root).
  • Build with prefix: DOCS_BASE_URL=/docs/ docker compose -f compose.docs.yml build, then run behind a reverse proxy that strips /docs before forwarding. Confirm CSS, fonts, JS, favicon, and llms.txt all load under /docs/... and that <Link> clicks keep the prefix in the address bar.

Summary by CodeRabbit

  • Chores
    • Enhanced documentation service deployment flexibility by adding support for configurable base URLs. The documentation can now be served from any custom deployment path, with all asset references, navigation links, routing, and RSS feeds automatically resolving correctly regardless of whether the docs are hosted at the root path or deployed under any sub-path.

Vite, TanStack Router, the SSR entry, and the prerender script now all
read the build-time DOCS_BASE_URL (defaulting to '/'), so the docs app
can be mounted under a prefix like /docs/ without breaking absolute
asset URLs. compose.docs.yml forwards the arg and the Dockerfile sets
it as an env before vite runs.

The previously hardcoded '/llms.txt' link in the footer and the
'/images/...' icon references in index.html now use BASE_URL so they
follow the configured mount point.
@coderabbitai

coderabbitai Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR makes the docs service deployable under a configurable base path. A new DOCS_BASE_URL environment variable (defaulting to /) is introduced in Docker Compose and Dockerfile, then propagated to Vite for asset prefixing and to TanStack Router in both client and server entry points for request routing. HTML favicon and component links are updated to use relative paths via %BASE_URL% placeholders or runtime import.meta.env.BASE_URL. The prerender script aligns SSR rendering by prepending the computed base path to route URLs.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 accurately summarizes the main change: adding a DOCS_BASE_URL build argument to support sub-path mounting of the docs app.
Description check ✅ Passed The description is comprehensive and well-structured, covering the summary, implementation details, pre-PR checklist, and test plan as required by the template.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/docs-base-url

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@services/docs/scripts/prerender.ts`:
- Line 18: BASE_PATH normalization only removes a trailing slash and can produce
values without a leading slash (e.g., "docs"); update the BASE_PATH
initialization so it produces either an empty string for root or a value that
always starts with '/' and has no trailing slash. Specifically, replace the
current BASE_PATH assignment with logic that reads process.env.DOCS_BASE_URL,
returns '' if falsy or equals '/', otherwise ensures the value begins with '/'
and does not end with '/', and keep references to BASE_PATH (used later around
line 105) intact.

In `@services/docs/vite.config.ts`:
- Around line 6-9: The Vite `base` is set directly from
process.env.DOCS_BASE_URL which can be inconsistent (e.g. "docs", "/docs",
"/docs/"); move normalization logic out of defineConfig() and before the `export
default` so it isn't declared inside the object literal, compute a canonical
base in a const (e.g. read process.env.DOCS_BASE_URL, ensure it starts and ends
with a single '/', default to '/'), then reference that const in the
`defineConfig({ base: ... })` assignment; update references to DOCS_BASE_URL,
`base`, and ensure the normalization function/const is declared at module scope
(not inside `defineConfig()`).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 51cf8e9b-235d-4103-993b-fe84e6ea406e

📥 Commits

Reviewing files that changed from the base of the PR and between b2b88e9 and 1ab1940.

📒 Files selected for processing (8)
  • compose.docs.yml
  • services/docs/Dockerfile
  • services/docs/app/components/docs/docs-footer.tsx
  • services/docs/app/entry-server.tsx
  • services/docs/app/router.tsx
  • services/docs/index.html
  • services/docs/scripts/prerender.ts
  • services/docs/vite.config.ts

const SITE_URL = process.env.DOCS_SITE_URL ?? 'https://docs.tale.dev';
// Mount-point prefix passed to the router during SSR so it resolves URLs
// against the same basepath the client uses. Empty for root deployments.
const BASE_PATH = (process.env.DOCS_BASE_URL ?? '/').replace(/\/$/, '');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Harden BASE_PATH normalization to require a leading slash.

Line 18 only strips a trailing slash; DOCS_BASE_URL=docs becomes docs and Line 105 then renders relative URLs (docs/...). Normalize to '' (root) or '/segment'.

Suggested patch
-const BASE_PATH = (process.env.DOCS_BASE_URL ?? '/').replace(/\/$/, '');
+const rawBase = process.env.DOCS_BASE_URL ?? '/';
+const normalizedBase = rawBase.replace(/^\/+|\/+$/g, '');
+const BASE_PATH = normalizedBase.length === 0 ? '' : `/${normalizedBase}`;

Also applies to: 105-105

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/docs/scripts/prerender.ts` at line 18, BASE_PATH normalization only
removes a trailing slash and can produce values without a leading slash (e.g.,
"docs"); update the BASE_PATH initialization so it produces either an empty
string for root or a value that always starts with '/' and has no trailing
slash. Specifically, replace the current BASE_PATH assignment with logic that
reads process.env.DOCS_BASE_URL, returns '' if falsy or equals '/', otherwise
ensures the value begins with '/' and does not end with '/', and keep references
to BASE_PATH (used later around line 105) intact.

Comment on lines +6 to +9
// Build-time mount point. Defaults to '/' (e.g. docs.tale.dev). Set to a
// sub-path with trailing slash like '/docs/' to serve the docs app under
// that prefix — Vite then prefixes every asset URL accordingly.
base: process.env.DOCS_BASE_URL ?? '/',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In Vite, what exact input format is recommended for the baseoption, and how doesimport.meta.env.BASE_URLbehave whenbase is provided without a leading or trailing slash?

💡 Result:

Recommended input format for Vite’s base option: 1) Use an absolute URL pathname that ends with a slash, e.g. /foo/ [1]. 2) You can also use a full URL pathname, e.g. https://bar.com/foo/ (the origin is ignored in development; the path part is used the same as /foo/) [1]. 3) For embedded deployment (relative), use '' or './' [1]. How import.meta.env.BASE_URL behaves when base is provided without a leading or trailing slash: - import.meta.env.BASE_URL is “the public base url the app is being served from” and it is “determined by the base config option” [2]. - Vite’s base option supports values like /foo/, and for relative base you can use '' or ./ [1]. The official configuration docs list valid formats using leading and trailing slashes for absolute bases (e.g. /foo/) [1]. - In Vite’s implementation history, the team specifically added support for “base without trailing slash” (PR titled “feat: base without trailing slash”) [3], meaning Vite can accept /foo as base (without the ending /) while still working as a base path. - Regarding whether the leading slash is required: Vite’s configuration resolution code emits a warning when the base option “should start with a slash”, indicating that omitting the leading slash is not the intended/validated format [4]. Practical takeaway: - Prefer setting base exactly in the documented/validated form: /subdir/ (leading and trailing slash) or .//'' (embedded) [1]. - If you omit the trailing slash (e.g. /subdir), Vite has support for it [3]. - If you omit the leading slash, Vite warns that it “should start with a slash”, so import.meta.env.BASE_URL may not match what you expect versus the documented absolute base formats [4][2].

Citations:


🏁 Script executed:

fd -t f "vite.config.ts" | head -20

Repository: tale-project/tale

Length of output: 205


🏁 Script executed:

cat -n services/docs/vite.config.ts

Repository: tale-project/tale

Length of output: 3612


🏁 Script executed:

# Check other vite configs for env variable handling patterns
rg "process\.env\." services/platform/vite.config.ts services/web/vite.config.ts -A 2

Repository: tale-project/tale

Length of output: 537


🏁 Script executed:

# Look for any utility functions for path/base normalization in the codebase
fd -t f "format" -o -t f "normalize" | grep -E "\.(ts|js)$" | head -20

Repository: tale-project/tale

Length of output: 178


🏁 Script executed:

# Check if there's a shared utils or lib directory
ls -la lib/ 2>/dev/null || ls -la src/ 2>/dev/null | head -20

Repository: tale-project/tale

Length of output: 43


🏁 Script executed:

cat -n services/platform/vite.config.ts | head -20

Repository: tale-project/tale

Length of output: 1283


Normalize DOCS_BASE_URL before assigning Vite base, but fix the patch syntax.

Line 9 currently trusts raw env input. Values like docs or /docs can produce inconsistent URL prefixing across generated links/assets. Normalization to a canonical "/.../" shape is necessary.

However, the proposed patch has a critical syntax error: const declarations cannot be placed inside the defineConfig() object literal. Move them outside, before the export default, following the pattern already used in services/platform/vite.config.ts:

Corrected patch
+// Normalize env input to Vite's canonical base shape: "/" or "/segment/".
+// Accepts docs, /docs, /docs/ from deploy environments.
+const rawBase = process.env.DOCS_BASE_URL ?? '/';
+const base =
+  rawBase === '/'
+    ? '/'
+    : `/${rawBase.replace(/^\/+|\/+$/g, '')}/`;
+
 export default defineConfig({
   // Build-time mount point. Defaults to '/' (e.g. docs.tale.dev). Set to a
   // sub-path with trailing slash like '/docs/' to serve the docs app under
   // that prefix — Vite then prefixes every asset URL accordingly.
-  base: process.env.DOCS_BASE_URL ?? '/',
+  base,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Build-time mount point. Defaults to '/' (e.g. docs.tale.dev). Set to a
// sub-path with trailing slash like '/docs/' to serve the docs app under
// that prefix — Vite then prefixes every asset URL accordingly.
base: process.env.DOCS_BASE_URL ?? '/',
// Normalize env input to Vite's canonical base shape: "/" or "/segment/".
// Accepts docs, /docs, /docs/ from deploy environments.
const rawBase = process.env.DOCS_BASE_URL ?? '/';
const base =
rawBase === '/'
? '/'
: `/${rawBase.replace(/^\/+|\/+$/g, '')}/`;
export default defineConfig({
// Build-time mount point. Defaults to '/' (e.g. docs.tale.dev). Set to a
// sub-path with trailing slash like '/docs/' to serve the docs app under
// that prefix — Vite then prefixes every asset URL accordingly.
base,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/docs/vite.config.ts` around lines 6 - 9, The Vite `base` is set
directly from process.env.DOCS_BASE_URL which can be inconsistent (e.g. "docs",
"/docs", "/docs/"); move normalization logic out of defineConfig() and before
the `export default` so it isn't declared inside the object literal, compute a
canonical base in a const (e.g. read process.env.DOCS_BASE_URL, ensure it starts
and ends with a single '/', default to '/'), then reference that const in the
`defineConfig({ base: ... })` assignment; update references to DOCS_BASE_URL,
`base`, and ensure the normalization function/const is declared at module scope
(not inside `defineConfig()`).

@yannickmonney yannickmonney merged commit 9d9ec26 into main May 8, 2026
12 checks passed
@yannickmonney yannickmonney deleted the feat/docs-base-url branch May 8, 2026 11:33
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.

1 participant