如何在浏览器中从字符串运行含外部库的JavaScript?(SvelteKit)
解决方案
1. 预导入库并注入动态函数作用域
在executeFunction所在模块预先导入需要的外部库,通过new Function的参数将库注入动态代码的作用域,无需修改调用方参数,避免大规模重构。
示例代码:
import imageConversion from 'image-conversion'; import type { LoadOutput } from './your-types'; // 替换为实际类型路径 export async function executeFunction(data: LoadOutput, input: Record<string, any>): Promise<any> { let args = []; for (let param of data.functionTree[0].parameters) { let value = input[param.name]; if(!value) { return undefined; } args.push(value); } // 将预导入的库作为参数传入,让动态代码可直接使用 let func = new Function('imageConversion', `return ${data.jsCode}`)(imageConversion); return await func.call(null, ...args); }
动态代码中即可直接调用库方法:
function(img) { return imageConversion.compress(img, { quality: 0.5 }); }
若需多个库,扩展参数列表即可:
import imageConversion from 'image-conversion'; import anotherLib from 'another-lib'; // ... let func = new Function('imageConversion', 'anotherLib', `return ${data.jsCode}`)(imageConversion, anotherLib);
2. 全局挂载库(临时场景适用)
在SvelteKit客户端初始化逻辑中,将预导入的库挂载到window对象,动态代码可直接访问全局变量。
示例:
// 在+layout.svelte或初始化脚本中 import imageConversion from 'image-conversion'; if (typeof window !== 'undefined') { (window as any).imageConversion = imageConversion; }
executeFunction无需修改:
export async function executeFunction(data: LoadOutput, input: Record<string, any>): Promise<any> { // ... 原有逻辑 ... let func = new Function('return ' + data.jsCode)(); return await func.call(null, ...args); }
注意:该方式会污染全局作用域,仅适合临时验证场景,不推荐大型项目使用。
3. 动态加载库并传入作用域(按需加载场景)
若无需预先导入所有库,可在executeFunction内动态加载所需库,再传入动态代码作用域,减少初始打包体积。
示例:
export async function executeFunction(data: LoadOutput, input: Record<string, any>): Promise<any> { // ... 原有逻辑 ... // 假设data中包含需要加载的库列表,如data.requiredLibs = ['image-conversion'] const libs = await Promise.all( (data.requiredLibs || []).map(lib => import(lib)) ); // 提取库的导出内容(根据库的导出方式调整) const libValues = libs.map(lib => lib.default || lib); // 生成库对应的变量名(可根据需求调整命名规则) const paramNames = (data.requiredLibs || []).map(lib => lib.split('/').pop() || lib); // 创建函数并传入库 let func = new Function(...paramNames, `return ${data.jsCode}`)(...libValues); return await func.call(null, ...args); }
注意:需确保库已通过npm安装,且Vite能正确解析裸模块名;动态代码需使用约定的变量名调用库。
为什么直接在动态代码中加import会报错?
new Function创建的代码运行在非模块作用域中,浏览器无法解析裸模块名(如image-conversion)——浏览器无法识别该模块的实际URL路径。即使在模块中使用new Function,其代码也不会自动继承模块的导入能力,必须显式注入依赖。
内容的提问来源于stack exchange,提问作者Finn
相关产品推荐
相关产品推荐

