ttrpg-tools/src/data-loader/index.ts

92 lines
2.3 KiB
TypeScript
Raw Normal View History

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
*
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 在构建时会被处理
2026-02-26 14:07:58 +08:00
if (typeof import.meta !== "undefined" && import.meta.glob) {
2026-02-26 09:31:12 +08:00
try {
// @ts-ignore - 只加载 .csv 和 .md 文件
2026-02-26 14:07:58 +08:00
const modules = import.meta.glob("../../content/**/*.{csv,md}", {
as: "raw",
eager: true,
});
2026-02-26 09:31:12 +08:00
const index: Record<string, string> = {};
for (const [path, content] of Object.entries(modules)) {
2026-02-26 14:07:58 +08:00
const normalizedPath = path.replace("/src/", "/");
2026-02-26 09:31:12 +08:00
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 {
2026-02-26 14:07:58 +08:00
const response = await fetch("/__CONTENT_INDEX.json");
2026-02-26 13:35:09 +08:00
if (!response.ok) {
2026-02-26 14:07:58 +08:00
throw new Error("Failed to fetch content index");
2026-02-26 13:35:09 +08:00
}
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 加载
2026-02-26 14:07:58 +08:00
if (dataIndex !== null) throw new Error(`no data in index: ${path}`);
2026-02-26 09:24:26 +08:00
try {
const response = await fetch(path);
if (!response.ok) {
throw new Error(`Failed to fetch: ${path}`);
}
return await response.text();
} catch (error) {
2026-02-26 14:07:58 +08:00
console.error("fetchData error:", error);
2026-02-26 09:24:26 +08:00
throw error;
}
}