透過任務(Tasks)與外部工具整合

存在許多工具可用於自動化諸如程式碼檢查(linting)、建置、封裝、測試或部署軟體系統等任務。範例包括 TypeScript 編譯器、像 ESLintTSLint 這樣的檢查工具,以及諸如 MakeAntGulpJakeRakeMSBuild 等建置系統。

VS Code can talk to a variety of external tools

這些工具大多是從命令列執行,並自動化軟體開發迴圈(編輯、編譯、測試和偵錯)內部與外部的工作。鑑於它們在開發生命週期中的重要性,能夠在 VS Code 內執行工具並分析其結果會非常有幫助。VS Code 中的任務可以設定為執行指令碼並啟動程序,因此許多現有的工具無需進入命令列或編寫新程式碼即可在 VS Code 內使用。工作區或資料夾特定的任務是在工作區的 .vscode 資料夾內的 tasks.json 檔案中進行設定的。

延伸模組也可以使用 任務提供者(Task Provider) 提供任務,而這些貢獻的任務可以增加定義在 tasks.json 檔案中的工作區特定設定。

注意: 任務支援僅在操作工作區資料夾時可用。編輯單一檔案時不可用。

TypeScript Hello World

讓我們從一個簡單的 "Hello World" TypeScript 程式開始,我們想將其編譯為 JavaScript。

建立一個空資料夾 "mytask",產生一個 tsconfig.json 檔案,並從該資料夾啟動 VS Code。

mkdir mytask
cd mytask
tsc --init
code .

現在建立一個 HelloWorld.ts 檔案,內容如下

function sayHello(name: string): void {
  console.log(`Hello ${name}!`);
}

sayHello('Dave');

按下 ⇧⌘B (Windows, Linux Ctrl+Shift+B) 或從全域 終端機 選單執行 執行建置任務(Run Build Task),會顯示下列選擇器

TypeScript Build Task

第一個項目執行 TypeScript 編譯器並將 TypeScript 檔案轉譯為 JavaScript 檔案。當編譯器完成後,應該會有一個 HelloWorld.js 檔案。第二個項目以監控模式啟動 TypeScript 編譯器。每次儲存 HelloWorld.ts 檔案時,都會重新產生 HelloWorld.js 檔案。

您也可以將 TypeScript 建置或監控任務定義為預設建置任務,以便在觸發 執行建置任務(Run Build Task) (⇧⌘B (Windows, Linux Ctrl+Shift+B)) 時直接執行它。為此,請從全域 終端機 選單中選擇 設定預設建置任務(Configure Default Build Task)。這會向您顯示一個包含可用建置任務的選擇器。選擇 tsc: buildtsc: watch,VS Code 將會產生一個 tasks.json 檔案。下面顯示的檔案將 tsc: build 任務設為預設建置任務。

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "type": "typescript",
      "tsconfig": "tsconfig.json",
      "problemMatcher": ["$tsc"],
      "group": {
        "kind": "build",
        "isDefault": true
      }
    }
  ]
}

上述的 tasks.json 範例並未定義新任務。它將 VS Code 的 TypeScript 延伸模組所貢獻的 tsc: build 任務標註為預設建置任務。您現在可以透過按下 ⇧⌘B (Windows, Linux Ctrl+Shift+B) 來執行 TypeScript 編譯器。

任務自動偵測

VS Code 目前會針對下列系統自動偵測任務:Gulp、Grunt、Jake 和 npm。我們正與對應的延伸模組作者合作,以增加對 Maven 和 C# dotnet 命令的支援。如果您使用 Node.js 作為執行階段來開發 JavaScript 應用程式,通常會有一個 package.json 檔案來描述您的相依性與要執行的指令碼。如果您已複製 eslint-starter 範例,那麼從全域選單執行 執行任務(Run Tasks) 會顯示下列清單

Tasks ESLint starter

如果尚未執行,請透過執行 npm install 來安裝必要的 npm 模組。現在開啟 server.js 檔案,在語句末尾增加一個分號(注意 ESLint starter 假設語句末尾沒有分號),並再次執行 執行任務(Run Tasks)。這次選擇 npm: lint 任務。當提示使用哪個問題比對器時,選擇 ESLint stylish

Tasks ESLint Problem Matcher Selection

執行該任務會產生一個錯誤,顯示在 問題(Problems) 檢視中

Tasks ESLint Problem

此外,VS Code 建立了一個包含下列內容的 tasks.json 檔案

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "type": "npm",
      "script": "lint",
      "problemMatcher": ["$eslint-stylish"]
    }
  ]
}

這指示 VS Code 使用 ESLint stylish 格式掃描 npm lint 指令碼的輸出以找出問題。

對於 Gulp、Grunt 和 Jake,任務自動偵測的運作方式相同。以下是為 vscode-node-debug 延伸模組偵測到的任務範例。

Gulp task auto-detection

提示: 您可以透過輸入 'task'、Space 和命令名稱,經由 快速開啟(Quick Open) (⌘P (Windows, Linux Ctrl+P)) 來執行您的任務。在此例中為 'task lint'。

任務自動偵測可以使用下列設定停用

{
  "js/ts.tsc.autoDetect": "off",
  "grunt.autoDetect": "off",
  "jake.autoDetect": "off",
  "gulp.autoDetect": "off",
  "npm.autoDetect": "off"
}

