refactor: replace webpack context loading with dev server proxy

Remove the webpack-based file indexing strategy in favor of a proxy
approach. The dev server now proxies content requests to a local CLI
server, simplifying the data loading logic and removing webpack-specific
types and loaders.
This commit is contained in:
2026-07-11 09:19:41 +08:00
parent 52563fd3ef
commit c661d2a1d2
3 changed files with 22 additions and 61 deletions
+13 -33
View File
@@ -1,10 +1,14 @@
/**
* 文件索引管理器
* 支持种文件索引加载方式:
* 1. CLI 环境:从 /__CONTENT_INDEX.json 加载
* 2. Dev 环境:使用 webpackContext 仅加载 .md 文件(仅在 dev 构建中生效)
* 3. 浏览器环境:用户选择本地文件夹,扫描文件索引
* 支持种文件索引加载方式:
* 1. CLI / 代理环境:从 /__CONTENT_INDEX.json 加载
* 2. 浏览器环境:用户选择本地文件夹,扫描文件索引
* - 支持 IndexedDB 持久化目录句柄,刷新页面无需重新选择
*
* Dev 工作流:运行 CLI 服务器并在 rsbuild 配置中设置代理
* > npm run tttk serve ./content
* > npm run dev
* rsbuild 会将 /__CONTENT_INDEX.json、/__COMPLETIONS.json、/content/ 代理到 CLI 服务器
*/
import {
@@ -18,20 +22,20 @@ type FileIndex = Record<string, string>;
let fileIndex: FileIndex | null = null;
let indexLoadPromise: Promise<void> | null = null;
let activeSource: "cli" | "webpack" | "folder" | null = null;
let activeSource: "cli" | "folder" | null = null;
/** Currently active directory handle (if folder source) */
let activeDirHandle: FileSystemDirectoryHandle | null = null;
/**
* 加载文件索引(只加载一次)
* 尝试顺序:CLI JSON → webpack context (dev only) → 已持久化的目录句柄
* 尝试顺序:CLI JSON → 已持久化的目录句柄
*/
function ensureIndexLoaded(): Promise<void> {
if (indexLoadPromise) return indexLoadPromise;
indexLoadPromise = (async () => {
// 策略 1: CLI 环境 — 从 /__CONTENT_INDEX.json 加载
// 策略 1: CLI / 代理环境 — 从 /__CONTENT_INDEX.json 加载
try {
const response = await fetch("/__CONTENT_INDEX.json");
if (response.ok) {
@@ -44,31 +48,7 @@ function ensureIndexLoaded(): Promise<void> {
// CLI 索引不可用时尝试下一个策略
}
// 策略 2: Dev 环境 — webpackContext + raw loader(仅 dev 构建时生效)
// 生产构建时 process.env.NODE_ENV 被替换为 'production',整个分支会被 tree-shake 掉
if (process.env.NODE_ENV === "development") {
try {
const context = import.meta.webpackContext("../../content", {
recursive: true,
regExp: /\.md|\.yarn|\.csv|\.svg$/i,
});
const keys = context.keys();
const index: FileIndex = {};
for (const key of keys) {
const module = context(key) as { default?: string } | string;
const content =
typeof module === "string" ? module : (module.default ?? "");
const normalizedPath = "/content" + key.slice(1);
index[normalizedPath] = content;
}
fileIndex = { ...fileIndex, ...index };
activeSource = "webpack";
} catch (e) {
// webpackContext 不可用时忽略
}
}
// 策略 3: 浏览器 — 尝试从 IndexedDB 恢复保存的目录句柄
// 策略 2: 浏览器 — 尝试从 IndexedDB 恢复保存的目录句柄
if (!activeSource) {
try {
const restored = await restoreSavedHandle();
@@ -176,7 +156,7 @@ export async function loadFromUserFolder(): Promise<string[] | null> {
/**
* 移除已保存的目录句柄,并清除索引
* 之后确保索引加载时回退到 CLI/webpack 策略
* 之后确保索引加载时回退到 CLI 策略
*/
export async function switchToBuiltInSource(): Promise<void> {
await removeHandle();