2026-02-26 09:31:12 +08:00
|
|
|
|
let dataIndex: Record<string, string> | null = null;
|
|
|
|
|
|
let isDevIndexLoaded = false;
|
2026-02-26 13:35:09 +08:00
|
|
|
|
let isCliIndexLoaded = false;
|
2026-02-26 09:31:12 +08:00
|
|
|
|
|
2026-02-26 09:24:26 +08:00
|
|
|
|
/**
|
2026-02-26 09:31:12 +08:00
|
|
|
|
* 设置全局数据索引(CLI 环境使用)
|
2026-02-26 09:24:26 +08:00
|
|
|
|
*/
|
2026-02-26 09:31:12 +08:00
|
|
|
|
export function setDataIndex(index: Record<string, string>) {
|
|
|
|
|
|
dataIndex = index;
|
2026-02-26 09:24:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-02-26 09:31:12 +08:00
|
|
|
|
* 从索引获取数据
|
2026-02-26 09:24:26 +08:00
|
|
|
|
*/
|
2026-02-26 09:31:12 +08:00
|
|
|
|
function getIndexedData(path: string): string | null {
|
|
|
|
|
|
if (dataIndex && dataIndex[path]) {
|
|
|
|
|
|
return dataIndex[path];
|
2026-02-26 09:24:26 +08:00
|
|
|
|
}
|
2026-02-26 09:31:12 +08:00
|
|
|
|
return null;
|
2026-02-26 09:24:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-02-26 09:31:12 +08:00
|
|
|
|
* 在 dev 环境加载 glob 索引
|
2026-02-26 09:24:26 +08:00
|
|
|
|
*/
|
2026-02-26 09:31:12 +08:00
|
|
|
|
async function loadDevIndex(): Promise<void> {
|
|
|
|
|
|
if (isDevIndexLoaded) return;
|
|
|
|
|
|
isDevIndexLoaded = true;
|
2026-02-26 09:24:26 +08:00
|
|
|
|
|
2026-02-26 09:31:12 +08:00
|
|
|
|
// @ts-ignore - import.meta.glob 在构建时会被处理
|
|
|
|
|
|
if (typeof import.meta !== 'undefined' && import.meta.glob) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// @ts-ignore - 只加载 .csv 和 .md 文件
|
|
|
|
|
|
const modules = import.meta.glob('../../content/**/*.{csv,md}', { as: 'raw', eager: true });
|
|
|
|
|
|
const index: Record<string, string> = {};
|
|
|
|
|
|
for (const [path, content] of Object.entries(modules)) {
|
|
|
|
|
|
const normalizedPath = path.replace('/src/', '/');
|
|
|
|
|
|
index[normalizedPath] = content as string;
|
|
|
|
|
|
}
|
|
|
|
|
|
dataIndex = { ...dataIndex, ...index };
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
// glob 不可用时忽略
|
|
|
|
|
|
}
|
2026-02-26 09:24:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-26 13:35:09 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 在 CLI 环境从 /__CONTENT_INDEX.json 加载索引
|
|
|
|
|
|
*/
|
|
|
|
|
|
async function loadCliIndex(): Promise<void> {
|
|
|
|
|
|
if (isCliIndexLoaded) return;
|
|
|
|
|
|
isCliIndexLoaded = true;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const response = await fetch('/__CONTENT_INDEX.json');
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
|
throw new Error('Failed to fetch content index');
|
|
|
|
|
|
}
|
|
|
|
|
|
const index = await response.json();
|
|
|
|
|
|
dataIndex = { ...dataIndex, ...index };
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
// CLI 索引不可用时忽略(可能不在 CLI 环境)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-26 09:24:26 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 异步加载数据
|
|
|
|
|
|
* @param path 数据路径
|
|
|
|
|
|
* @returns 数据内容
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function fetchData(path: string): Promise<string> {
|
2026-02-26 13:35:09 +08:00
|
|
|
|
// CLI 环境:先从 /__CONTENT_INDEX.json 加载索引
|
|
|
|
|
|
await loadCliIndex();
|
|
|
|
|
|
|
|
|
|
|
|
// dev 环境:加载 glob 索引
|
2026-02-26 09:31:12 +08:00
|
|
|
|
await loadDevIndex();
|
|
|
|
|
|
|
2026-02-26 09:24:26 +08:00
|
|
|
|
// 首先尝试从索引获取
|
|
|
|
|
|
const indexedData = getIndexedData(path);
|
|
|
|
|
|
if (indexedData) {
|
|
|
|
|
|
return indexedData;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 索引不存在时,使用 fetch 加载
|
|
|
|
|
|
try {
|
|
|
|
|
|
const response = await fetch(path);
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
|
throw new Error(`Failed to fetch: ${path}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
return await response.text();
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('fetchData error:', error);
|
|
|
|
|
|
throw error;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|