自訂任務

並非所有任務或指令碼都能在您的工作區中自動偵測到。有時需要定義您自己的自訂任務。假設您有一個用於執行測試以正確設定某些環境的指令碼。該指令碼儲存在您工作區內的指令碼資料夾中,在 Linux 和 macOS 上命名為 test.sh,在 Windows 上命名為 test.cmd。從全域 終端機 選單執行 設定任務(Configure Tasks),並選擇 從範本建立 tasks.json 檔案(Create tasks.json file from template) 項目。這會開啟下列選擇器

Configure Task Runner

注意: 如果您沒有看到任務執行器範本清單,可能是您的資料夾中已經有一個 tasks.json 檔案,其內容會被開啟在編輯器中。關閉該檔案並刪除或重新命名它以進行此範例。

我們正致力於支援更多自動偵測,因此此清單未來會越來越少。由於我們想編寫自己的自訂任務,請從清單中選擇 Others。這會開啟一個帶有任務架構的 tasks.json 檔案。將內容替換為以下內容

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Run tests",
      "type": "shell",
      "command": "./scripts/test.sh",
      "windows": {
        "command": ".\\scripts\\test.cmd"
      },
      "group": "test",
      "presentation": {
        "reveal": "always",
        "panel": "new"
      }
    }
  ]
}

任務的屬性具有下列語意

  • label: 使用者介面中使用的任務標籤。
  • type: 任務類型。對於自訂任務,這可以是 shellprocess。如果指定 shell,命令會被解釋為 shell 命令(例如:bash、cmd 或 PowerShell)。如果指定 process,命令會被解釋為要執行的程序。
  • command: 實際要執行的命令。
  • windows: 任何 Windows 特定的屬性。當命令在 Windows 作業系統上執行時,將會取代預設屬性。
  • group: 定義任務所屬的群組。在此範例中,它屬於 test 群組。屬於測試群組的任務可以透過從 命令面板(Command Palette) 執行 執行測試任務(Run Test Task) 來執行。
  • presentation: 定義如何處理使用者介面中的任務輸出。在此範例中,顯示輸出的整合終端機設為 always 顯示,且每次任務執行時都會建立一個 new 終端機。
  • options: 覆寫 cwd(目前工作目錄)、env(環境變數)或 shell(預設 shell)的預設值。選項可以針對個別任務設定,也可以全域或針對每個平台設定。在此處設定的環境變數只能從您的任務指令碼或程序內參照,如果它們是 args、command 或其他任務屬性的一部分,則不會被解析。
  • runOptions: 定義任務執行的时间與方式。
  • hide: 從「執行任務(Run Task)」快速選擇中隱藏任務,這對於無法獨立執行的複合任務元素非常有用。

您可以在 tasks.json 檔案中使用 IntelliSense 查看完整的任務屬性和值集。使用 觸發建議(Trigger Suggest) (⌃Space (Windows, Linux Ctrl+Space)) 彈出建議,並透過滑鼠懸停或 Read More... ('i') 彈出視窗閱讀說明。

tasks.json IntelliSense

您也可以查閱 tasks.json 結構描述(schema)

當命令和引數包含空格或其他特殊字元(如 $)時,Shell 命令需要特殊處理。預設情況下,任務系統支援下列行為

  • 如果只提供單一命令,任務系統會將命令原封不動地傳遞給底層 shell。如果命令需要引號或跳脫才能正常運作,則命令需要包含正確的引號或跳脫字元。例如,若要列出名稱中包含空格的資料夾目錄,在 bash 中執行的命令應該看起來像這樣:ls 'folder with spaces'
{
  "label": "dir",
  "type": "shell",
  "command": "dir 'folder with spaces'"
}
  • 如果提供了命令和引數,如果命令或引數包含空格,任務系統將會使用單引號。對於 cmd.exe,會使用雙引號。像下面這樣的 shell 命令將會在 PowerShell 中執行為 dir 'folder with spaces'
{
  "label": "dir",
  "type": "shell",
  "command": "dir",
  "args": ["folder with spaces"]
}
  • 如果您想控制引數如何被引用,引數可以是一個指定值與引用樣式的常值。以下範例針對帶有空格的引數使用跳脫而非引用。
{
  "label": "dir",
  "type": "shell",
  "command": "dir",
  "args": [
    {
      "value": "folder with spaces",
      "quoting": "escape"
    }
  ]
}

