From 5d1f442584d5fa5d95e74d3aee061c1afef2ebd9 Mon Sep 17 00:00:00 2001 From: shenlan Date: Tue, 11 Nov 2025 23:19:43 +0800 Subject: [PATCH] feat(dashboard): fetch download manifests dynamically (#675) --- dashboard/package.json | 2 +- dashboard/scripts/start.js | 23 +++++++++++++ dashboard/src/app/docs/page.tsx | 2 +- dashboard/src/app/docs/resources.server.ts | 33 +++---------------- dashboard/src/app/download/page.tsx | 2 +- .../lib/download/dl-index-data-artifacts.ts | 18 +++------- .../download/dl-index-data-offline-package.ts | 17 +++------- 7 files changed, 41 insertions(+), 56 deletions(-) create mode 100644 dashboard/scripts/start.js diff --git a/dashboard/package.json b/dashboard/package.json index 6f32b12..090eb0b 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -10,7 +10,7 @@ "prebuild": "tsx ../scripts/export-slugs.ts && tsx ../scripts/scan-md.ts && tsx ../scripts/fetch-dl-index.ts && node ../scripts/copy-manifests.js", "build": "next build", "build:static": "npm run prebuild && next build", - "start": "next start", + "start": "node ./scripts/start.js", "lint": "next lint", "typecheck": "tsc --noEmit", "format": "prettier --write .", diff --git a/dashboard/scripts/start.js b/dashboard/scripts/start.js new file mode 100644 index 0000000..99f521b --- /dev/null +++ b/dashboard/scripts/start.js @@ -0,0 +1,23 @@ +#!/usr/bin/env node + +const { spawn } = require('node:child_process') + +const args = process.argv.slice(2) + +const child = spawn('next', ['start', ...args], { + stdio: 'inherit', + shell: process.platform === 'win32', +}) + +child.on('error', (error) => { + console.error('Failed to launch Next.js:', error) + process.exit(1) +}) + +child.on('close', (code, signal) => { + if (signal) { + process.kill(process.pid, signal) + } else { + process.exit(code ?? 0) + } +}) diff --git a/dashboard/src/app/docs/page.tsx b/dashboard/src/app/docs/page.tsx index 05a4792..ca31ed5 100644 --- a/dashboard/src/app/docs/page.tsx +++ b/dashboard/src/app/docs/page.tsx @@ -1,4 +1,4 @@ -export const dynamic = 'error' +export const dynamic = 'force-dynamic' import { notFound } from 'next/navigation' diff --git a/dashboard/src/app/docs/resources.server.ts b/dashboard/src/app/docs/resources.server.ts index cf5e5f5..64a5a3e 100644 --- a/dashboard/src/app/docs/resources.server.ts +++ b/dashboard/src/app/docs/resources.server.ts @@ -32,7 +32,7 @@ interface RawDocResource { async function fetchDocs(): Promise { try { const response = await fetch(DOCS_MANIFEST_URL, { - cache: 'no-cache', + cache: 'no-store', }) if (!response.ok) { @@ -58,15 +58,8 @@ async function loadDocs(): Promise { return fallbackDocs } -let cachedDocs: RawDocResource[] | null = null - async function getRawDocs(): Promise { - if (cachedDocs) { - return cachedDocs - } - - cachedDocs = await loadDocs() - return cachedDocs + return loadDocs() } async function buildDocsDataset(): Promise { @@ -76,20 +69,12 @@ async function buildDocsDataset(): Promise { ) } -let cachedDocsDataset: DocResource[] | null = null - export async function getDocsDataset(): Promise { - if (cachedDocsDataset) { - return cachedDocsDataset - } - - cachedDocsDataset = await buildDocsDataset() - return cachedDocsDataset + return buildDocsDataset() } export function clearDocsCache(): void { - cachedDocs = null - cachedDocsDataset = null + // Intentionally left blank. Runtime fetches always return fresh data. } @@ -258,20 +243,12 @@ async function buildDocsCollections(): Promise { return buildCollections(docs) } -let cachedCollections: DocCollection[] | null = null - export async function getDocCollections(): Promise { - if (cachedCollections) { - return cachedCollections - } - - cachedCollections = await buildDocsCollections() - return cachedCollections + return buildDocsCollections() } export function clearCollectionsCache(): void { clearDocsCache() - cachedCollections = null } function normalizeResource(item: RawDocResource): DocResource | null { diff --git a/dashboard/src/app/download/page.tsx b/dashboard/src/app/download/page.tsx index 3d278f9..ea73f43 100644 --- a/dashboard/src/app/download/page.tsx +++ b/dashboard/src/app/download/page.tsx @@ -1,4 +1,4 @@ -export const dynamic = 'error' +export const dynamic = 'force-dynamic' import { notFound } from 'next/navigation' diff --git a/dashboard/src/lib/download/dl-index-data-artifacts.ts b/dashboard/src/lib/download/dl-index-data-artifacts.ts index cc06d73..6ea7685 100644 --- a/dashboard/src/lib/download/dl-index-data-artifacts.ts +++ b/dashboard/src/lib/download/dl-index-data-artifacts.ts @@ -2,15 +2,14 @@ import 'server-only' import type { DirListing } from '@lib/download/types' import fallbackArtifacts from '../../../public/_build/artifacts-manifest.json' -import fallbackOfflinePackage from '../../../public/_build/offline-package.json' const ARTIFACTS_MANIFEST_URL = 'https://dl.svc.plus/dl-index/artifacts-manifest.json' -const FALLBACK_LISTINGS_URL = 'https://dl.svc.plus/dl-index/offline-package.json' +const FALLBACK_LISTINGS_URL = 'https://dl.svc.plus/dl-index/offline-package-manifest.json' async function fetchListings(url: string): Promise { try { const response = await fetch(url, { - cache: 'no-cache', + cache: 'no-store', }) if (!response.ok) { @@ -41,17 +40,10 @@ async function loadDownloadListings(): Promise { return fallbackArtifacts as DirListing[] } -let cachedListings: DirListing[] | null = null - export async function getDownloadListings(): Promise { - if (cachedListings) { - return cachedListings - } - - cachedListings = await loadDownloadListings() - return cachedListings + return loadDownloadListings() } export function clearDownloadListingsCache(): void { - cachedListings = null -} \ No newline at end of file + // Intentionally left blank. Runtime fetches always return fresh data. +} diff --git a/dashboard/src/lib/download/dl-index-data-offline-package.ts b/dashboard/src/lib/download/dl-index-data-offline-package.ts index ebee303..ef925dd 100644 --- a/dashboard/src/lib/download/dl-index-data-offline-package.ts +++ b/dashboard/src/lib/download/dl-index-data-offline-package.ts @@ -10,7 +10,7 @@ const OFFLINE_PACKAGE_URL = 'https://dl.svc.plus/dl-index/offline-package-manife export async function fetchOfflinePackageListings(): Promise { try { const response = await fetch(OFFLINE_PACKAGE_URL, { - cache: 'no-cache', + cache: 'no-store', }) if (!response.ok) { @@ -27,18 +27,11 @@ export async function fetchOfflinePackageListings(): Promise { } /** - * Get cached offline-package listings - * This is a simple in-memory cache - in production you might want to use a more robust solution + * Retrieve offline-package listings on demand. + * Data is fetched dynamically so updates are reflected without a deploy. */ -let cachedListings: DirListing[] | null = null - export async function getOfflinePackageListings(): Promise { - if (cachedListings) { - return cachedListings - } - - cachedListings = await fetchOfflinePackageListings() - return cachedListings + return fetchOfflinePackageListings() } /** @@ -78,5 +71,5 @@ export async function getOfflinePackageFileCount(): Promise { * Clear the cache (useful for testing or when data might have changed) */ export function clearOfflinePackageCache(): void { - cachedListings = null + // Intentionally left blank. Runtime fetches always return fresh data. }