Vue-cli: Weird issue with source maps

Created on 20 Nov 2018  ·  20Comments  ·  Source: vuejs/vue-cli

Version

3.1.1

Reproduction link

https://github.com/farzadmf/vue-cli-sourcemap-issue

Node and OS info

Node 11.0.0 / yarn 1.12.3 / Windows 10

Steps to reproduce

  1. Run "yarn serve" to start the application
  2. Open Chrome devtools and start searching for "HelloWorld.vue"

What is expected?

When I search for HelloWorld.vue in Chrome devtools, I should see a single file being listed, and when I open that file, I should see my actual source code there

What is actually happening?

When I search for "HelloWorld.vue", I see multiple files being listed with names such as HelloWorld.vue?e24f ... (and a few others with different hash values)


  • I developed an app a few months ago with Vue, and I don't remember having this problem; maybe I've forgotten ...!
  • The version of vue-cli I have is 3.1.3, but it's not available in the drop-down
  • My Chrome version is 70.0.3538.102
enhancement help wanted cli-service build

Most helpful comment

@farzadmf HI 😃 you can do this: ⬇️ in your vue.config.js config file:

module.exports = {
  configureWebpack: (config) => {
    if (process.env.NODE_ENV === 'development') {
      config.devtool = 'eval-source-map';

      config.output.devtoolModuleFilenameTemplate = info => info.resourcePath.match(/^\.\/\S*?\.vue$/)
        ? `webpack-generated:///${info.resourcePath}?${info.hash}`
        : `webpack-yourCode:///${info.resourcePath}`;

      config.output.devtoolFallbackModuleFilenameTemplate = 'webpack:///[resource-path]?[hash]';
    }
  },
};

image

this idea source is The joy that is Source Maps (with Vue.js and TypeScript) 🔗

All 20 comments

We'll look into this.

However, Sourc emaps in chrome have always been unstable to me and many other people, and I remember that I experiences this issue specifically and could only resolve it by switching to a different kind of source map.

So you can try using different values for the devtool setting of webpack:

// vue.config.js
module.exports = {
  configureWeback: {
    // See available sourcemaps:
    // https://webpack.js.org/configuration/devtool/#devtool
    // and try out different ones
    devtool: 'eval-source-map'

  }
}

@LinusBorg Thank you for your answer, I tried your solution (with a bit of fixing the typos ;) ), but, to be honest, I don't think I see any difference :(

@farzadmf HI 😃 you can do this: ⬇️ in your vue.config.js config file:

module.exports = {
  configureWebpack: (config) => {
    if (process.env.NODE_ENV === 'development') {
      config.devtool = 'eval-source-map';

      config.output.devtoolModuleFilenameTemplate = info => info.resourcePath.match(/^\.\/\S*?\.vue$/)
        ? `webpack-generated:///${info.resourcePath}?${info.hash}`
        : `webpack-yourCode:///${info.resourcePath}`;

      config.output.devtoolFallbackModuleFilenameTemplate = 'webpack:///[resource-path]?[hash]';
    }
  },
};

image

this idea source is The joy that is Source Maps (with Vue.js and TypeScript) 🔗

Good for you @kkxujq that it works, but for me, it's still the same :(
image

And this is the structure of my webpack-yourcose://:
image

I don't have an src folder the same as you :( ?! and only my pure ts files are listed

Good for you @kkxujq that it works, but for me, it's still the same :(
image

And this is the structure of my webpack-yourcose://:
image

I don't have an src folder the same as you :( ?! and only my pure ts files are listed

if your project is ts files, please use this ⬇️ config \:

// vue.config.js
configureWebpack: config => {
    if (process.env.NODE_ENV === 'development') {
      config.devtool = 'eval-source-map';
      config.output.devtoolModuleFilenameTemplate = info =>

        info.resourcePath.match(/\.vue$/) && !info.identifier.match(/type=script/)  // this is change ✨ 
          ? `webpack-generated:///${info.resourcePath}?${info.hash}`
          : `webpack-yourCode:///${info.resourcePath}`;

      config.output.devtoolFallbackModuleFilenameTemplate = 'webpack:///[resource-path]?[hash]';
    }
  }

