Home > Software engineering >  Babel-loader mangles Webpack's source map sources for node_modules
Babel-loader mangles Webpack's source map sources for node_modules

Time:09-21

Using babel-loader with Webpack, if one does not exclude node_modules, Webpack's source maps will (incorrectly) use the path listed in each module's own source maps, rather than generating new paths.

For example, I'm using module a, which is laid out like the following:

node_modules/
--a/
----dist/
------index.js
------index.js.map
----src/
------index.ts

Inside that source map there is "sources":["../src/index.ts"], which is reasonable and correct.

However, when Webpack consumes this, 'webpack:///../src/index.ts' will be one of the sources of the source map. This is not a TS project and that entry will disappear if the usage of a is commented out, so there is no confusion as to where this entry is coming from.

If I were to add exclude: /node_modules/ to my babel-loader config, the correct source is displayed as "webpack:///./node_modules/a/dist/index.js".

How can I correct this? Using these source maps is rather impossible because they contain relative paths from deep within a module. I have no way of knowing on larger project with dozens of modules what ../src/index.ts is actually referring to.

Webpack config:

const { resolve } = require('path');

module.exports = function() {
    return {
        module: {
            rules: [
                {
                    test: /\.m?[jt]sx?$/,
                    //exclude: /node_modules/,  // Uncommenting "fixes" the sources
                    loader: 'babel-loader',
                },
            ]
        },
        mode: 'production',
        devtool: 'source-map',

        output: {
            filename: 'ssr-bundle.js',
            path: resolve(__dirname, 'dist'),
            libraryTarget: 'commonjs2',
        },
        externals: {
            preact: 'preact'
        },
        target: 'node',
    }
}

Example entry point to use as reproduction material:

import { h } from 'preact';
import { computed, signal } from '@preact/signals';

const currentState = signal('idle');
const isFormEnabled = computed(() => currentState.value !== 'loading');

export default function App() {
    return h('form', {}, [
        h('input', { type: 'text', disabled: !isFormEnabled.value })
    ]);
}

(@preact/signals is a from the above example. It's not important and can be swapped out with anything.)

"@babel/core": "^7.19.1",
"babel-loader": "^8.2.5",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"

CodePudding user response:

I had some annoying experiences with source map from node_modules previously . Then I came up with a best solution is to use a community source-map-loader rather than just only use the built-in source map after having done some experiments without a desire results. In short, you might find it set up properly with this setup:

{
  devtool: 'source-map',
  module: {
    rules: [
      {
        test: /\.js$/,
        enforce: "pre",
        use: ["source-map-loader"],
      },
    ],
  },
  // ...
}
  • Related