How to debug a VueJS 3 Typescript project with VS Code and Chrome using SourceMaps (with Vue CLI and Webpack)?
Asked Answered
R

1

12

Tl;dr
The VS Code debugger always says Unbound breakpoint but setting break points in chrome dev tools works and opens the respected file in VS Code automatically (after that the VS Code debugger for that file works). Also source (map) files in chrome have weird names like HelloWorld.vue?4a7c.

I set up a new VueJS 3 project with Typescript using vue create my_project. I selected Typescript, Babel and as Vue version 3.

I'm trying to get the VS Code debugger up and running to debug my project the way I used to with other projects like Java. Therefore I copied the best practices from the VS Code recipe sides. (Since there is no VueJS Typescript debugging recipe I used the one for VueJS and Typescript and tried to mix them)

The actual problem is, when I set a breakpoint in VS Code it says Unbound breakpoint. My assumption is that VS Code can't map any of the source map files to my source files indicating that webpack somehow messes up the file naming or my configuration for file mapping is wrong.

What I got working so far is that when I inspect the project with chrome developer tools I see e.g. a main.ts where I can set breakpoints and once the breakpoint is hit the file opens in VS Code and the debugger (at least for this specific file) works as expected. When it comes to the .vue files things are a bit more messed up. In chrome the .vue files are obfuscated/compiled but there are files named the following way [file-name].vue?[4-digit-hex-value] (e.g. HelloWorld.vue?4a7c) which contains the actual source and setting break points in there works and the file will be opened in VS Code automatically.

If anybody could provide a configuration that works in their setup that would help me a lot.

So far I have the following config files:

launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "chrome",
            "request": "launch",
            "name": "vuejs: chrome",
            "url": "http://localhost:8080",
            "webRoot": "${workspaceFolder}/src",
            "breakOnLoad": true,
            "pathMapping": {
              "/_karma_webpack_": "${workspaceFolder}"
            },
            "sourceMapPathOverrides": {
                "webpack:/*": "${webRoot}/*",
                "/./*": "${webRoot}/*",
                "/src/*": "${webRoot}/*",
                "/*": "*",
                "/./~/*": "${webRoot}/node_modules/*"
            },
            "preLaunchTask": "serve"
        }
    ]
}

tasks.json

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "serve",
            "type": "npm",
            "script": "serve",
            "isBackground": true,
            "problemMatcher": [{
                "base": "$tsc-watch",
                "background": {
                    "activeOnStart": true,
                    "beginsPattern": "Starting development server",
                    "endsPattern": "Compiled successfully"
                }
            }],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

(npm serve just executes the in package.json defined script "serve": "vue-cli-service serve")

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "useDefineForClassFields": true,
    "baseUrl": ".",
    "types": [
      "webpack-env"
    ],
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

vue.config.js

const { defineConfig } = require('@vue/cli-service')

module.exports = defineConfig({
  transpileDependencies: true,
  configureWebpack: {
    devtool: 'source-map',
  }
})
Ragin answered 6/4, 2022 at 4:17 Comment(1)
Oddly enough, your configuration was the only one I got my solution to debug and hit breakpoints. Thank you for posting.Lucylud
R
10

The solution I'm going with for now is the following:

(I don't know what happens behind the scenes but somehow it works - really don't know what source maps are generated or not)

I just use the official VS Code attach Chrome debug setup and added a pre launch task that start the developer server which is serving the application in dev mode. Somehow this is all it needs to work with a fully functional VS Code debugger and the VueJS 3 Typescript application (and actually also Tailwind installed).

launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "pwa-chrome",
            "request": "launch",
            "name": "My VueJS Chrome",
            "url": "http://localhost:8080",
            "webRoot": "${workspaceFolder}",
            "preLaunchTask": "serve",
            // "userDataDir": "${env:HOME}/.vscode/vscode-chrome-debug-userdatadir" 
            // This config is to always use the same configuration for the chrome app (system wide) 
            // therefore you can install the prefered extensions once and they will stay!
            // Taken from here: https://mcmap.net/q/555267/-run-vscode-chrome-debugger-with-its-extensions
        }
    ]
}

tasks.json (This is the official VueJS VS Code pre launch task recipe)

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "serve",
            "type": "npm",
            "script": "serve",
            "isBackground": true,
            "problemMatcher": [{
                "base": "$tsc-watch",
                "background": {
                    "activeOnStart": true,
                    "beginsPattern": "Starting development server",
                    "endsPattern": "Compiled successfully"
                }
            }],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

Just put the two files into the .vscode directory of the root of your project and you are ready to go!

OFF-TOPIC (Installation of tailwindcss):

Used the official setup guide from here - just adjusted to work with the vue cli create instead of vite.

1. Install tailwindcss, postcss and autoprefixer - also generate the tailwindcss config files

With npm:

npm install -D tailwindcss postcss autoprefixer

With yarn:

yarn add tailwindcss postcss autoprefixer

And now generate the config files:

npx tailwindcss init -p

2. Add the following two lines to the tailwind.config.js file:
The lines of importance are:

    "./index.html",
    "./src/**/*.{vue,js,ts,jsx,tsx}",

Therefore the file should look like this:

module.exports = {
  content: [
    "./index.html",
    "./src/**/*.{vue,js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

3. Create a ./src/index.css file and add the @tailwind directives for each of Tailwind’s layers.

@tailwind base;
@tailwind components;
@tailwind utilities;

4. Import the newly-created ./src/index.css file in your ./src/main.js file.

import { createApp } from 'vue'
import App from './App.vue'
import './index.css'

createApp(App).mount('#app')

Notice the import './index.css'

Thats it. Just start using it with npm run serve or yarn serve or the setup described in the top of this answer.

Ragin answered 6/4, 2022 at 19:49 Comment(1)
This answer works fine with @vue/cli 5.x and vue 2 ass well. Thanks.Enzyme

© 2022 - 2024 — McMap. All rights reserved.