限定导出是为明确公共接口与私有实现边界,通过精准可见性控制实现安全跨项目共享。Go用小写隐藏内部项,TS禁用export*,Rust用pub(crate),剥离敏感数据至internal目录,主模块仅提供受控函数访问;默认导出替代命名导出,构建期剔除调试导出。

限定导出不是为了“藏代码”,而是让变量库只暴露它该承担的契约,不泄露实现细节、不暴露调试入口、不泄漏类型结构。真正安全的跨项目共享,靠的不是加密或混淆,而是精准的可见性控制。
明确公共接口与私有实现边界
核心变量库对外只应提供少数稳定、语义清晰的命名导出,其余全部隐藏。例如一个统一配置库,只导出 getConfig() 和 getFeatureFlags() 两个函数,所有环境判断逻辑、密钥派生过程、fallback策略都封装在未导出的内部模块中。
- Go 项目:内部常量/函数用小写首字母(如 defaultTimeout),仅将 GetAPIBaseURL() 这类业务级入口大写导出
- TypeScript 项目:不加 export 的 const / interface / type 默认不可见;避免 export * 或 export { A, B, C } 暴露全量成员
- Rust 项目:敏感配置结构体用 pub(crate) 限制作用域,而非 pub 全局可见
拆分变量层与逻辑层,隔离敏感数据源
把真正承载密钥、Token、灰度开关规则的原始数据源,从主变量模块中剥离,放入 internal/ 或 private/ 子目录。主模块只通过受控函数访问这些数据,不直接暴露原始字段。
- 例如:创建 internal/secrets.ts,其中 API_KEY 不导出,仅由同目录下 getSecureClient() 函数内部使用
- 构建时确保该目录被 tsconfig.json 的 exclude 字段排除,不生成 .d.ts 声明文件
- NPM 包发布前检查 package.json 的 files 字段,显式声明只包含 dist/ 和 index.d.ts,不包含 internal 目录
用默认导出替代命名导出,隐藏模块结构
命名导出会鼓励调用方做 import * as Config from '@company/config',再通过 IDE 自动补全枚举所有导出项——这等于把变量库的“能力地图”白送给攻击者。默认导出则强制使用者必须了解契约,无法静态探测。
- 主入口改为 export default createConfig({ env }),返回一个带方法的对象(如 .get('timeout'))
- 避免导出原始对象字面量(如 export const CONFIG = { ... }),防止字段被直接解构和篡改
- 对需要强类型的场景,不导出 export type ConfigSchema,改用运行时校验 + 泛型约束(如 function useConfig
(key: T): Config[T] )
构建期清除调试导出与开发痕迹
开发阶段常用的 dumpAllKeys()、forceEnv('staging') 等函数,在上线包中必须彻底移除,不能仅靠注释或条件判断保留。
- Webpack/Vite 中通过 define: { 'process.env.DEBUG': JSON.stringify(false) },配合 if (process.env.DEBUG) { export function dump... } 实现编译期剔除
- TypeScript 项目启用 stripExcessPropertyErrors 并配合 ESLint 规则禁止 export function debug* 出现在非 dev/ 目录
- CI 流水线增加检查步骤:扫描 dist 目录产物,拒绝包含 debug、dump、testOnly 字样的导出声明

















