Webpack打包后如何保留并获取原始源文件名称?
如何在打包后仍获取原始源文件名创建追踪对象
下面提供几种可靠的方案,解决Webpack打包后__filename指向打包文件的问题,让你可以安全复用追踪代码:
方案1:Webpack DefinePlugin 编译时注入原始文件名
直接通过Webpack的内置插件,在编译阶段为每个模块注入原始文件名,运行时直接使用即可:
- 修改Webpack配置文件,添加
DefinePlugin:
const webpack = require('webpack'); const path = require('path'); module.exports = { // 其他配置项(入口、输出等) plugins: [ new webpack.DefinePlugin({ // 注入仅保留文件名的原始路径,也可根据需求改为完整路径 __ORIGINAL_FILENAME__: JSON.stringify(path.basename(__resourcePath)) }) ] };
- 在你的TS/JS源文件中直接使用:
const TRACER = new Tracker(__ORIGINAL_FILENAME__);
__resourcePath是Webpack编译时提供的当前模块的原始文件路径,通过path.basename可以只提取文件名,避免路径过长。
方案2:Babel插件注入自定义标识
如果项目使用Babel编译,可以写一个极简的Babel插件,自动为每个文件注入原始文件名:
- 编写Babel插件(比如
inject-original-filename.js):
const path = require('path'); module.exports = function({ types: t }) { return { visitor: { Program(path, state) { // 获取当前文件的原始路径,提取文件名 const fileName = path.basename(state.file.opts.filename); // 在文件顶部插入常量定义 path.unshiftContainer('body', t.variableDeclaration('const', [ t.variableDeclarator( t.identifier('__ORIGINAL_FILENAME__'), t.stringLiteral(fileName) ) ])); } } }; };
- 在Babel配置(比如
.babelrc或babel.config.js)中引入该插件:
{ "plugins": ["./inject-original-filename.js"] }
- 源文件中直接使用:
const TRACER = new Tracker(__ORIGINAL_FILENAME__);
这个方案不依赖Webpack,Rollup等其他打包工具也能兼容。
方案3:Source Map 运行时解析(调试场景专用)
如果无法修改构建配置,可通过Source Map反向解析原始文件名,但该方案运行时开销大,仅适合调试:
const { SourceMapConsumer } = require('source-map'); const path = require('path'); async function getOriginalFilename() { try { // 通过抛出错误获取栈信息 throw new Error(); } catch (e) { const stackLine = e.stack?.split('\n')[2]; if (!stackLine) return __filename; // 提取栈中的行号、列号和打包文件路径 const match = stackLine.match(/at .+ \((.+):(\d+):(\d+)\)/); if (!match) return __filename; const [, bundlePath, line, column] = match; // 加载对应的Source Map文件(需确保打包时生成了source map) const sourceMapUrl = `${bundlePath}.map`; const response = await fetch(sourceMapUrl); const sourceMapData = await response.json(); // 解析原始文件路径 const consumer = await new SourceMapConsumer(sourceMapData); const originalPos = consumer.originalPositionFor({ line: parseInt(line, 10), column: parseInt(column, 10) }); consumer.destroy(); return originalPos.source ? path.basename(originalPos.source) : __filename; } } // 注意:这里需要异步调用 const TRACER = new Tracker(await getOriginalFilename());
方案选择建议
优先选择方案1或方案2,这两种都是构建时注入,运行时无额外开销,且能保证文件名的准确性,完全满足你复制粘贴代码不失效的需求。方案3仅作为无法修改构建配置时的应急方案。
内容的提问来源于stack exchange,提问作者Grogi
相关产品推荐
相关产品推荐