除了跳脫之外,還支援下列值

  • strong: 使用 shell 的強制引用機制,這會抑制字串內的所有評估。在 PowerShell 和 Linux 與 macOS 的 shell 下,會使用單引號 (')。對於 cmd.exe,會使用 "
  • weak: 使用 shell 的弱引用機制,這仍會評估字串內的運算式(例如,環境變數)。在 PowerShell 和 Linux 與 macOS 的 shell 下,會使用雙引號 (")。cmd.exe 不支援弱引用,所以 VS Code 也會使用 "

如果命令本身包含空格,VS Code 預設也會強制引用該命令。如同引數,使用者可以使用相同的常值樣式控制命令的引用。

還有更多的任務屬性可以設定您的工作流程。您可以使用 ⌃Space (Windows, Linux Ctrl+Space) 配合 IntelliSense 來概覽有效的屬性。

Tasks IntelliSense

除了全域選單列之外,還可以使用 命令面板(Command Palette) (⇧⌘P (Windows, Linux Ctrl+Shift+P)) 存取任務命令。您可以篩選 'task' 來查看各種與任務相關的命令。

Tasks in Command Palette

複合任務(Compound tasks)

您也可以使用 dependsOn 屬性將較簡單的任務組成複合任務。例如,如果您有一個包含 client 和 server 資料夾的工作區,且兩者都包含建置指令碼,您可以建立一個在不同終端機中啟動這兩個建置指令碼的任務。如果您在 dependsOn 屬性中列出多個任務,它們預設會並行執行。

tasks.json 檔案看起來像這樣

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Client Build",
      "command": "gulp",
      "args": ["build"],
      "options": {
        "cwd": "${workspaceFolder}/client"
      }
    },
    {
      "label": "Server Build",
      "command": "gulp",
      "args": ["build"],
      "options": {
        "cwd": "${workspaceFolder}/server"
      }
    },
    {
      "label": "Build",
      "dependsOn": ["Client Build", "Server Build"]
    }
  ]
}

如果您指定 "dependsOrder": "sequence",那麼您的任務相依項目將會依照在 dependsOn 中列出的順序執行。任何在 dependsOn 中使用 "dependsOrder": "sequence" 的背景/監控任務,必須具有一個能追蹤它們何時「完成」的問題比對器。以下任務會執行任務 Two、任務 Three,然後執行任務 One。

{
  "label": "One",
  "type": "shell",
  "command": "echo Hello ",
  "dependsOrder": "sequence",
  "dependsOn": ["Two", "Three"]
}

使用者層級任務

您可以使用 任務:開啟使用者任務(Tasks: Open User Tasks) 命令建立不綁定於特定工作區或資料夾的使用者層級任務。在此處只能使用 shellprocess 任務,因為其他任務類型需要工作區資訊。

輸出行為

有時您會想要控制執行任務時整合終端機面板的行為。例如,您可能想要最大化編輯器空間,並且只有在認為有問題時才查看任務輸出。終端機的行為可以使用任務的 presentation 屬性來控制。它提供下列屬性

  • reveal: 控制整合終端機面板是否被帶到前景。有效值為
    • always - 面板總是會被帶到前景。這是預設值。
    • never - 使用者必須使用 檢視 > 終端機 命令 (⌃` (Windows, Linux Ctrl+`)) 明確將終端機面板帶到前景。
    • silent - 只有在未掃描輸出以尋找錯誤和警告時,終端機面板才被帶到前景。
  • revealProblems: 控制執行此任務時是否顯示「問題」面板。優先於 reveal 選項。預設為 never
    • always - 執行此任務時,總是顯示「問題」面板。
    • onProblem - 僅在發現問題時才顯示「問題」面板。
    • never - 執行此任務時,絕不顯示「問題」面板。
  • focus: 控制終端機是否取得輸入焦點。預設為 false
  • echo: 控制執行的命令是否在終端機中回顯。預設為 true
  • showReuseMessage: 控制是否顯示「Terminal will be reused by tasks, press any key to close it」訊息。
  • panel: 控制終端機實例是否在任務執行之間共用。可能的值為
    • shared - 終端機被共用,其他任務執行的輸出會新增到同一個終端機中。
    • dedicated - 終端機專用於特定任務。如果再次執行該任務,終端機會被重複使用。然而,不同任務的輸出會呈現在不同的終端機中。
    • new - 該任務的每次執行都會使用一個新的乾淨終端機。
  • clear: 控制在此任務執行前是否清除終端機。預設為 false
  • close: 控制任務結束時,任務執行的終端機是否關閉。預設為 false
  • group: 控制任務是否使用分割面板在特定終端機群組中執行。同一群組中的任務(由字串值指定)將使用分割終端機呈現,而不是新的終端機面板。

您也可以修改自動偵測任務的終端機面板行為。例如,如果您想從上面的 ESLint 範例更改 npm: run lint 的輸出行為,請為其增加 presentation 屬性

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "type": "npm",
      "script": "lint",
      "problemMatcher": ["$eslint-stylish"],
      "presentation": {
        "reveal": "never"
      }
    }
  ]
}

您也可以將自訂任務與偵測到的任務設定混合使用。一個設定 npm: run lint 任務並新增自訂 Run Test 任務的 tasks.json 看起來像這樣

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "type": "npm",
      "script": "lint",
      "problemMatcher": ["$eslint-stylish"],
      "presentation": {
        "reveal": "never"
      }
    },
    {
      "label": "Run tests",
      "type": "shell",
      "command": "./scripts/test.sh",
      "windows": {
        "command": ".\\scripts\\test.cmd"
      },
      "group": "test",
      "presentation": {
        "reveal": "always",
        "panel": "new"
      }
    }
  ]
}

執行行為

