如何使用 VS Code 除錯 Vue.js 專案?

語言: CN / TW / HK

簡介

此教程會以一個全新的 Vue.js 專案作為模板進行配置,你可以跟隨教程一步步操作,也可以按照教程將配置新增到已有的專案中。

倉庫地址: https://github.com/mrlmx/debug-vuejs-project-with-vscode

建立專案

通過 vue 提供的create-vue 腳手架,建立一個 vue3 專案。

npm init [email protected]

注意:通過上述命令,建立的是基於 vite 的專案,而不是基於 webpack 的專案。

然後在 VS Code 中開啟建立後的專案:

code ./debug-vuejs-project-with-vscode
  • code 是 VS Code 自帶的命令,如果你執行時提示沒有此命令,可以看這裡設定一下。
  • debug-vuejs-project-with-vscode 是我的專案名稱。

生成 sourcemap 檔案

Vite

如果是通過create-vue 建立的專案,則修改 vite.config.ts 配置檔案,在開發環境生成 sourcemap 檔案。

export default defineConfig({
  build: {
    sourcemap: true,
  },
  // other configs...
});

更多配置,請參考: https://vitejs.dev/config/build-options.html#build-sourcemap

Vue Cli

如果是通過vue-cli 建立的專案,則修改 vue.config.js 配置檔案,在開發環境生成 sourcemap 檔案。

module.exports = {
  configureWebpack: {
    devtool: "source-map"
  }
  // other configs...
};

更多配置,請參考: https://cli.vuejs.org/guide/webpack.html

Webpack

如果是自己搭建的專案,則修改自己定義的 webpack 配置檔案,在開發環境生成 sourcemap 檔案。

module.exports = {
  devtool: "source-map",
  // other configs...
};

更多配置,請參考: https://webpack.js.org/configuration/devtool/#devtool

配置檔案

launch.json

通過如下步驟,建立 launch.json 配置檔案(如果你的專案中已經存在該檔案,則可跳過此步驟)

  1. 選擇左側選單中的 Debug icon,開啟除錯選單。
  2. 點選 create a launch.json file,建立一個新的配置檔案。
  3. 選擇 Web App(Edge),當然,你也可以選擇 Web App(Chrome)

生成的 launch.json 檔案大致長這樣(不同版本的 VS Code 可能略有不同):

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "pwa-msedge",
            "request": "launch",
            "name": "Launch Edge against localhost",
            "url": "http://localhost:8080",
            "webRoot": "${workspaceFolder}"
        }
    ]
}

將生成的 launch.json 檔案內容,替換為下方配置:

{
  "version": "0.2.0",
  "configurations": [
    {
      // 使用 Edge 瀏覽器除錯
      "type": "msedge",
      // 使用 Chrome 瀏覽器除錯
      // "type": "chrome",

      "request": "launch",
      "name": "vuejs: msedge",

      // 專案的訪問地址(需要改成你專案開發環境對應的地址和埠號)
      "url": "http://localhost:5173",

      "webRoot": "${workspaceFolder}",
      "pathMapping": {
        "/_karma_webpack_": "${workspaceFolder}"
      },
      "sourceMapPathOverrides": {
        "webpack:/*": "${webRoot}/*",
        "/./*": "${webRoot}/*",
        "/src/*": "${webRoot}/*",
        "/*": "*",
        "/./~/*": "${webRoot}/node_modules/*"
      },

      // 設定進入 debug 環境之前需要執行的任務。
      // 此名稱對應專案中 .vscode 目錄下 tasks.json 檔案中的 label 屬性)
      "preLaunchTask": "vuejs: start"
    }
  ]
}

上面的配置中,有以下幾點需要注意:

  • type :VS Code 的 Debug 型別。

    msedge
    chrome
    
  • url :瀏覽器啟動時訪問的地址。

    • 需要改為你專案的開發環境地址,如果一致則無需修改。
  • preLaunchTask :設定進入 debug 環境之前需要執行的任務。

    • 此名稱對應專案中 .vscode 目錄下 tasks.json 檔案中的 label 屬性。
    • tasks.json 檔案下面會建立。

更多資訊:

tasks.json

在專案的 .vscode 目錄建立 tasks.json 檔案,然後將下方內容貼上進去:

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "vuejs: start",
      "type": "npm",
      // 需要執行的命令(對應於 package.json 中的 scripts 命令)
      "script": "dev",
      "isBackground": true
    }
  ]
}

上面的配置在執行時,執行的命令是: npm run dev ,如果你的專案是其他的啟動命令,那麼修改為對應的 script 名稱即可。

注意: type 的其他可選值是 shell 或者 process ,可不要傻乎乎的改成 yarn

type :任務的型別。對於自定義任務,可以設定為 shellprocess

shell
process

更多資訊:

打斷點

咱們將 src/views/AboutView.vue 檔案的內容稍微改一下,然後打兩個斷點。

<script lang="ts" setup>
import { reactive, ref } from "vue";

const other = reactive([
  { name: "lmx", age: 18 },
  { name: "foo", age: 20 },
  { name: "bar", age: 12 },
]);
const count = ref(0);

