generator沙箱的核心是收口旧逻辑而非加新功能,通过声明式yield统一管控文件写入、命令执行、上下文注入等副作用行为,实现老旧脚手架中高危操作的原子化隔离与可控拦截。

直接用 Generator 的立即执行模式(IIFE-style yield)在老旧脚手架里做行为隔离沙箱,关键不在“加新功能”,而在“收口旧逻辑”——把散落在 config、hook、loader 中的副作用操作,统一收束到一个可声明、可跳过、不可变的 Generator 流中。
锁定可沙箱化的行为单元
老旧脚手架常见问题:构建步骤混杂(如 webpack.config.js 里穿插 fs.writeFileSync、环境变量注入、动态 require),导致无法单点隔离或替换。Generator 沙箱的第一步是识别出哪些行为必须原子化:
- 文件写入(生成配置、输出 bundle、写临时 token)
- 外部命令调用(git tag、curl 获取元数据、npx prettier 格式化)
- 敏感上下文注入(将 .env 变量注入到前端 runtime、拼接 CDN 域名)
- 条件性依赖加载(根据 NODE_ENV 动态 require 不同 logger 实现)
用 Generator 声明输入契约与输出结构
不改原有脚手架入口,只新增一个 generator.ts 文件,定义清晰的输入输出 interface:
interface BuildContext {
env: 'dev' | 'prod';
target: 'web' | 'node';
version: string;
}
interface BuildStep {
type: 'WRITE_FILE' | 'RUN_COMMAND' | 'INJECT_CONTEXT';
payload: Record<string any>;
id: string; // 如 'inject-cdn-config-v1'
}</string>
Generator 函数只接收 完全静态可推导的上下文(不能传 function、class 实例或未克隆的对象),返回 固定 shape 的 step 流,例如:
function* buildSandbox(ctx: BuildContext): Generator<buildstep> {
yield { type: 'INJECT_CONTEXT', payload: { cdn: getCDN(ctx.env) }, id: 'cdn-inject' };
yield { type: 'WRITE_FILE', payload: { path: 'dist/config.js', content: genConfig(ctx) }, id: 'config-write' };
if (ctx.env === 'prod') {
yield { type: 'RUN_COMMAND', payload: { cmd: 'npx terser dist/bundle.js' }, id: 'terser-run' };
}
}</buildstep>
在运行时实现“立即执行 + 可控拦截”
老旧脚手架通常用同步函数链(如 runStep1() → runStep2()),Generator 沙箱不替代它,而是作为它的“策略层”:
- 调用方遍历 generator 返回的 step 流,对每个 step 做类型分发
- 所有
RUN_COMMAND步骤统一走封装好的 execa 沙箱调用(自动设置 cwd、timeout、no-shell、禁用 stdio 继承) - 所有
WRITE_FILE步骤强制写入临时目录(如./.sandbox/output/),而非项目根路径 - 所有
INJECT_CONTEXT步骤仅返回纯数据对象,由 loader 层决定是否注入、如何序列化
这样既保留了老脚手架的执行流程,又把高危行为全部收进可控边界内,无需重写 webpack 配置或 gulp task。
兼容旧插件体系的桥接设计
若脚手架支持插件(如 vue-cli plugin 或自研 plugin API),可在插件注册阶段要求其提供 Generator 工厂函数:
export default definePlugin({
name: 'my-analytics-plugin',
setup(ctx) {
return function* () {
yield { type: 'WRITE_FILE', payload: { path: 'public/analytics.js', content: genScript(ctx) }, id: 'analytics-script' };
yield { type: 'RUN_COMMAND', payload: { cmd: 'curl -X POST https://api.example.com/log' }, id: 'analytics-log' };
};
}
});
主流程统一收集所有插件返回的 Generator,合并为单一有序 step 流,再逐个执行。插件不再能直接调用 fs 或 child_process,只能申明意图——这正是行为隔离的本质。