您可以使用 runOptions 屬性指定任務的執行行為

  • reevaluateOnRerun: 控制透過 重新執行上一個任務(Rerun Last Task) 命令執行任務時,變數如何評估。預設為 true,表示重新執行任務時將重新評估變數。當設為 false 時,將使用任務上一次執行的解析變數值。

  • runOn: 指定任務執行的時間點。

    • default - 任務僅在透過 執行任務(Run Task) 命令執行時才會運作。
    • folderOpen: 開啟包含該任務的資料夾時會執行該任務。另請參閱如何 控制自動任務執行
  • instanceLimit: 允許同時執行的任務實例數量。預設值為 1

  • instancePolicy: 決定當任務達到其 instanceLimit 時會發生什麼。可以設定為

    • prompt - 提示使用者終止哪個實例(預設)。
    • silent - 不啟動新實例(靜默)。
    • terminateNewest - 終止最新執行的實例。
    • terminateOldest - 終止最舊執行的實例。
    • warn - 不啟動新實例(顯示警告)。

控制自動任務執行

task.allowAutomaticTasks 在 VS Code 中開啟 在 VS Code Insiders 中開啟 設定可控制在您開啟工作區時,是否允許帶有 "runOn": "folderOpen" 的任務自動執行。無論此設定為何,自動任務絕不會在 未受信任的工作區 中執行。

此設定接受兩個值

  • off (預設): 不執行自動任務。如果您尚未針對目前工作區做出選擇,系統會提示您一次 允許 (Allow)不允許 (Disallow) 自動任務。如果您選擇 不允許(或明確將值設為 off),任務將不會執行且不會再提示您。
  • on: 開啟受信任的工作區時,總是自動執行自動任務,不會提示。

要設定此項目,請將其加入您的使用者或工作區設定中

{
  "task.allowAutomaticTasks": "off"
}

您也可以隨時使用命令面板中的 任務:管理自動任務(Tasks: Manage Automatic Tasks) 命令,並在 允許自動任務不允許自動任務 之間進行選擇,以更改您對目前工作區的選擇。

自訂自動偵測到的任務

如前所述,您可以在 tasks.json 檔案中自訂自動偵測到的任務。您通常這樣做是為了修改呈現屬性,或附加問題比對器以掃描任務輸出的錯誤和警告。您可以透過按右側的齒輪圖示,將對應的任務參考插入 tasks.json 檔案中,從 執行任務(Run Task) 清單直接自訂任務。假設您有下列 Gulp 檔案用於使用 ESLint 檢查 JavaScript 檔案(該檔案摘自 https://github.com/adametry/gulp-eslint

const gulp = require('gulp');
const eslint = require('gulp-eslint');

gulp.task('lint', () => {
  // ESLint ignores files with "node_modules" paths.
  // So, it's best to have gulp ignore the directory as well.
  // Also, Be sure to return the stream from the task;
  // Otherwise, the task may end before the stream has finished.
  return (
    gulp
      .src(['**/*.js', '!node_modules/**'])
      // eslint() attaches the lint output to the "eslint" property
      // of the file object so it can be used by other modules.
      .pipe(eslint())
      // eslint.format() outputs the lint results to the console.
      // Alternatively use eslint.formatEach() (see Docs).
      .pipe(eslint.format())
      // To have the process exit with an error code (1) on
      // lint error, return the stream and pipe to failAfterError last.
      .pipe(eslint.failAfterError())
  );
});

gulp.task('default', ['lint'], function() {
  // This will only run if the lint task is successful...
});

從全域 終端機 選單執行 執行任務(Run Task) 會顯示下列選擇器

Configure Task

按下齒輪圖示。這將會建立下列 tasks.json 檔案

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "type": "gulp",
      "task": "default",
      "problemMatcher": []
    }
  ]
}

通常您現在會新增問題比對器(在此例中為 $eslint-stylish)或修改呈現設定。

使用問題比對器處理任務輸出

VS Code 可以使用問題比對器處理任務的輸出。問題比對器會掃描任務輸出的文字以尋找已知的警告或錯誤字串,並在編輯器內及「問題」面板中回報。VS Code 內建了多種問題比對器

  • TypeScript: $tsc 假設輸出中的檔案名稱相對於開啟的資料夾。
  • TypeScript Watch: $tsc-watch 符合在監控模式執行時,由 tsc 編譯器回報的問題。
  • JSHint: $jshint 假設檔案名稱以絕對路徑回報。
  • JSHint Stylish: $jshint-stylish 假設檔案名稱以絕對路徑回報。
  • ESLint Compact: $eslint-compact 假設輸出中的檔案名稱相對於開啟的資料夾。
  • ESLint Stylish: $eslint-stylish 假設輸出中的檔案名稱相對於開啟的資料夾。
  • Go: $go 符合由 go 編譯器回報的問題。假設檔案名稱相對於開啟的資料夾。
  • CSharp and VB Compiler: $mscompile 假設檔案名稱以絕對路徑回報。
  • Lessc compiler: $lessc 假設檔案名稱以絕對路徑回報。
  • Node Sass compiler: $node-sass 假設檔案名稱以絕對路徑回報。

您也可以建立自己的問題比對器,我們將在 後續章節 中討論。

將鍵盤快速鍵綁定至任務

如果您需要頻繁執行某個任務,可以為該任務定義鍵盤快速鍵。

例如,若要將 Ctrl+H 綁定到上述的 執行測試(Run tests) 任務,請將下列內容新增至您的 keybindings.json 檔案

{
  "key": "ctrl+h",
  "command": "workbench.action.tasks.runTask",
  "args": "Run tests"
}

