mirror of
https://github.com/linshenkx/prompt-optimizer.git
synced 2026-05-18 22:22:23 +08:00
- 迁移原因:统一CSP安全支持,简化架构设计 - 核心变更: * 移除handlebars依赖,添加mustache依赖 * 删除CSPSafeTemplateProcessor及相关测试 * 统一使用Mustache.render()处理所有模板 * 移除环境检测逻辑,所有平台使用相同处理流程 - 文档更新: * 更新语法指南中的模板技术描述 * 归档文档补充迁移说明和架构演进经验 - 测试调整:更新相关单元测试以匹配新的模板引擎 - 兼容性:保持所有现有模板变量替换功能不变 技术优势:原生CSP支持,统一处理逻辑,简化维护复杂度
8.5 KiB
8.5 KiB
CSP安全模板处理 - 开发经验总结
🎯 核心经验
1. CSP问题诊断经验
问题识别技巧
- 错误特征: "unsafe-eval" 关键词是CSP问题的明确标识
- 环境特异性: 只在浏览器扩展中出现,其他环境正常
- 代码定位: 通过错误堆栈快速定位到
Handlebars.compile()调用
根因分析方法
// 验证CSP限制的简单测试
try {
new Function('return 1')();
console.log('CSP允许动态代码执行');
} catch (e) {
console.log('CSP禁止动态代码执行:', e.message);
}
2. 环境检测设计经验
多重检测的必要性
问题: 单一检测条件容易误判
// ❌ 不够准确的检测
static isExtensionEnvironment(): boolean {
return typeof chrome !== 'undefined';
}
解决: 多层验证确保准确性
// ✅ 准确的检测逻辑
static isExtensionEnvironment(): boolean {
// 1. 环境排除
// 2. API存在性检查
// 3. 功能有效性验证
// 4. 异常处理保护
}
Electron环境排除的重要性
经验: Electron应用可能注入Chrome API,导致误判 解决: 优先检测Electron特征,明确排除
// 多种Electron检测方式
const electronIndicators = [
'window.require',
'window.electronAPI',
'window.electron',
'navigator.userAgent.includes("Electron")'
];
3. 向后兼容设计经验
渐进增强策略
原则: 新功能不能破坏现有功能 实现:
- 默认使用原有方案(Handlebars)
- 仅在特定环境使用新方案(CSP安全)
- 异常时回退到安全状态
异常处理的重要性
// ✅ 防御性编程
try {
// 环境检测逻辑
} catch (error) {
// 任何错误都返回false,确保其他平台正常工作
return false;
}
经验: 宁可功能受限,也不能影响其他平台的正常运行
4. 测试驱动开发经验
测试优先的价值
- 需求澄清: 通过测试用例明确功能边界
- 回归保护: 确保修改不破坏现有功能
- 文档作用: 测试即文档,展示使用方式
环境模拟技巧
// 模拟不同环境的技巧
beforeEach(() => {
// 清理全局状态
delete (global as any).chrome;
delete (global as any).window;
});
// 精确模拟浏览器扩展环境
(global as any).chrome = {
runtime: {
getManifest: vi.fn(() => ({ manifest_version: 3 }))
}
};
🔧 技术实现经验
1. 正则表达式设计
模式选择考虑
- 简单性:
/\{\{([^}]+)\}\}/g足够处理基本需求 - 性能: 全局匹配比多次单独匹配更高效
- 容错性: 处理空格和边界情况
替换逻辑优化
// ✅ 安全的替换逻辑
result.replace(/\{\{([^}]+)\}\}/g, (match, variableName) => {
const trimmedName = variableName.trim();
const value = context[trimmedName];
// 类型安全 + 默认值处理
return value !== undefined ? String(value) : '';
});
2. 类型安全实践
接口复用策略
经验: 复用现有接口比创建新接口更好
- 减少维护成本
- 保持API一致性
- 自动获得类型检查
类型转换处理
// ✅ 安全的类型转换
return value !== undefined ? String(value) : '';
// ❌ 可能出问题的方式
return value || ''; // 0, false会被转换为空字符串
3. 性能优化经验
避免重复检测
问题: 每次模板处理都进行环境检测 优化: 可考虑缓存检测结果(当前未实现)
// 未来优化方向
class CSPSafeTemplateProcessor {
private static _isExtension: boolean | null = null;
static isExtensionEnvironment(): boolean {
if (this._isExtension === null) {
this._isExtension = this.detectEnvironment();
}
return this._isExtension;
}
}
内存使用优化
- 避免创建不必要的中间对象
- 使用原地替换而非创建新字符串
- 及时释放大型临时变量
🚨 常见陷阱与解决
1. 环境检测陷阱
陷阱1: 过度依赖单一特征
// ❌ 容易误判
if (typeof chrome !== 'undefined') {
// Electron也可能有chrome对象
}
陷阱2: 忽略异常处理
// ❌ 可能导致其他平台崩溃
const manifest = chrome.runtime.getManifest();
return manifest.manifest_version !== undefined;
解决方案: 多重验证 + 异常保护
// ✅ 安全的检测方式
try {
if (isElectronEnvironment()) return false;
if (hasChromeAPI()) {
return validateManifest();
}
return false;
} catch (error) {
return false; // 保护其他平台
}
2. 模板处理陷阱
陷阱1: 变量名处理不当
// ❌ 没有处理空格
const variableName = match[1];
// ✅ 正确处理
const variableName = match[1].trim();
陷阱2: 类型转换问题
// ❌ 可能返回undefined字符串
return context[variableName];
// ✅ 安全转换
return value !== undefined ? String(value) : '';
3. 测试相关陷阱
陷阱1: 全局状态污染
// ❌ 测试间相互影响
it('test1', () => {
(global as any).chrome = mockChrome;
// 测试逻辑
});
it('test2', () => {
// chrome对象仍然存在,影响测试结果
});
解决方案: 完整的清理机制
// ✅ 每个测试独立
beforeEach(() => {
delete (global as any).chrome;
delete (global as any).window;
delete (global as any).navigator;
});
📈 性能优化建议
1. 当前性能特点
- 优势: 比Handlebars更轻量,启动更快
- 限制: 功能简化,仅支持基本变量替换
- 适用: 浏览器扩展的CSP限制环境
2. 进一步优化方向
缓存优化
// 环境检测结果缓存
// 正则表达式对象缓存
// 编译结果缓存(如果需要)
批量处理
// 对于大量模板,可考虑批量处理
static processBatch(templates: Template[], context: TemplateContext) {
const isExtension = this.isExtensionEnvironment();
return templates.map(template =>
isExtension ? this.processCSPSafe(template, context)
: this.processHandlebars(template, context)
);
}
🔮 未来扩展方向
1. 功能增强
- 简单条件: 支持基本的if/else逻辑
- 格式化: 支持日期、数字格式化
- 自定义函数: 允许注册简单的处理函数
2. 工具支持
- 模板验证: 构建时检查模板兼容性
- 转换工具: Handlebars到CSP安全格式的转换
- 调试工具: 模板处理过程的可视化
3. 架构演进
- 插件化: 支持不同的模板引擎插件
- 配置化: 允许用户配置处理行为
- 监控: 添加性能和错误监控
💡 核心经验总结:
- 安全第一: 任何新功能都不能影响现有平台的稳定性
- 测试驱动: 完整的测试覆盖是质量保证的基础
- 渐进增强: 在限制环境中提供基本功能,在完整环境中提供全功能
- 防御编程: 多重检测和异常处理确保系统健壮性
🎉 架构演进更新(2025-08-29)
从"兼容方案"到"原生方案"的演进
核心启发: 经过CSP安全处理的实践,我们意识到"环境特定的兼容性方案"虽然解决了问题,但增加了系统复杂性。最佳实践是选择原生支持目标环境的技术栈。
关键决策: Mustache.js迁移
- 技术原因: Mustache天然不使用
eval(),原生支持CSP环境 - 架构原因: 统一的模板引擎消除了环境差异处理
- 维护原因: 单一代码路径,降低测试和维护成本
经验升华:
- 技术选型: 优先选择跨平台、无限制的技术方案
- 架构设计: 避免环境特定的处理逻辑,追求统一性
- 问题解决: 从"兼容现有技术"转向"选择合适技术"
实际效果:
- 📉 代码复杂度: 从双处理器架构简化为单处理器
- 📈 可维护性: 消除环境检测逻辑,统一测试覆盖
- 🎯 性能表现: Mustache比环境检测+分支处理更高效
- 🔒 安全保障: 原生CSP支持比兼容层更可靠
对后续项目的指导:
- 遇到环境限制问题时,首先评估是否有原生支持的替代方案
- 兼容性方案应作为临时解决方案,目标是找到统一的最终方案
- 架构简化往往比功能兼容更有价值
这次从Handlebars到Mustache的迁移,完美诠释了"选择正确的技术比完善错误的技术更重要"这一架构原则。