mirror of
https://github.com/mattermost/mattermost.git
synced 2026-10-13 09:27:38 +08:00
docs: emit redirect stubs at both <from>/index.html and <from>.html (#38389)
active-redirects.json entries whose `from` lives outside the docs CloudFront function's frozen legacy-Sphinx prefix set currently 404 in production. The stub file exists in S3 at <from>/index.html but the CFF (mattermost-iac-docs-prod -> 05-cdn -> clean-url-rewrite.js) only serves that key for the frozen legacy prefixes; for any other first path segment it falls back to <from>.html, which doesn't exist for plugin-client-redirects stubs. Add a postbuild step that duplicates every stub at the sibling flat key. The legacy branch keeps hitting <from>/index.html unchanged; the fallback branch now finds <from>.html. Real content pages are never overwritten (the script skips any path where <from>.html already exists), .html-suffixed from-values are skipped (CFF Phase A canonicalizes them before Phase B routes them), and .. traversal in a malformed from is rejected before any filesystem call. Smoke-tested against a local build: 741 stubs duplicated, 0 real content pages touched, byte-identical meta-refresh content.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
"docusaurus": "docusaurus",
|
||||
"start": "docusaurus start",
|
||||
"build": "docusaurus build",
|
||||
"postbuild": "node scripts/duplicate-redirect-stubs.mjs",
|
||||
"stage:agents-docs": "node scripts/stage-agents-docs.mjs",
|
||||
"build:sidebars": "node scripts/gen-documentation-sidebar.mjs && node scripts/gen-developer-sidebar.mjs",
|
||||
"build:openapi:spec": "node scripts/build-openapi.mjs",
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env node
|
||||
// Copy every plugin-client-redirects stub from `build/<from>/index.html` to
|
||||
// `build/<from>.html` so the docs CloudFront function's `<uri>.html` fallback
|
||||
// branch finds it (see mattermost-iac-docs-prod → 05-cdn →
|
||||
// clean-url-rewrite.js).
|
||||
|
||||
import {readFileSync, writeFileSync, existsSync, statSync} from 'node:fs';
|
||||
import {join, resolve, dirname, sep} from 'node:path';
|
||||
import {fileURLToPath} from 'node:url';
|
||||
|
||||
const HERE = dirname(fileURLToPath(import.meta.url));
|
||||
const SITE_ROOT = resolve(HERE, '..');
|
||||
const BUILD_DIR = join(SITE_ROOT, 'build');
|
||||
const REDIRECTS_JSON = join(SITE_ROOT, 'sidebars', 'active-redirects.json');
|
||||
|
||||
if (!existsSync(BUILD_DIR)) {
|
||||
console.error(`[duplicate-redirect-stubs] ${BUILD_DIR} not found; run \`docusaurus build\` first.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const {redirects} = JSON.parse(readFileSync(REDIRECTS_JSON, 'utf8'));
|
||||
const BUILD_DIR_PREFIX = BUILD_DIR + sep;
|
||||
|
||||
let duplicated = 0;
|
||||
let skippedExisting = 0;
|
||||
let skippedMissingStub = 0;
|
||||
let skippedHtmlSuffix = 0;
|
||||
let skippedOutsideBuild = 0;
|
||||
|
||||
for (const {from} of redirects) {
|
||||
// CFF Phase A already 301s `.html` to the extensionless form.
|
||||
if (from.endsWith('.html')) {
|
||||
skippedHtmlSuffix++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const rel = from.replace(/^\/+/, '');
|
||||
const stubPath = resolve(BUILD_DIR, rel, 'index.html');
|
||||
const flatPath = resolve(BUILD_DIR, `${rel}.html`);
|
||||
if (!stubPath.startsWith(BUILD_DIR_PREFIX) || !flatPath.startsWith(BUILD_DIR_PREFIX)) {
|
||||
skippedOutsideBuild++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!existsSync(stubPath) || !statSync(stubPath).isFile()) {
|
||||
skippedMissingStub++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Never shadow a real content page at the flat key.
|
||||
if (existsSync(flatPath)) {
|
||||
skippedExisting++;
|
||||
continue;
|
||||
}
|
||||
|
||||
writeFileSync(flatPath, readFileSync(stubPath));
|
||||
duplicated++;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[duplicate-redirect-stubs] duplicated=${duplicated} ` +
|
||||
`skipped-existing=${skippedExisting} ` +
|
||||
`skipped-missing-stub=${skippedMissingStub} ` +
|
||||
`skipped-html-suffix=${skippedHtmlSuffix} ` +
|
||||
`skipped-outside-build=${skippedOutsideBuild} ` +
|
||||
`total=${redirects.length}`,
|
||||
);
|
||||
Reference in New Issue
Block a user