like this \:
image

You can try this method, good luck \:)

Thanks you @kkxujq for your answer. It seems more promising now, but I feel something is still missing:

image

  • As you see, as example, I don't see App.vue in webpack-yourcode:// section
  • The file seems to be off! If you look, my source code is starting at line 39 with all those empty lines before it
  • Good thing that my breakpoint is working

It would be ideal if I could somehow see my file as I see it in my editor (including template, script, and style) ...

@kkxujq - this is (I think) bloody brilliant!

I've been struggling with multiple files for as long as I can remember, then this week decided to tackle it.

I worked out that there are at least 4 copies of files (sometimes 10, I don't know why) because of the template, script and style parts; each gets their own file.vue?xxxxx file.

The JS code you referenced above from that link worked perfectly, thanks!

The TS code took some tweaking:

    if (process.env.NODE_ENV === 'development') {
      config.devtool = 'eval-source-map'
      config.output.devtoolFallbackModuleFilenameTemplate = 'webpack:///[resource-path]?[hash]'
      config.output.devtoolModuleFilenameTemplate = info => {
        const isVue = info.resourcePath.match(/\.vue$/)
        const isScript = info.identifier.match(/type=script/)
        return isVue && !isScript
          ? `webpack-vue:///${info.resourcePath}`
          : `webpack-generated:///${info.resourcePath}?${info.hash}`
      }
    }

I seemed to have to swap the output paths around; I assume this holds that a Vue file is not a script?

Now, I can see all my .vue files in webpack-vue (I renamed this, and it seems to show first) which is extremely useful:

image

Hopefully this won't just be a fluke. When Webpack works or is intuitive, it's amazing. When it's not it's like pulling teeth.

Going to get on and run with the project now... hopefully it will stand up to the rigours of development!

I was noticing the same sort of issue existed in Firefox as well. The suggested fix narrowed the list down from 5 duplicates (in my case) to two. However, Firefox wasn't showing the hash as part of the listing, so it took a bit of work to find out which one was getting through.

Once I did, however, I was able to look at what else was in the 'info' used to generate the listing, and noticed that the 'moduleId' for the one I wanted to keep was always empty. So here is the final, adjusted version that worked for me.

configureWebpack: (config) => {
    if (process.env.NODE_ENV === 'development') {
      config.devtool = 'eval-source-map';
      config.output.devtoolFallbackModuleFilenameTemplate = 'webpack:///[resource-path]?[hash]';
      config.output.devtoolModuleFilenameTemplate = info => {
        const isVue = info.resourcePath.match(/\.vue$/);
        const isScript = info.query.match(/type=script/);
        const hasModuleId = info.moduleId !== '';

        // Detect generated files, filter as webpack-generated
        if (
          // Must result from vue-loader
          isVue
          // Must not be 'script' files (enough for chrome), or must have moduleId (firefox)
          && (!isScript || hasModuleId)
        ) {
          let pathParts = info.resourcePath.split('/');
          const baseName = pathParts[pathParts.length - 1];
          // prepend 'generated-' to filename as well, so it's easier to find desired files via Ctrl+P
          pathParts.splice(-1,1,`generated-${baseName}`);
          return `webpack-generated:///${pathParts.join('/')}?${info.hash}`;
        }

        // If not generated, filter as webpack-vue
        return `webpack-vue:///${info.resourcePath}`;
      }
    }

Also worth noting that, while it does filter the listings and allow breakpoints to be placed...the debugger doesn't get refreshed with the new contents when hot-reloaded. You have to reload the page to get that updated - severely limiting the effectiveness of hot-reloading.

Useful tips here, thank you all! I did some playing around myself and ended up with this for a vanilla JS/Babel setup:

config.output.devtoolModuleFilenameTemplate = (info) => {
  const isGeneratedDuplicate = info.resourcePath.match(/\.vue$/) && info.allLoaders;
  if (isGeneratedDuplicate) {
    return `webpack-generated:///${info.resourcePath}?${info.hash}`;
  }
  return `webpack:///${path.normalize(info.resourcePath)}`;
};
config.output.devtoolFallbackModuleFilenameTemplate = 'webpack:///[resource-path]?[hash]';

The regex-based solution by @kkxujq worked, but it felt kinda fragile to me, so I was wondering if there was something else that would work as a detection mechanism, and it turns out that allLoaders is an empty string for the original component files we're interested in (or at least that's the case for our setup), but non-empty for all the webpack generated stuff.

Also, in my case .js files ended up with a relative resource path that would look like ./src/utils/index.js, while the .vue files I was interested in ended up like src/components/foo.vue. This made the sources tree in Chrome have two different top level directories, so I threw in a path.normalize() which solved that issue.

I accidentally found a way to find the right vue file in Chrome devtools:
press cmd+opt+f to search through files:
type <code> file:<filename.vue>.
e.g:
image
I didn't find any syntax rules of the Chrome Search tool on the internet.
Just tried file: and it seems working. 😃
Hope it helps

UPDATE:

I debugged into the devtools and found that the Chrome Search tool truly supports file:<filename> (or f:<filename>) syntax:
image

Useful tips here, thank you all! I did some playing around myself and ended up with this for a vanilla JS/Babel setup:

config.output.devtoolModuleFilenameTemplate = (info) => {
  const isGeneratedDuplicate = info.resourcePath.match(/\.vue$/) && info.allLoaders;
  if (isGeneratedDuplicate) {
    return `webpack-generated:///${info.resourcePath}?${info.hash}`;
  }
  return `webpack:///${path.normalize(info.resourcePath)}`;
};
config.output.devtoolFallbackModuleFilenameTemplate = 'webpack:///[resource-path]?[hash]';

The regex-based solution by @kkxujq worked, but it felt kinda fragile to me, so I was wondering if there was something else that would work as a detection mechanism, and it turns out that allLoaders is an empty string for the original component files we're interested in (or at least that's the case for our setup), but non-empty for all the webpack generated stuff.

