Skip to content

Commit 622f926

Browse files
committed
fix: paths and collisions with assets
1 parent dc82a08 commit 622f926

71 files changed

Lines changed: 91 additions & 14 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 1 addition & 1 deletion

airborne_docs/CLAUDE.md

Lines changed: 12 additions & 5 deletions

airborne_docs/docusaurus.config.ts

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,75 @@
11
import { themes as prismThemes } from "prism-react-renderer";
22
import type { Config } from "@docusaurus/types";
33
import type * as Preset from "@docusaurus/preset-classic";
4+
import * as fs from "fs";
5+
import * as path from "path";
46

57
// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...)
68

9+
function docsStaticAssetsPlugin() {
10+
return {
11+
name: "docs-static-assets",
12+
configureWebpack(config: any, isServer: boolean) {
13+
// Only relocate for the production client build
14+
if (isServer || config.mode !== "production") return {};
15+
// The CSS extractor is CssExtractRspackPlugin (with @docusaurus/faster) or
16+
// MiniCssExtractPlugin (plain webpack) — both names contain "CssExtract".
17+
for (const plugin of config.plugins ?? []) {
18+
if (plugin?.constructor?.name?.includes("CssExtract") && plugin.options) {
19+
plugin.options.filename = "docs_static/assets/css/[name].[contenthash:8].css";
20+
plugin.options.chunkFilename = "docs_static/assets/css/[name].[contenthash:8].css";
21+
}
22+
}
23+
return {
24+
output: {
25+
filename: "docs_static/assets/js/[name].[contenthash:8].js",
26+
chunkFilename: "docs_static/assets/js/[name].[contenthash:8].js",
27+
assetModuleFilename: "docs_static/assets/[name].[contenthash:8][ext]",
28+
},
29+
};
30+
},
31+
};
32+
}
33+
34+
// This plugin is to keep the redirect from foo to foo/ under our own
35+
// control, this emits a small `foo.html` stub at each no-slash path that redirects to the
36+
// canonical `/foo/` with a root-relative URL (resolves on airborne.juspay.in, never the
37+
// origin). Because `foo.html` exists, GitHub Pages serves it directly and never issues its
38+
// own leaking redirect.
39+
function noSlashRedirectStubsPlugin() {
40+
return {
41+
name: "no-slash-redirect-stubs",
42+
async postBuild({ outDir }: { outDir: string }) {
43+
const indexFiles: string[] = [];
44+
(function collect(dir: string) {
45+
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
46+
const full = path.join(dir, e.name);
47+
if (e.isDirectory()) collect(full);
48+
else if (e.name === "index.html") indexFiles.push(full);
49+
}
50+
})(outDir);
51+
for (const file of indexFiles) {
52+
const relDir = path.relative(outDir, path.dirname(file));
53+
if (relDir === "") continue;
54+
const urlPath = "/" + relDir.split(path.sep).join("/") + "/";
55+
const stub = path.join(outDir, relDir + ".html");
56+
if (fs.existsSync(stub)) continue;
57+
fs.writeFileSync(
58+
stub,
59+
`<!doctype html><html lang="en"><head><meta charset="utf-8">` +
60+
`<meta http-equiv="refresh" content="0; url=${urlPath}">` +
61+
`<title>Redirecting…</title></head>` +
62+
`<body>Redirecting to <a href="${urlPath}">${urlPath}</a>…</body></html>\n`,
63+
);
64+
}
65+
},
66+
};
67+
}
68+
769
const config: Config = {
870
title: "Airborne",
971
tagline: "Over-the-air updates for React Native, Android, and iOS",
10-
favicon: "img/favicon.ico",
72+
favicon: "docs_static/img/favicon.ico",
1173

1274
future: {
1375
v4: true,
@@ -90,6 +152,8 @@ const config: Config = {
90152
],
91153

92154
plugins: [
155+
docsStaticAssetsPlugin,
156+
noSlashRedirectStubsPlugin,
93157
"docusaurus-plugin-sass",
94158
// Generates /llms.txt and /llms-full.txt at build time for LLM consumers.
95159
[
@@ -122,7 +186,7 @@ const config: Config = {
122186
themes: ["docusaurus-theme-openapi-docs", "@docusaurus/theme-mermaid"],
123187

124188
themeConfig: {
125-
image: "img/airborne-social-card.png",
189+
image: "docs_static/img/airborne-social-card.png",
126190
mermaid: {
127191
theme: { light: "neutral", dark: "dark" },
128192
},
@@ -140,8 +204,8 @@ const config: Config = {
140204
title: "",
141205
logo: {
142206
alt: "Airborne",
143-
src: "img/airborne-logo-light.svg",
144-
srcDark: "img/airborne-logo-dark.svg",
207+
src: "docs_static/img/airborne-logo-light.svg",
208+
srcDark: "docs_static/img/airborne-logo-dark.svg",
145209
href: "/docs",
146210
width: 132,
147211
},

airborne_docs/src/components/Screenshot/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import ThemedImage from "@theme/ThemedImage";
33
import useBaseUrl from "@docusaurus/useBaseUrl";
44

55
type ScreenshotProps = {
6-
/** File name (without extension) under static/img/screenshots/{light,dark}/ */
6+
/** File name (without extension) under static/docs_static/img/screenshots/{light,dark}/ */
77
name: string;
88
/** Accessible alt text. Falls back to the caption or name. */
99
alt?: string;
@@ -18,8 +18,8 @@ type ScreenshotProps = {
1818
* the dark capture in dark mode, both captured from the live Airborne dashboard.
1919
*/
2020
export default function Screenshot({ name, alt, caption, width }: ScreenshotProps): React.JSX.Element {
21-
const light = useBaseUrl(`/img/screenshots/light/${name}.png`);
22-
const dark = useBaseUrl(`/img/screenshots/dark/${name}.png`);
21+
const light = useBaseUrl(`/docs_static/img/screenshots/light/${name}.png`);
22+
const dark = useBaseUrl(`/docs_static/img/screenshots/dark/${name}.png`);
2323
const altText = alt ?? (typeof caption === "string" ? caption : name);
2424

2525
return (

airborne_docs/src/pages/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Link from "@docusaurus/Link";
44
import useBaseUrl from "@docusaurus/useBaseUrl";
55

66
export default function Home(): React.JSX.Element {
7-
// Trailing slash matches trailingSlash: true (avoids a redirect hop to /docs/).
7+
// Trailing slash matches trailingSlash: true (the canonical /docs/ form).
88
const docsUrl = useBaseUrl("/docs/");
99
return (
1010
<>
File renamed without changes.

airborne_docs/static/img/airborne-logo-light.svg renamed to airborne_docs/static/docs_static/img/airborne-logo-light.svg

File renamed without changes.

airborne_docs/static/img/airborne-social-card.png renamed to airborne_docs/static/docs_static/img/airborne-social-card.png

File renamed without changes.

airborne_docs/static/img/docusaurus-social-card.jpg renamed to airborne_docs/static/docs_static/img/docusaurus-social-card.jpg

File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)