變數替換

在撰寫任務設定時,擁有預定義的常見變數(例如作用中檔案 ${file} 或工作區根資料夾 ${workspaceFolder})非常有用。VS Code 支援 tasks.json 檔案中字串內的變數替換,您可以在 變數參考 中查看預定義變數的完整清單。

注意: 並非所有屬性都接受變數替換。具體來說,只有 commandargsoptions 支援變數替換。

以下是一個將目前開啟的檔案傳遞給 TypeScript 編譯器的自訂任務設定範例。

{
  "label": "TypeScript compile",
  "type": "shell",
  "command": "tsc ${file}",
  "problemMatcher": ["$tsc"]
}

同樣地,您也可以透過在名稱前加上 ${config: 來參照專案的設定。例如,${config:python.formatting.autopep8Path} 會傳回 Python 延伸模組設定 formatting.autopep8Path

以下是一個自訂任務設定的範例,它使用由 python.formatting.autopep8Path 設定定義的 autopep8 可執行檔,在目前檔案上執行 autopep8

{
  "label": "autopep8 current file",
  "type": "process",
  "command": "${config:python.formatting.autopep8Path}",
  "args": ["--in-place", "${file}"]
}

如果您想為 tasks.jsonlaunch.json 指定 Python 延伸模組所使用的已選 Python 直譯器,可以使用 ${command:python.interpreterPath} 命令。

如果簡單的變數替換不足夠,您也可以透過在 tasks.json 檔案中增加 inputs 區段來取得任務使用者的輸入。

Inputs Example

有關 inputs 的更多資訊,請參閱 變數參考

作業系統特定屬性

任務系統支援定義特定於作業系統的值(例如要執行的命令)。為此,請在 tasks.json 檔案中放入作業系統特定的常值,並在該常值內指定對應的屬性。

以下是一個使用 Node.js 可執行檔作為命令,且在 Windows 和 Linux 上處理方式不同的範例

{
  "label": "Run Node",
  "type": "process",
  "windows": {
    "command": "C:\\Program Files\\nodejs\\node.exe"
  },
  "linux": {
    "command": "/usr/bin/node"
  }
}

有效的作業系統屬性為用於 Windows 的 windows、用於 Linux 的 linux 以及用於 macOS 的 osx。在作業系統特定範圍中定義的屬性,會覆寫在任務或全域範圍中定義的屬性。

全域任務

任務屬性也可以定義在全域範圍中。如果存在,除非特定任務定義了具有不同值的相同屬性,否則將會使用這些全域屬性。在下面的範例中,有一個全域 presentation 屬性,它定義了所有任務都應在新面板中執行

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "presentation": {
    "panel": "new"
  },
  "tasks": [
    {
      "label": "TS - Compile current file",
      "type": "shell",
      "command": "tsc ${file}",
      "problemMatcher": ["$tsc"]
    }
  ]
}

提示: 若要存取全域範圍的 tasks.json 檔案,請開啟命令面板 (⇧⌘P (Windows, Linux Ctrl+Shift+P)) 並執行 任務:開啟使用者任務(Tasks: Open User Tasks) 命令。

PowerShell 中的字元跳脫

當預設 shell 為 PowerShell,或當任務設定為使用 PowerShell 時,您可能會看到非預期的空格和引號跳脫。非預期的跳脫僅發生在 cmdlet 上,因為 VS Code 不知道您的命令是否包含 cmdlet。下面的範例 1 顯示了您會遇到無法在 PowerShell 中運作的跳脫的情況。範例 2 顯示了取得良好跳脫的最佳跨平台方式。在某些情況下,您可能無法遵循範例 2,且需要執行範例 3 中顯示的手動跳脫。

"tasks": [
    {
        "label": "PowerShell example 1 (unexpected escaping)",
        "type": "shell",
        "command": "Get-ChildItem \"Folder With Spaces\""
    },
    {
        "label": "PowerShell example 2 (expected escaping)",
        "type": "shell",
        "command": "Get-ChildItem",
        "args": ["Folder With Spaces"]
    },
    {
        "label": "PowerShell example 3 (manual escaping)",
        "type": "shell",
        "command": "& Get-ChildItem \\\"Folder With Spaces\\\""
    }
]

更改任務輸出的編碼

任務經常操作磁碟上的檔案。如果這些檔案儲存在磁碟上的編碼與系統編碼不同,您需要讓作為任務執行的命令知道要使用哪種編碼。由於這取決於作業系統和所使用的 shell,因此沒有控制此問題的通用解決方案。以下是有關如何使其運作的建議與範例。

如果您需要調整編碼,您應該檢查更改作業系統使用的預設編碼是否有意義,或者至少透過調整 shell 的設定檔來為您使用的 shell 進行更改。

如果您只需要針對特定任務進行調整,請將更改編碼所需的作業系統特定命令新增至任務命令列。以下範例適用於使用代碼頁 437 作為預設值的 Windows。該任務顯示一個包含西里爾字母的檔案輸出,因此需要代碼頁 866。假設預設 shell 設為 cmd.exe,用於列出檔案的任務看起來像這樣

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "more",
      "type": "shell",
      "command": "chcp 866 && more russian.txt",
      "problemMatcher": []
    }
  ]
}