Also, in my case .js files ended up with a relative resource path that would look like ./src/utils/index.js, while the .vue files I was interested in ended up like src/components/foo.vue. This made the sources tree in Chrome have two different top level directories, so I threw in a path.normalize() which solved that issue.

Nice try, but actual source code for one of my components ended up in

webpack-generated:///src/components/my-component/generated-index.vue?749d

don't know why.

It's not only miss, there are dozens of them.

Works for me (no "*.ts" in my project).

const isDevelopment = process.env.NODE_ENV === 'development';

let webpackConfigHelpers = {
  dump: function(fileName, objectToDump, append = false) {
    const pathNodeModulesCache = path.resolve(__dirname, 'node_modules', '.cache');

    fs.mkdirSync(pathNodeModulesCache, { recursive: true });

    let _path = path.resolve(pathNodeModulesCache, fileName);
    let content = JSON.stringify(objectToDump, null, 2);

    if (append) {
      fs.appendFileSync(_path, content);
    } else {
      fs.writeFileSync(_path, content);
    }
  },
};

  // . . . . .

    if (isDevelopment && WEBPACK_DEV_FIX_SOURCE_MAPS) {
      console.log('WEBPACK_DEV_FIX_SOURCE_MAPS');
      webpackConfig.devtool = 'eval-source-map';

      webpackConfigHelpers.dump('sourceMapping.txt', '');

      webpackConfig.output.devtoolModuleFilenameTemplate = info => {
        webpackConfigHelpers.dump('sourceMapping.txt', info, true);

        let resPath = path.normalize(info.resourcePath);

        let generated = info.allLoaders;

        if (generated) {
          return `webpack-generated:///${resPath}?${info.hash}`;
        } else {
          return `webpack-sourcecode:///${resPath}`;
        }
      };

      webpackConfig.output.devtoolFallbackModuleFilenameTemplate = 'webpack:///[resource-path]?[hash]';
    }

