Webpack自定义Loader删除Terser无法识别冗余代码相关问题咨询
问题解答
问题1:需求实现方案合理性判断
- 用Loader实现完全合理。Loader的核心定位就是对单个模块的源代码做预处理转换,你的需求是针对特定模块内的
SvgsMap对象做属性过滤,属于单模块源码转译场景,完全匹配Loader的适用范围。 - 不需要使用Plugin:Plugin的作用是介入webpack全构建流程,处理跨模块、构建产物、流程控制类的需求,对你的场景来说太重,没有必要。
- 替代方案:更推荐用AST语法树解析的方式实现,比VM执行更安全,不会意外执行源码中的副作用代码,稳定性更高。
问题2:VM使用错误说明
你的VM用法确实存在问题:vm.Script.createCachedData()是用于缓存脚本编译结果、加速后续重复执行同一段脚本的接口,返回的是二进制缓存数据,不是你要的解析后的JS对象,也不能直接转成可输出的源码。
如果坚持用VM实现,正确的逻辑步骤是:
- 创建VM上下文,执行传入的source代码,拿到内存中的
SvgsMap对象 - 基于白名单过滤
SvgsMap的属性 - 手动将过滤后的对象序列化成符合语法的JS代码字符串,替换原source中的
SvgsMap定义
VM方案示例代码
const vm = require('vm'); const whitelists = ["map1"]; const loaderFn = function (source) { try { const context = {}; // 执行源码并把SvgsMap挂载到上下文对象 vm.runInNewContext(source + '; context.SvgsMap = SvgsMap;', context); // 过滤白名单属性 const filteredMap = {}; whitelists.forEach(key => { if (context.SvgsMap[key]) filteredMap[key] = context.SvgsMap[key]; }); // 序列化生成新的源码 const newMapStr = `const SvgsMap = { ${Object.entries(filteredMap).map(([k, v]) => `${k}: ${v.toString()}`).join(',\n')} }`; return newMapStr; } catch (err) { console.error('VM处理出错', err); return source; } }; module.exports = loaderFn;
注意:VM方案会执行源码中的所有逻辑,如果目标文件存在副作用代码,可能会出现预期外的问题,更推荐使用下面的AST方案。
更推荐的AST方案示例
使用Babel生态的语法解析工具,只分析代码结构不执行代码,安全性更高。
首先安装依赖:npm install @babel/parser @babel/traverse @babel/generator @babel/types -D
const parser = require('@babel/parser'); const traverse = require('@babel/traverse').default; const generate = require('@babel/generator').default; const t = require('@babel/types'); const whitelists = ["map1"]; const loaderFn = function (source) { try { // 解析源码为AST语法树 const ast = parser.parse(source, { sourceType: 'module' }); // 遍历AST找到SvgsMap的定义节点 traverse(ast, { VariableDeclarator(path) { if (path.node.id.name === 'SvgsMap' && t.isObjectExpression(path.node.init)) { // 过滤属性,只保留白名单内的项 path.node.init.properties = path.node.init.properties.filter(prop => { return t.isIdentifier(prop.key) && whitelists.includes(prop.key.name); }); } } }); // 把修改后的AST生成新的源码 const { code } = generate(ast, {}, source); return code; } catch (err) { console.error('AST处理出错', err); return source; } }; module.exports = loaderFn;
内容的提问来源于stack exchange,提问作者choz
相关产品推荐
相关产品推荐