const handlePlus = () => {
  console.log("plus before", count.value);
  count.value++;
  console.log("plus after", count.value);
};

const handleMinus = () => {
  console.log("minus before", count.value);
  count.value--;
  console.log("minus after", count.value);
};
</script>

<template>
  <div class="about">
    <h1>This is an about page</h1>
    <div>
      <p>{{ count }}</p>
      <button @click="handlePlus">plus</button>
      <button @click="handleMinus">minus</button>
      <hr style="margin: 20px 0" />
      <p v-for="item of other" :key="item.name">
        {{ item.name }}: {{ item.age }}
      </p>
    </div>
  </div>
</template>

在第 13 行和 第 19 行,分別打了 2 個斷點(在對應行號左邊,點選滑鼠左鍵即可打斷點):

注意事項

需要注意的是:一定要在啟動 Debug 前打好斷點,否則你將無法匹配到斷點。

啟動之後,在原始檔中新增新的斷點是無效的,執行中的編譯檔案無法匹配到新的斷點,除非修改原始檔的程式碼觸發編譯,這樣新生成的編譯檔案才會對映到新斷點。

我猜測的原因是:因為 *.vue 這種 SFC 格式的檔案,需要將 scripttemplatestyle 這 3 個模組拆分編譯,實際執行的是編譯後的 js 檔案,而且每次檔案修改或者重啟專案之後,都會編譯出新的檔案。

如果不提前打斷點,那麼原始檔和編譯後的檔案將不會關聯上。

彈窗提示

另外,我發現:不管是否提前打了斷點,在啟動時都會提示:

The task 'xxx' cannot be tracked. Make sure to have a problem matcher defined。

我搜了一下,暫時沒有找到特別完美的解決方案,這裡提供兩種蹩腳的方法:

方案一:

如果你不在意這個提示的話,可以每次都點選一下「Debug Anyway」按鈕,或者勾選一下「Remember my choice for this task」,以後每次執行的時候就不會提示了,所謂眼不見心不煩。

方案二:

把 launch.json 檔案中的 preLaunchTask 屬性去掉,Debug 之前自己手動啟動專案,反正配置 preLaunchTask 的目的就是自動幫你把專案啟動起來,所謂自己動手豐衣足食。

啟動 Debug

經過上述配置之後,就可以通過 Debug 模式啟動專案了,咱們來分別介紹一下「快捷鍵」和「手動啟動」這 2 種啟動方式。

快捷鍵:F5

如果你的專案只有 1 個 Debug 配置的話,可以直接通過 F5 快捷鍵啟動 Debug 模式,非常的簡單方便,推薦日常使用。

手動啟動

如果你的專案有多個 Debug 配置,launch.json 檔案的 configurations 陣列有多個配置物件。

這個時候 F5 快捷鍵啟動的就是第一個配置,如果你想要啟動其他 Debug 配置,就需要通過手動選擇了。

可以看到,點選「下拉選單」之後,展示了 2 個配置選項: vuejs: msedgevuejs: chrome

示例中 launch.json 配置檔案的內容是這樣的:

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

看到這裡,你應該已經把 debug 的環境配置好了,現在可以開始愉快的除錯了。

一些問題

在我寫這篇文章的過程中,也發現了幾個讓我頭痛的問題,這裡順帶提一下。

在開始說這些問題之前,咱們先看一下這張圖:

  • 標註 1:是咱們的程式碼原始檔。
  • 標註 2:是執行時命中斷點後,VS Code 自動開啟的編譯後的檔案。

    AboutView.vue?t=1661699383436
    t
    
  • 標註 3:是第一個斷點,行號是 13。
  • 標註 4:是第二個斷點,行號是 19。

1. 必須先打斷點

我們可以看到,在執行過程中,其實斷點命中是編譯後的檔案。

前面我們提到,在執行 Debug 模式之後再去原始檔中新增新斷點,正常情況下是無法匹配的。

那如果我在除錯過程中,想要新增新斷點該怎麼辦呢?

方法 1:直接在「編譯後的檔案」中打新斷點。

此方法的弊端是:他是個一次性的斷點。

因為新斷點是針對這個編譯檔案的,如果原始檔改動後,會重新編譯出新的檔案,那麼這個斷點將會失效,後續將不會被匹配到。

方法 2:直接在「原始檔」中打新斷點。

此方法的弊端是:需要手動觸發編譯。

前面也提到過,在原始檔中新增新斷點之後,執行中的編譯檔案是無法感知到的,所以必須讓原始檔觸發重新編譯,生成新的編譯檔案,這樣原始檔的所有斷點就會同步對映到新的編譯檔案中了。

我每次觸發重新編譯的方式是,隨便在某個地方新增一行 console.log("") ,然後每次直接修改列印的內容即可。

2. 斷點位置不一致

原始檔和編譯後的檔案斷點的行號一致,但是對應的行號卻是不同的程式碼,和我們預期的斷點位置不一致:

對比之後可以看出,@vue/compiler-sfc 自動將