如果任務是在 PowerShell 中執行,該命令讀起來需要像這樣:chcp 866; more russian.txt。在 Linux 和 macOS 上,locale 命令可用於檢查地區設定並調整必要的環境變數。

任務運作範例

為了強調任務的強大功能,以下是 VS Code 如何使用任務來整合諸如檢查工具和編譯器等外部工具的幾個範例。

將 TypeScript 轉譯為 JavaScript

TypeScript 主題 包含一個範例,該範例建立了一個將 TypeScript 轉譯為 JavaScript 的任務,並在 VS Code 內觀察任何相關錯誤。

將 Less 和 SCSS 轉譯為 CSS

CSS 主題提供了如何使用任務產生 CSS 檔案的範例。

  1. 使用建置任務手動轉譯
  2. 使用檔案監控器自動化編譯步驟

定義問題比對器

VS Code 內建了一些最常見的問題比對器。然而,市面上有許多編譯器和檢查工具,它們都會產生自己風格的錯誤和警告,因此您可能希望建立自己的問題比對器。

我們有一個 helloWorld.c 程式,開發人員將 printf 誤拼寫為 prinft。使用 gcc 編譯它會產生下列警告

helloWorld.c:5:3: warning: implicit declaration of function ‘prinft’

我們想要產生一個可以捕捉輸出中訊息並在 VS Code 中顯示對應問題的問題比對器。問題比對器極度依賴 正規表示式。以下章節假設您熟悉正規表示式。

提示: 我們發現 RegEx101 練習場(具有 ECMAScript/JavaScript 風格)是開發和測試正規表示式的絕佳方式。

捕捉上述警告(和錯誤)的比對器看起來像這樣

{
  // The problem is owned by the cpp language service.
  "owner": "cpp",
  // The file name for reported problems is relative to the opened folder.
  "fileLocation": ["relative", "${workspaceFolder}"],
  // The name that will be shown as the source of the problem.
  "source": "gcc",
  // The actual pattern to match problems in the output.
  "pattern": {
    // The regular expression. Example to match: helloWorld.c:5:3: warning: implicit declaration of function ‘printf’ [-Wimplicit-function-declaration]
    "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
    // The first match group matches the file name which is relative.
    "file": 1,
    // The second match group matches the line on which the problem occurred.
    "line": 2,
    // The third match group matches the column at which the problem occurred.
    "column": 3,
    // The fourth match group matches the problem's severity. Can be ignored. Then all problems are captured as errors.
    "severity": 4,
    // The fifth match group matches the message.
    "message": 5
  }
}

請注意,file、line 和 message 屬性是強制性的。fileLocation 指定任務輸出產生且在問題中比對到的檔案路徑是 absolute(絕對)還是 relative(相對)。如果任務同時產生絕對路徑和相對路徑,您可以使用 autoDetect 檔案位置。使用 autoDetect,路徑會先被測試為絕對路徑,如果檔案不存在,則假設路徑為相對路徑。

severity 指定如果模式不包含嚴重性時要使用的問題嚴重性。severity 的可能值為 errorwarninginfo

這是一個完成的 tasks.json 檔案,包含上述程式碼(註解已移除)並包裝了實際的任務詳細資訊

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "build",
      "command": "gcc",
      "args": ["-Wall", "helloWorld.c", "-o", "helloWorld"],
      "problemMatcher": {
        "owner": "cpp",
        "fileLocation": ["relative", "${workspaceFolder}"],
        "source": "gcc",
        "pattern": {
          "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
          "file": 1,
          "line": 2,
          "column": 3,
          "severity": 4,
          "message": 5
        }
      }
    }
  ]
}

在 VS Code 內執行它並按下 ⇧⌘M (Windows, Linux Ctrl+Shift+M) 以取得問題清單,會得到下列輸出

GCC Problem Matcher

注意: C/C++ 延伸模組 包含了 GCC 的問題比對器,因此無需定義我們自己的。

模式中還有幾個可以使用的屬性。這些是

  • location - 如果問題位置是 line 或 line,column 或 startLine,startColumn,endLine,endColumn,則可以使用我們的通用位置比對群組。
  • endLine - 問題結束行的比對群組索引。如果編譯器未提供結束行值,則可以省略。
  • endColumn - 問題結束欄的比對群組索引。如果編譯器未提供結束欄值,則可以省略。
  • code - 問題代碼的比對群組索引。如果編譯器未提供代碼值,則可以省略。

您也可以定義一個僅捕捉檔案的問題比對器。為此,定義一個 pattern,並將選用的 kind 屬性設為 file。在此情況下,無需提供 linelocation 屬性。

注意: 如果 kind 屬性設為 file,功能性模式至少必須提供 filemessage 的比對群組。如果未提供 kind 屬性或 kind 屬性設為 location,則功能模式也必須提供 linelocation 屬性。

注意: 問題比對器僅剖析給定命令的輸出。如果您想剖析寫入到單獨檔案(例如記錄檔)的輸出,請讓您執行的命令在執行完成前,將單獨檔案中的行印出。

定義多行問題比對器

有些工具會將在原始檔案中發現的問題分散到多行,特別是在使用 stylish 報表工具時。例如 ESLint;在 stylish 模式下,它產生的輸出如下

test.js
  1:0   error  Missing "use strict" statement                 strict
 1 problems (1 errors, 0 warnings)

