How to load library source maps using webpack?

JavascriptReactjsWebpack

Javascript Problem Overview


I'm building two projects with webpack; one is a library for the other.

Is it possible to consume the sourcemaps from my library project when building my wrapper project? I would like the ability to debug my library code from my wrapper UI.

My build works correctly in that the library is built in. The only issue is sourcemaps. The JavaScript I see in the browser debugger is uglified, because sourcemaps are unavailable.

Snippet of my project structure:

+-- my-ui/
    +-- dist/
        +-- my-ui.js
        +-- my-ui.js.map
    +-- node_modules/
        +-- my-lib/
            +-- dist/
                +-- bundle.js
                +-- bundle.js.map

Snippet from webpack.config.js:

module.exports = {
    entry: './src/js/main.jsx',
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'my-ui.js',
        library: 'my-ui',
        libraryTarget: 'umd'
    },
    devtool: 'source-map',
    module: {
        loaders: [
            {test: /\.jsx?$/, loader: 'babel', include: path.join(__dirname, 'src')}
        ]
    },
    plugins: [
        new Clean('dist'),
        new HtmlWebpackPlugin({
            template: 'src/index.html',
            inject: true
        })
    ]
};

Javascript Solutions


Solution 1 - Javascript

I finally figured out my issue...

Thanks to @BinaryMuse for the tip on source-map-loader. This indeed was the right way to go, though it wasn't working for me initially.

What I eventually realized is that I need to enable the source-map-loader for webpack in both "my-lib" and "my-ui". Without source-map-loader in "my-lib" webpack config, the source-map-loader inside "my-ui" errors (with a warning message sadly) because it cannot locate source maps for transitive dependencies of "my-lib". Apparently the source maps are so good that source-map-loader is able to peek at all aspects of the dependency tree.

Also of note, I ran into an issue using source-map-loader in conjunction with react-hot-loader. See, react-hot-loader does not include source maps. When source-map-loader tries to find them (because it's just scanning everything), it cannot and aborts everything.

Ultimately, I'd like source-map-loader to be more fault tolerant, but when set up correctly, it does work!

devtool: 'source-map',
module: {
    preLoaders: [
        {test: /\.jsx?$/, loader: 'eslint', exclude: /node_modules/},
        {test: /\.jsx?$/, loader: 'source-map', exclude: /react-hot-loader/}
    ],
    loaders: [
        {test: /\.jsx?$/, loader: 'raect-hot!babel', exclude: /node_modules/}
    ]
}

Solution 2 - Javascript

You should be able to use any of the eval source map options that Webpack provides.

Really that just amounts to setting the right devtool option in your webpack.config.js for the my-lib project.

devtool: 'eval',

eval and eval-source-map should both work.

See the Webpack documentation for the various options.

Solution 3 - Javascript

I am using create-react-app and this is how I Fixed it (without running eject cmd)

> Note : If your app is already overriding webpack config using react-app-rewired you can ignore first three steps.

  • npm i react-app-rewired -D - This will help you to override webpack configuration.
  • package.json - change your scripts, replace react-scripts with react-app-rewired
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-app-rewired eject"
  }

  • config-overrides.js - create this file in the parent level of the app.

  • npm i source-map-loader -D - To load source maps (assuming that your lib's dist has source map file). It doesn't matter which build tool(ex: Rollup, webpack or parcel) you use to generate sourcemap.

  • Copy below code in config-overrides.js

module.exports = {
  webpack: (config, env) => {
    // Load source maps in dev mode
    if (env === 'development') {
      config.module.rules.push({
        test: /\.(js|mjs|jsx|ts|tsx)$/,
        use: ['source-map-loader'],
        enforce: 'pre',
      });

      // For `babel-loader` make sure that sourceMap is true.
      config.module.rules = config.module.rules.map(rule => {
        // `create-react-app` uses `babel-loader` in oneOf
        if (rule.oneOf) {
          rule.oneOf.map(oneOfRule => {
            if (
              oneOfRule.loader &&
              oneOfRule.loader.indexOf('babel-loader') !== -1
            ) {
              if (oneOfRule.hasOwnProperty('options')) {
                if (oneOfRule.options.hasOwnProperty('sourceMaps')) {
                  // eslint-disable-next-line no-param-reassign
                  oneOfRule.options.sourceMaps = true;
                }
              }
            }
          });
        }
        return rule;
      });
    }

    return config;
  },
};


  • Restart your app (if it's already running). source files get loaded in different locations, based on path in map file. Check all folders patiently :)

> Note :

  1. Your source maps get loaded in one of the folder(ex : localhost:3000 or webpack:/// ) based on path it reads from xxx.js.map file.
  2. If you are using rollup for your libs, please make sure you give proper path in the configuration file (output.sourcemapPathTransform ), This will help to load sourcemaps in the proper location.

Solution 4 - Javascript

My answer is similar to @Jeff Fairley's and I had the same directory structure, with the only difference being that I was using module: { rules: [] } instead of his module: { preLoaders: [..], loaders: [...]}. This is what I had to add to my webpack.config.js file:

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

Then I ran

npm i -D source-map-loader

and I saw the TypeScript source code of the dependency I was using when clicking through tracebacks in Chrome's devtools. See the Webpack docs for source-map-loader.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJeff FairleyView Question on Stackoverflow
Solution 1 - JavascriptJeff FairleyView Answer on Stackoverflow
Solution 2 - JavascriptNoah SolomonView Answer on Stackoverflow
Solution 3 - JavascriptYugandhar PathiView Answer on Stackoverflow
Solution 4 - JavascriptBoris VView Answer on Stackoverflow