要保留Loader转换前的最原始源码,关键在于组合启用devtool:'source-map'或'hidden-source-map'、各Loader显式开启sourceMap参数(如Babel设sourceMap:true、ts-loader禁用transpileOnly)、禁用concatenateModules和别名干扰,并确保.map文件中sources数组为真实路径且sourcesContent非空。

要让 SourceMap 保留 Loader 转换前的最原始源码(比如 TypeScript、JSX、ES6+ 或 Vue/SFC 中的 script 部分),关键不是靠 module-source-map(该术语并不存在于 Webpack 官方配置中),而是通过正确组合 devtool 选项与 Loader 的 sourceMap 参数,并禁用可能覆盖原始内容的中间处理。
确保每个 Loader 显式启用 sourceMap 输入输出
Webpack 不会自动为 Loader 传递或生成 SourceMap,必须逐层开启:
- Babel Loader:添加
options.sourceMap: true,且确保babel.config.js中未设置inputSourceMap: false - TypeScript Loader(如
ts-loader):启用transpileOnly: false(默认)并设compilerOptions.sourceMap: true;若用fork-ts-checker-webpack-plugin,需额外配typescript: { memoryLimit: 4096, diagnosticOptions: { pretty: true } }保证映射链完整 - Vue Loader:v15+ 默认支持,但需确认
vueOptions.compilerOptions.preserveWhitespace: false不干扰行号;SFC 中的<script lang="ts"></script>需由 ts-loader 处理,不能跳过
选用能穿透多层转换的 devtool 值
devtool: 'source-map' 或 'inline-source-map' 是基础要求,但它们本身不保证“最原始”——真正起作用的是是否保留 sourcesContent 字段:
- 必须避免使用
eval-*类型(如eval-source-map),它们只记录模块路径,不内嵌原始内容 - 推荐
devtool: 'source-map'(生成独立 .map 文件)或'hidden-source-map'(用于 Sentry 等平台),二者均默认写入sourcesContent - 若发现 .map 文件中
sourcesContent为空,检查是否被optimization.minimizer(如 Terser)清除了——需在 TerserPlugin 中显式设sourceMap: true
关闭干扰原始映射的优化行为
某些 Webpack 行为会切断映射链,导致最终 .map 只指向 Loader 输出,而非原始文件:
- 禁用
optimization.concatenateModules: true(即 Module Concatenation),它会把多个模块合并为一个函数,丢失单个源文件边界 - 避免
optimization.splitChunks对源码做非预期拆分;若必须拆分,确保每个 chunk 的 SourceMap 单独生成且sources数组包含真实路径 - 移除
resolve.alias中对源码路径的重定向(如@/src→src/),别名可能导致sources字段写入别名路径而非物理路径,影响调试器定位
验证原始源码是否真正保留
打包后打开生成的 .js.map 文件,直接查看 JSON 内容:
- 确认
sources数组里是类似["src/index.ts", "src/utils.ts"]这样的真实相对路径,而非["webpack:///./src/index.ts"] - 确认
sourcesContent是非空数组,且每个元素是对应源文件的完整字符串内容(可复制一段验证是否匹配原始 .ts 文件) - 在 Chrome DevTools 的 Sources 面板中,展开
webpack://→ 查看能否展开到具体.ts或.jsx文件,并断点执行——能停在原始行号即说明成功


