我們的問題比對器是基於行的,因此我們需要使用與實際問題位置和訊息(1:0 error Missing "use strict" statement)不同的正規表示式來捕捉檔案名稱(test.js)。

為此,請對 pattern 屬性使用問題模式陣列。透過這種方式,您可以為每一行想要比對的內容定義一個模式。

注意: 在多行問題比對器中,模式陣列必須從第一個模式開始,比對輸出的每一連續行。即使中間行不包含有用的資訊,您也不能跳過它們。

如果您的工具輸出三行,而您只需要第一行和第三行的資料,您的模式陣列仍需要三個項目。對於您不需要資料的行,請使用 {"regexp": "^.*$"} 且不指派任何捕捉群組。

"pattern": [
    { "regexp": "^Error:\\s+(.*)$", "message": 1 },
    { "regexp": "^.*$" },
    { "regexp": "^\\s+at\\s+(.*):(\\d+)$", "file": 1, "line": 2 }
]

下列問題模式比對了 stylish 模式下 ESLint 的輸出 - 但仍有一個我們接下來需要解決的小問題。下方的程式碼具有第一個用於捕捉檔案名稱的正規表示式,第二個用於捕捉行、欄、嚴重性、訊息和錯誤代碼

{
  "owner": "javascript",
  "fileLocation": ["relative", "${workspaceFolder}"],
  "pattern": [
    {
      "regexp": "^([^\\s].*)$",
      "file": 1
    },
    {
      "regexp": "^\\s+(\\d+):(\\d+)\\s+(error|warning|info)\\s+(.*)\\s\\s+(.*)$",
      "line": 1,
      "column": 2,
      "severity": 3,
      "message": 4,
      "code": 5
    }
  ]
}

然而,如果資源上有一個以上的問題,此模式將無法運作。例如,想像 ESLint 的下列輸出

test.js
  1:0   error  Missing "use strict" statement                 strict
  1:9   error  foo is defined but never used                  no-unused-vars
  2:5   error  x is defined but never used                    no-unused-vars
  2:11  error  Missing semicolon                              semi
  3:1   error  "bar" is not defined                           no-undef
  4:1   error  Newline required at end of file but not found  eol-last
 6 problems (6 errors, 0 warnings)

模式的第一個正規表示式將比對 "test.js",第二個比對 "1:0 error ..."。下一行 "1:9 error ..." 會被處理但不會被第一個正規表示式比對,因此沒有捕捉到問題。

為了使其運作,多行模式的最後一個正規表示式可以指定 loop 屬性。若設為 true,它會指示任務系統只要正規表示式比對成功,就將多行比對器的最後一個模式套用到輸出中的行。

第一個模式捕捉到的資訊(在此例中比對 test.js)將與每個比對 loop 模式的後續行結合,以建立多個問題。在此範例中,將會建立六個問題。

這是一個完全捕捉 ESLint stylish 問題的問題比對器

{
  "owner": "javascript",
  "fileLocation": ["relative", "${workspaceFolder}"],
  "pattern": [
    {
      "regexp": "^([^\\s].*)$",
      "file": 1
    },
    {
      "regexp": "^\\s+(\\d+):(\\d+)\\s+(error|warning|info)\\s+(.*)\\s\\s+(.*)$",
      "line": 1,
      "column": 2,
      "severity": 3,
      "message": 4,
      "code": 5,
      "loop": true
    }
  ]
}

注意:如果您有多個問題發生在同一個資源上且具有完全相同的行和欄,則只會顯示一個問題。這適用於所有問題比對器,而不僅僅是多行問題比對器。

修改現有的問題比對器

如果現有的問題比對器接近您的需求,您可以在您的 tasks.json 任務中修改它。例如,$tsc-watch 問題比對器僅適用於已關閉的文件。如果您想要它適用於所有文件,可以修改它

{
  "type": "npm",
  "script": "watch",
  "problemMatcher": {
    "base": "$tsc-watch",
    "applyTo": "allDocuments"
  },
  "isBackground": true
}

其他可修改的問題比對器屬性包括 backgroundfileLocationownerpatternseveritysource

背景 / 監控任務

有些工具支援在背景執行,同時監控檔案系統是否有變更,並在磁碟上的檔案變更時觸發動作。透過 Gulp,此類功能由 npm 模組 gulp-watch 提供。TypeScript 編譯器 tsc 透過 --watch 命令列選項內建了對此的支援。

為了提供背景任務在 VS Code 中活躍並產生問題結果的回饋,問題比對器必須使用額外資訊來偵測輸出中的這些 state(狀態)變更。讓我們以 tsc 編譯器為例。當編譯器以監控模式啟動時,它會將下列額外資訊印到主控台

> tsc --watch
12:30:36 PM - Compilation complete. Watching for file changes.

當磁碟上包含問題的檔案變更時,會出現下列輸出

12:32:35 PM - File change detected. Starting incremental compilation...
src/messages.ts(276,9): error TS2304: Cannot find name 'candidate'.
12:32:35 PM - Compilation complete. Watching for file changes.

