如何在边缘环境构建时排除mysql2包,替代eval方案?
我的Web应用运行在不支持多数Node.js库的边缘环境中,目前使用兼容边缘环境的PlanetScale连接器。近期出于安全及快速CI需求,需要存储数据库快照,本地连接快照需用到mysql2,但该包不兼容边缘环境,导致构建失败。
我尝试通过条件动态导入的方式引入mysql2:
... let { CONNECTOR } = import.meta.env if (CONNECTOR === "mysql") { const mysql = await import("mysql2/promise"); } ...
但该方案仍无法通过构建。无奈之下使用了eval的方式实现:
... let { CONNECTOR } = import.meta.env if (CONNECTOR === "mysql") { const mysql = await eval(`import("mysql2/promise")`); } ...
此方案虽能通过构建且在开发环境正常运行,但代码写法极不规范。我尝试调整rollup和vite配置均无效,且将mysql2移至dev依赖也不可行,因为Cloudflare不会传递--production标志,构建时仍会报错。请问有无替代eval的合理方案?
方案1:将mysql2标记为外部依赖(Vite配置)
Vite的external配置可指定依赖不被打包进最终产物,边缘环境不会加载这些依赖,仅在本地开发/运行时使用。
修改vite.config.js:
export default { // 其他配置... external: ['mysql2'], // 适配Cloudflare Pages,添加依赖优化排除 optimizeDeps: { exclude: ['mysql2'] } }
之后保留原条件动态导入代码即可:
let { CONNECTOR } = import.meta.env if (CONNECTOR === "mysql") { const mysql = await import("mysql2/promise"); // 本地快照连接逻辑 }
构建时Vite会跳过mysql2的打包,边缘环境中该分支不会执行,自然不会触发加载;本地运行时因为mysql2已安装(作为依赖或dev依赖),可正常导入。
方案2:通过条件编译完全剔除边缘环境不需要的代码
利用Vite的define配置注入环境变量,让构建工具在生产构建时直接移除包含mysql2的代码分支。
修改vite.config.js:
export default { // 其他配置... define: { 'import.meta.env.LOCAL_DEV': JSON.stringify(process.env.NODE_ENV === 'development') } }
代码中使用该变量做判断:
if (import.meta.env.LOCAL_DEV) { // 仅本地环境执行,生产构建时该分支会被完全剔除 const mysql = await import("mysql2/promise"); // 本地快照连接逻辑 }
这种方式下,生产构建产物中不会包含任何mysql2相关的导入逻辑,彻底避免兼容性问题。
方案3:拆分本地专用模块
把mysql2相关逻辑单独抽成一个模块,比如local-snapshot-connector.js:
// local-snapshot-connector.js import mysql from 'mysql2/promise'; export async function connectToSnapshot() { // 快照连接逻辑 }
在Vite配置中将其标记为外部依赖:
// vite.config.js export default { external: ['./src/local-snapshot-connector.js'], }
主代码中通过环境变量动态导入:
let { CONNECTOR } = import.meta.env if (CONNECTOR === "mysql") { const { connectToSnapshot } = await import('./src/local-snapshot-connector.js'); // 使用connectToSnapshot }
构建时不会打包这个本地模块,边缘环境不会加载,本地运行时可正常使用。
内容的提问来源于stack exchange,提问作者Kostas Xafis

