Skip to content

Commit aa8318f

Browse files
authoredJun 20, 2025··
chore: config to serve assets from relative path (#3003)
1 parent 330f0d8 commit aa8318f

File tree

11 files changed

+74
-14
lines changed

11 files changed

+74
-14
lines changed
 

‎packages/commons/docs-loader/src/readonly-docs-loader.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,9 +689,11 @@ const getFonts = cache(async (domain: string) => {
689689
);
690690
}
691691
const response = await loadWithUrl(domain);
692+
const assetHost = (await getEdgeFlags(domain)).isAssetHost;
692693
const fonts = generateFonts(
693694
response.definition.config.typographyV2,
694-
await getFiles(domain)
695+
await getFiles(domain),
696+
assetHost
695697
);
696698
kvSet(domain, "fonts", fonts);
697699
return fonts;

‎packages/commons/docs-server/src/file-resolver.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import "server-only";
33
import { FileData } from "@fern-api/docs-utils/types/file-data";
44
import { FernNavigation } from "@fern-api/fdr-sdk";
55

6-
export function createFileResolver(files: Record<string, FileData>) {
6+
export function createFileResolver(
7+
files: Record<string, FileData>,
8+
assetHost: boolean
9+
) {
710
return (src: string | undefined) => {
811
if (src == null) {
912
return undefined;
@@ -22,6 +25,14 @@ export function createFileResolver(files: Record<string, FileData>) {
2225

2326
return { src };
2427
}
28+
29+
if (assetHost) {
30+
file.src = file.src.replace(
31+
"https://files.buildwithfern.com/",
32+
`/_files/`
33+
);
34+
}
35+
2536
return file;
2637
};
2738
}

‎packages/commons/docs-server/src/generateFonts.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,18 @@ export function getFontExtension(url: string): string {
1111
function generateFontFace(
1212
variant: DocsV1Read.CustomFontConfigVariant,
1313
fontConfig: DocsV1Read.FontConfigV2,
14-
files: Record<string, { src: string }>
14+
files: Record<string, { src: string }>,
15+
assetHost: boolean
1516
): string | undefined {
1617
const file = files[variant.fontFile];
1718
if (file == null) {
1819
return undefined;
1920
}
21+
22+
if (assetHost) {
23+
file.src = file.src.replace("https://files.buildwithfern.com/", `/_files/`);
24+
}
25+
2026
let fontExtension: string;
2127
try {
2228
fontExtension = getFontExtension(new URL(file.src).pathname);
@@ -44,7 +50,8 @@ export interface FernFonts {
4450

4551
export function generateFonts(
4652
typography: DocsV1Read.DocsTypographyConfigV2 | undefined,
47-
files: Record<string, { src: string }>
53+
files: Record<string, { src: string }>,
54+
assetHost: boolean
4855
): FernFonts {
4956
const fontFaces: string[] = [];
5057
let additionalCss = "";
@@ -55,7 +62,12 @@ export function generateFonts(
5562
if (typography?.bodyFont?.variants != null) {
5663
let setVariant = false;
5764
for (const variant of typography.bodyFont.variants) {
58-
const fontFace = generateFontFace(variant, typography.bodyFont, files);
65+
const fontFace = generateFontFace(
66+
variant,
67+
typography.bodyFont,
68+
files,
69+
assetHost
70+
);
5971
if (fontFace != null) {
6072
fontFaces.push(fontFace);
6173
setVariant = true;
@@ -73,7 +85,8 @@ export function generateFonts(
7385
const fontFace = generateFontFace(
7486
variant,
7587
typography.headingsFont,
76-
files
88+
files,
89+
assetHost
7790
);
7891
if (fontFace != null) {
7992
fontFaces.push(fontFace);
@@ -95,7 +108,12 @@ export function generateFonts(
95108
if (typography?.codeFont?.variants != null) {
96109
let setVariant = false;
97110
for (const variant of typography.codeFont.variants) {
98-
const fontFace = generateFontFace(variant, typography.codeFont, files);
111+
const fontFace = generateFontFace(
112+
variant,
113+
typography.codeFont,
114+
files,
115+
assetHost
116+
);
99117
if (fontFace != null) {
100118
fontFaces.push(fontFace);
101119
setVariant = true;

‎packages/commons/docs-utils/src/flags.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export interface EdgeFlags {
3333
isDefaultSearchFilterOff: boolean;
3434
isChangelogRedirects: boolean;
3535
isPosthogDisabled: boolean;
36+
isAssetHost: boolean;
3637
}
3738

3839
export const DEFAULT_EDGE_FLAGS: EdgeFlags = {
@@ -70,9 +71,11 @@ export const DEFAULT_EDGE_FLAGS: EdgeFlags = {
7071
isDefaultSearchFilterOff: false,
7172
isChangelogRedirects: false,
7273
isPosthogDisabled: false,
74+
isAssetHost: false,
7375
};
7476

7577
export const DEFAULT_SELF_HOSTED_EDGE_FLAGS: EdgeFlags = {
7678
...DEFAULT_EDGE_FLAGS,
7779
isWhitelabeled: true,
80+
isAssetHost: true,
7881
};

‎packages/fern-dashboard/src/app/[orgName]/(visual-editor)/editor/[...slug]/@logo/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export default async function LogoPage({
2828
loader.getRoot(),
2929
]);
3030

31-
const resolveFileSrc = createFileResolver(files);
31+
const resolveFileSrc = createFileResolver(files, false);
3232
const foundNode = FernNavigation.utils.findNode(root, slugjoin(slug));
3333

3434
let frontmatter = null;

‎packages/fern-docs/bundle/src/app/[host]/[domain]/dynamic/@logo/[slug]/page.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ export default async function LogoPage({
2222
await getFernToken()
2323
);
2424

25-
const [{ basePath }, config, files, root] = await Promise.all([
25+
const [{ basePath }, config, files, root, flags] = await Promise.all([
2626
loader.getMetadata(),
2727
loader.getConfig(),
2828
loader.getFiles(),
2929
loader.getRoot(),
30+
loader.getEdgeFlags(),
3031
]);
3132

32-
const resolveFileSrc = createFileResolver(files);
33+
const resolveFileSrc = createFileResolver(files, flags.isAssetHost);
3334
const foundNode = FernNavigation.utils.findNode(root, slugjoin(slug));
3435

3536
let frontmatter = null;

‎packages/fern-docs/bundle/src/app/[host]/[domain]/static/@logo/[slug]/page.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ export default async function LogoPage({
2222
await getFernToken()
2323
);
2424

25-
const [{ basePath }, config, files, root] = await Promise.all([
25+
const [{ basePath }, config, files, root, flags] = await Promise.all([
2626
loader.getMetadata(),
2727
loader.getConfig(),
2828
loader.getFiles(),
2929
loader.getRoot(),
30+
loader.getEdgeFlags(),
3031
]);
3132

32-
const resolveFileSrc = createFileResolver(files);
33+
const resolveFileSrc = createFileResolver(files, flags.isAssetHost);
3334
const foundNode = FernNavigation.utils.findNode(root, slugjoin(slug));
3435

3536
let frontmatter = null;

‎packages/fern-docs/bundle/src/app/utils.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@ export async function generateHtml({
2323
loader.getConfig(),
2424
loader.getFiles(),
2525
]);
26-
faviconUrl = config.favicon ? files[config.favicon]?.src : undefined;
26+
27+
if (config.favicon) {
28+
faviconUrl = files[config.favicon]?.src.replace(
29+
"https://files.buildwithfern.com/",
30+
`/_files/`
31+
);
32+
}
2733
}
2834

2935
return `

‎packages/fern-docs/bundle/src/components/header/ProductDropdown.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ export async function ProductDropdown({
3636
}
3737

3838
const files = await loader.getFiles();
39+
const flags = await loader.getEdgeFlags();
3940

40-
const resolveFileSrc = createFileResolver(files);
41+
const resolveFileSrc = createFileResolver(files, flags.isAssetHost);
4142

4243
const productOptions = products.map((product): ProductDropdownItem => {
4344
const slug = product.slug ?? product.pointsTo;

‎packages/fern-docs/bundle/src/middleware.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,16 @@ export const middleware: NextMiddleware = async (request) => {
100100
return newPathname;
101101
};
102102

103+
/**
104+
* Rewrite /_files/* to https://files.buildwithfern.com/*
105+
*/
106+
if (pathname.startsWith("/_files/")) {
107+
const filePath = pathname
108+
.replace("/_files/", "") // trim file indicator
109+
.replace("https:/", "https://"); // pathnames normalize urls, so we need restore the protocol //
110+
return NextResponse.redirect(`https://files.buildwithfern.com/${filePath}`);
111+
}
112+
103113
/**
104114
* Rewrite /api/fern-docs/revalidate-all/v3 to /api/fern-docs/revalidate?regenerate=true
105115
*/

‎packages/fern-docs/edge-config/src/getEdgeFlags.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ const EDGE_FLAGS = [
5151
"default-search-filter-off" as const,
5252
"changelog-redirects" as const,
5353
"posthog-disabled" as const,
54+
"asset-host" as const,
5455
];
5556

5657
type EdgeFlag = (typeof EDGE_FLAGS)[number];
@@ -210,6 +211,10 @@ export async function getEdgeFlags(domain: string): Promise<EdgeFlags> {
210211
domain,
211212
config["posthog-disabled"]
212213
);
214+
const isAssetHost = checkDomainMatchesCustomers(
215+
domain,
216+
config["asset-host"]
217+
);
213218

214219
return {
215220
isApiPlaygroundEnabled: isDevelopment(domain) || isApiPlaygroundEnabled,
@@ -248,6 +253,7 @@ export async function getEdgeFlags(domain: string): Promise<EdgeFlags> {
248253
isDefaultSearchFilterOff,
249254
isChangelogRedirects,
250255
isPosthogDisabled,
256+
isAssetHost,
251257
};
252258
} catch (e) {
253259
console.error(`[get-edge-flags] ${JSON.stringify(e)}`);
@@ -286,6 +292,7 @@ export async function getEdgeFlags(domain: string): Promise<EdgeFlags> {
286292
isDefaultSearchFilterOff: false,
287293
isChangelogRedirects: false,
288294
isPosthogDisabled: false,
295+
isAssetHost: false,
289296
};
290297
}
291298
}

1 commit comments

Comments
 (1)

vercel[bot] commented on Jun 20, 2025

@vercel[bot]

Successfully deployed to the following URLs:

prod.ferndocs.com – ./packages/fern-docs/bundle

prodferndocscom-git-app-buildwithfern.vercel.app
prodferndocscom-buildwithfern.vercel.app

Please sign in to comment.