node_modules/.cache/sourceMapping.txt is for debug

After tinkering with the various configurations and suggestions shared here-in by others, I thought I'd also share the present incarnation of the "_I'm desperate for source maps_" config I came up with... which is applied to a vue-cli created project (vue create my-project):

Note: not a typescript project...

vue.config.js

let path = require('path')

module.exports = {
  configureWebpack: config => {
    if (process.env.NODE_ENV === 'development') {
      // See available sourcemaps:
      // https://webpack.js.org/configuration/devtool/#devtool
      config.devtool = 'eval-source-map'
      // console.log(`NOTICE: vue.config.js directive: ${config.devtool}`)

      config.output.devtoolModuleFilenameTemplate = info => {
        let resPath = path.normalize(info.resourcePath)
        let isVue = resPath.match(/\.vue$/)
        let isGenerated = info.allLoaders

        let generated = `webpack-generated:///${resPath}?${info.hash}`
        let vuesource = `vue-source:///${resPath}`

        return isVue && isGenerated ? generated : vuesource
      }

      config.output.devtoolFallbackModuleFilenameTemplate =
        'webpack:///[resource-path]?[hash]'
    }
  },
}

Results (chrome):

Sources


Console warnings, tho?

Now, if someone can clue us in on how to coerce the [Vue-warn]: ... messages in the console to jump over to these "_vue-source_" source maps, rather than the webpack-generated maps...?? 👀

Sigh, I don't understand why achieving a good debugging experience is (relatively) much easier with the productionSourceMap flag for builds... is this due to the complexities of hot-module reloading, as I think someone else may've already inferred?

What should i really expect here? Is it possible to get errors in the browser that actually points to the correct row and correct file that looks like your own code? Or will it always point to a generated file that looks like a render function?

What should i really expect here? Is it possible to get errors in the browser that actually points to the correct row and correct file that looks like your own code? Or will it always point to a generated file that looks like a render function?

@rnenjoy - there are various source map generators, I prefer config.devtool = 'eval-source-map' in development as you get a 1:1 likeness with your source files.

What should i really expect here? Is it possible to get errors in the browser that actually points to the correct row and correct file that looks like your own code? Or will it always point to a generated file that looks like a render function?

@rnenjoy - there are various source map generators, I prefer config.devtool = 'eval-source-map' in development as you get a 1:1 likeness with your source files.

I've tried every source map options available. But i've never managed to get 1:1 likeness and that it points to the correct place. Is it because i'm using nuxt or anything? My files are always generated.

I'm probably not well-versed in the details of WebPack to answer properly, but did you try the ones that say "original source" from here?

https://webpack.js.org/configuration/devtool/

I'm probably not well-versed in the details of WebPack to answer properly, but did you try the ones that say "original source" from here?

https://webpack.js.org/configuration/devtool/

Yeah all of them. Using some code above i managed the your-code thingy and it pointed to untouched files. But then the line was pointing all wrong so it didnt make any sense.

I'm probably not well-versed in the details of WebPack to answer properly, but did you try the ones that say "original source" from here?
https://webpack.js.org/configuration/devtool/

Yeah all of them. Using some code above i managed the your-code thingy and it pointed to untouched files. But then the line was pointing all wrong so it didnt make any sense.

Seems like it works with pages and top level components. BUt not child components.

We'll look into this.

However, Sourc emaps in chrome have always been unstable to me and many other people, and I remember that I experiences this issue specifically and could only resolve it by switching to a different kind of source map.

So you can try using different values for the devtool setting of webpack:

// vue.config.js
module.exports = {
  configureWeback: {
    // See available sourcemaps:
    // https://webpack.js.org/configuration/devtool/#devtool
    // and try out different ones
    devtool: 'eval-source-map'

  }
}

there's a typo error, it should be configureWebpack instead of configureWeback

Was this page helpful?
0 / 5 - 0 ratings