查看輸出顯示了下列模式

  • 當主控台印出 File change detected. Starting incremental compilation... 時,編譯器執行。
  • 當主控台印出 Compilation complete. Watching for file changes. 時,編譯器停止。
  • 在這兩個字串之間,會回報問題。
  • 編譯器在初始啟動後也會執行一次(不會向主控台列印 File change detected. Starting incremental compilation...)。

為了捕捉此資訊,問題比對器可以提供 background 屬性。

對於 tsc 編譯器,適當的 background 屬性看起來像這樣

"background": {
    "activeOnStart": true,
    "beginsPattern": "^\\s*\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM)? - File change detected\\. Starting incremental compilation\\.\\.\\.",
    "endsPattern": "^\\s*\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM)? - Compilation complete\\. Watching for file changes\\."
}

除了問題比對器上的 background 屬性外,任務本身必須標記為 isBackground,以便任務在背景持續執行。

一個以監控模式執行 tsc 任務的完整手工 tasks.json 看起來像這樣

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "watch",
      "command": "tsc",
      "args": ["--watch"],
      "isBackground": true,
      "problemMatcher": {
        "owner": "typescript",
        "fileLocation": "relative",
        "pattern": {
          "regexp": "^([^\\s].*)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$",
          "file": 1,
          "location": 2,
          "severity": 3,
          "code": 4,
          "message": 5
        },
        "background": {
          "activeOnStart": true,
          "beginsPattern": "^\\s*\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM)? - File change detected\\. Starting incremental compilation\\.\\.\\.",
          "endsPattern": "^\\s*\\d{1,2}:\\d{1,2}:\\d{1,2}(?: AM| PM)? - Compilation complete\\. Watching for file changes\\."
        }
      }
    }
  ]
}

後續步驟

這就是任務 - 讓我們繼續...

  • tasks.json Schema - 您可以查閱完整的 tasks.json 結構描述和說明。
  • 基本編輯 - 了解功能強大的 VS Code 編輯器。
  • 程式碼導覽 - 在原始碼中快速移動。
  • 語言支援 - 了解我們支援的程式語言,包括內建於 VS Code 中的語言,以及透過社群延伸模組支援的語言。
  • 偵錯 - 直接在 VS Code 編輯器中對您的原始程式碼進行偵錯。

常見問題

任務可以使用與整合終端機指定不同的 shell 嗎?

可以。您可以使用 "terminal.integrated.automationProfile.*" 設定來設定將用於 VS Code 中所有自動化的 shell,這包括任務。

    "terminal.integrated.automationProfile.windows": {
        "path": "cmd.exe"
    }

或者,您可以使用 options.shell 屬性覆寫任務的 shell。您可以針對個別任務、全域或每個平台進行設定。例如,若要在 Windows 上使用 cmd.exe,您的 tasks.json 將會包含

{
    "version": "2.0.0",
    "windows": {
        "options": {
            "shell": {
                "executable": "cmd.exe",
                "args": [
                    "/d", "/c"
                ]
            }
        }
    },
    ...

背景任務可以用作 launch.json 中的 prelaunchTask 嗎?

可以。由於背景任務會一直執行直到被殺死,因此背景任務本身沒有「完成」的訊號。要將背景任務用作 prelaunchTask,您必須將適當的背景 problemMatcher 新增至背景任務,以便任務系統和偵錯系統能夠知道任務「完成」了。

您的任務可以是

{
  "type": "npm",
  "script": "watch",
  "problemMatcher": "$tsc-watch",
  "isBackground": true
}

注意: $tsc-watch 是一個 背景 問題比對器,這對背景任務是必要的。

然後,您可以在 launch.json 檔案中將此任務用作 prelaunchTask

{
  "name": "Launch Extension",
  "type": "extensionHost",
  "request": "launch",
  "runtimeExecutable": "${execPath}",
  "args": ["--extensionDevelopmentPath=${workspaceRoot}"],
  "stopOnEntry": false,
  "sourceMaps": true,
  "outFiles": ["${workspaceRoot}/out/src/**/*.js"],
  "preLaunchTask": "npm: watch"
}

有關背景任務的更多資訊,請前往 背景 / 監控任務

為什麼執行任務時會收到 "command not found"?

"command not found" 訊息發生在當您嘗試執行的任務命令未被您的終端機識別為可執行內容時。大多數情況下,這是因為該命令設定為您 shell 啟動指令碼的一部分。任務是以非登入(non-login)和非互動式(non-interactive)方式執行的,這意味著您的 shell 啟動指令碼不會被執行。特別是 nvm 已知會將啟動指令碼作為其設定的一部分。

有幾種方式可以解決此問題

  1. 確保您的命令位於路徑中(path),並且不需要啟動指令碼即可加入到您的路徑中。這是解決此問題最徹底的方式,也是推薦的解決方案。
  2. 您可以為您的任務進行一次性修正,使其以登入或互動式方式執行。這並不推薦,因為它可能會有其他後果。然而,對於單一任務,這可能是一個快速簡便的修正。以下是一個以 bash 作為 shell 執行此操作的任務範例
{
  "type": "npm",
  "script": "watch",
  "options": {
    "shell": {
      "args": ["-c", "-l"]
    }
  }
}

上面的 npm 任務會執行 bash 並帶有命令(-c),就像任務系統預設做的一樣。然而,此任務也將 bash 作為登入 shell(-l)執行。

© . This site is unofficial and not affiliated with Microsoft.