透過任務整合外部工具
存在許多用於自動化任務的工具,例如程式碼檢查、構建、打包、測試或部署軟體系統。例如,有 TypeScript 編譯器、ESLint 和 TSLint 等程式碼檢查器,以及 Make、Ant、Gulp、Jake、Rake 和 MSBuild 等構建系統。

這些工具大多從命令列執行,用於自動化軟體開發內部迴圈(編輯、編譯、測試和除錯)內外的任務。鑑於它們在開發生命週期中的重要性,能夠在 VS Code 內部執行工具並分析其結果非常有用。VS Code 中的任務可以配置為執行指令碼和啟動程序,從而無需輸入命令列或編寫新程式碼即可在 VS Code 內部使用許多現有工具。工作區或資料夾特定的任務是從工作區 .vscode 資料夾中的 tasks.json 檔案配置的。
擴充套件也可以使用 任務提供程式 來貢獻任務,這些貢獻的任務可以新增在 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) 或從全域性 **終端** 選單執行 **執行構建任務** 會顯示以下選擇器:

第一個條目執行 TypeScript 編譯器,並將 TypeScript 檔案轉換為 JavaScript 檔案。編譯器完成後,應生成 HelloWorld.js 檔案。第二個條目以監視模式啟動 TypeScript 編譯器。每次儲存 HelloWorld.ts 檔案都會重新生成 HelloWorld.js 檔案。
您還可以將 TypeScript 的構建或監視任務定義為預設構建任務,以便在觸發 **執行構建任務** (⇧⌘B (Windows、Linux Ctrl+Shift+B)) 時直接執行。為此,請從全域性 **終端** 選單中選擇 **配置預設構建任務**。這將顯示一個包含可用構建任務的選擇器。選擇 **tsc: build** 或 **tsc: 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 示例,那麼從全域性選單執行 **執行任務** 會顯示以下列表:

如果尚未進行,請透過執行 npm install 來安裝必要的 npm 模組。現在開啟 server.js 檔案並在語句末尾新增一個分號(請注意,ESLint starter 假設語句不帶分號),然後再次執行 **執行任務**。這次選擇 **npm: lint** 任務。在提示選擇要使用的問題匹配器時,選擇 **ESLint stylish**。

執行任務會產生一個錯誤,顯示在 **問題** 檢視中:

此外,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 擴充套件檢測到的任務示例:

提示: 您可以透過在 **快速開啟** (⌘P (Windows、Linux Ctrl+P)) 中鍵入 'task'、Space 和命令名稱來執行您的任務。在這種情況下,是 'task lint'。
可以使用以下設定停用任務自動檢測:
{
"typescript.tsc.autoDetect": "off",
"grunt.autoDetect": "off",
"jake.autoDetect": "off",
"gulp.autoDetect": "off",
"npm.autoDetect": "off"
}
自定義任務
並非所有任務或指令碼都能在您的工作區中自動檢測到。有時需要定義自己的自定義任務。假設您有一個執行測試的指令碼,以正確設定某些環境。該指令碼儲存在工作區內的指令碼資料夾中,名為 test.sh(用於 Linux 和 macOS)或 test.cmd(用於 Windows)。從全域性 **終端** 選單執行 **配置任務**,然後選擇 **從模板建立 tasks.json 檔案** 條目。這將開啟以下選擇器:

注意: 如果您沒有看到任務執行程式模板列表,則您可能已經在資料夾中擁有一個
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:任務的型別。對於自定義任務,它可以是
shell或process。如果指定了shell,則命令被解釋為 shell 命令(例如:bash、cmd 或 PowerShell)。如果指定了process,則命令被解釋為要執行的程序。 - command:要執行的實際命令。
- windows:任何 Windows 特定屬性。在 Windows 作業系統上執行命令時,將使用它們代替預設屬性。
- group:定義任務所屬的組。在示例中,它屬於
test組。可以透過從 **命令面板** 執行 **執行測試任務** 來執行屬於測試組的任務。 - presentation:定義任務輸出在使用者介面中的處理方式。在此示例中,顯示輸出的整合終端是
always顯現,並且每次執行任務時都會建立一個new終端。 - options:覆蓋
cwd(當前工作目錄)、env(環境變數)或shell(預設 shell)的預設值。可以為每個任務設定選項,也可以全域性或按平臺設定。此處配置的環境變數只能在您的任務指令碼或程序內部引用,如果它們是 args、command 或其他任務屬性的一部分,則不會解析。 - runOptions:定義任務何時以及如何執行。
- hide:從“執行任務”快速選擇器中隱藏任務,這對於組合任務中不可獨立執行的元素很有用。
您可以使用 IntelliSense 和 **觸發建議** (⌃Space (Windows、Linux Ctrl+Space)) 在 tasks.json 檔案中檢視所有任務屬性和值,並在懸停或透過 **Read More...** ('i') 浮出視窗時閱讀說明。

您還可以參考 tasks.json 模式。
當命令和引數包含空格或其他特殊字元(如 $)時,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 預設也會對命令進行強引用。與引數一樣,使用者可以使用相同的字面量樣式來控制命令的引用。
還有更多工屬性可用於配置您的工作流。您可以使用 IntelliSense 和 **觸發建議** (⌃Space (Windows、Linux Ctrl+Space)) 來概覽有效屬性。

除了全域性選單欄,還可以使用 **命令面板** (⇧⌘P (Windows、Linux Ctrl+Shift+P)) 訪問任務命令。您可以篩選 "task" 來檢視各種與任務相關的命令。

複合任務
您還可以透過 dependsOn 屬性將任務組合成更簡單的任務。例如,如果您有一個工作區,其中包含客戶端和伺服器資料夾,並且它們都包含構建指令碼,則可以建立一個任務來在單獨的終端中啟動這兩個構建指令碼。如果您在 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 中列出的順序執行。"dependsOrder": "sequence" 中使用的任何後臺/監視任務必須具有跟蹤它們何時“完成”的問題匹配器。以下任務按順序執行任務 Two、任務 Three,然後任務 One。
{
"label": "One",
"type": "shell",
"command": "echo Hello ",
"dependsOrder": "sequence",
"dependsOn": ["Two", "Three"]
}
使用者級任務
您可以使用 **Tasks: Open User Tasks** 命令建立不與特定工作區或資料夾繫結的使用者級任務。此處只能使用 shell 和 process 任務,因為其他任務型別需要工作區資訊。
輸出行為
有時您想控制整合終端面板在執行任務時的行為。例如,您可能希望最大化編輯器空間,並且僅在認為可能存在問題時才檢視任務輸出。終端的行為可以透過任務的 presentation 屬性來控制。它提供了以下屬性:
- reveal:控制是否將整合終端面板帶到最前面。有效值為:
always- 面板始終帶到最前面。這是預設值。never- 使用者必須顯式透過 **View** > **Terminal** 命令 (⌃` (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"
}
}
]
}
您還可以將自定義任務與檢測到的任務的配置混合使用。一個 tasks.json 檔案,該檔案配置 **npm: run lint** 任務並新增一個自定義的 **Run Test** 任務,看起來像這樣:
{
// 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- 開啟包含的任務所在的資料夾時,將執行該任務。當您第一次開啟包含folderOpen任務的資料夾時,系統會詢問您是否允許在該資料夾中自動執行任務。您之後可以透過 **Manage Automatic Tasks** 命令選擇 **Allow Automatic Tasks** 或 **Disallow Automatic Tasks** 來更改您的決定。
- instanceLimit - 允許同時執行的任務例項數。預設值為
1。
自定義自動檢測任務
如上所述,您可以在 tasks.json 檔案中自定義自動檢測的任務。通常,您會這樣做是為了修改 presentation 屬性或附加問題匹配器來掃描任務的輸出以查詢錯誤和警告。您可以透過按任務右側的齒輪圖示直接從 **Run Task** 列表中自定義任務,以將相應的任務引用插入到 tasks.json 檔案中。假設您有以下 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...
});
從全域性 **終端** 選單執行 **執行任務** 將顯示以下選擇器:

按齒輪圖示。這將建立以下 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)或修改 presentation 設定。
使用問題匹配器處理任務輸出
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 檔案中的字串內進行變數替換,您可以在 變數參考 中找到預定義變數的完整列表。
注意: 並非所有屬性都接受變數替換。具體來說,只有
command、args和options支援變數替換。
下面是一個自定義任務配置示例,它將當前開啟的檔案傳遞給 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.json 或 launch.json 指定 Python 擴充套件使用的選定 Python 直譯器,您可以使用 ${command:python.interpreterPath} 命令。
如果簡單的變數替換不足以滿足需求,您還可以透過向 tasks.json 檔案新增 inputs 部分來獲取使用者輸入。

有關 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 的編碼是否有意義。
如果您只需要為特定任務進行調整,請將更改編碼所需的特定於 OS 的命令新增到任務命令列。以下示例適用於 Windows,其預設內碼表為 437。任務顯示一個包含西里爾字元的檔案的輸出,因此需要內碼表 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 檔案的示例。
定義問題匹配器
VS Code 附帶了一些最常見的“內建”問題匹配器。然而,市面上有大量的編譯器和程式碼檢查工具,它們都會產生自己風格的錯誤和警告,因此您可能需要建立自己的問題匹配器。
我們有一個 helloWorld.c 程式,其中開發人員將 printf 誤鍵入為 prinft。使用 gcc 編譯它會產生以下警告:
helloWorld.c:5:3: warning: implicit declaration of function ‘prinft’
我們想建立一個問題匹配器,該匹配器能夠捕獲輸出中的訊息並在 VS Code 中顯示相應的問題。問題匹配器在很大程度上依賴於 正則表示式。下面的部分假定您熟悉正則表示式。
提示: 我們發現 RegEx101 playground,它有一個 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 的可能值為 error、warning 或 info。
這是一個完整的 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) 獲取問題列表,會得到以下輸出:

注意: C/C++ 擴充套件 包含 GCC 的問題匹配器,因此無需自行定義。
在模式內部還可以使用另外幾個屬性。它們是:
- location - 如果問題位置是行、行:列或 startLine,startColumn,endLine,endColumn,則可以使用我們的通用位置匹配組。
- endLine - 問題結束行的匹配組索引。如果編譯器未提供結束行值,則可以省略。
- endColumn - 問題結束列的匹配組索引。如果編譯器未提供結束列值,則可以省略。
- code - 問題程式碼的匹配組索引。如果編譯器未提供程式碼值,則可以省略。
您還可以定義一個僅捕獲檔案的問題匹配器。為此,請定義一個 pattern,並將可選的 kind 屬性設定為 file。在這種情況下,無需提供 line 或 location 屬性。
注意: 一個功能性的模式至少需要為
file和message提供一個匹配組(如果kind屬性設定為file)。如果未提供kind屬性或kind屬性設定為location,則功能模式還必須提供line或location屬性。
注意: 問題匹配器僅解析給定命令的輸出。如果您想解析寫入單獨檔案的輸出(例如,日誌檔案),請在命令執行完畢之前讓該命令列印該單獨檔案的行。
定義多行問題匹配器
某些工具會將原始檔中發現的問題分散在多行上,尤其是使用 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 屬性使用一個問題模式陣列。這樣,您可以為要匹配的每一行定義一個模式。
以下問題模式匹配 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
}
]
}
然而,如果一個資源上有多個問題,此模式將不起作用。例如,想象一下 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
}
其他可修改的問題匹配器屬性包括 background、fileLocation、owner、pattern、severity 和 source。
後臺/監視任務
某些工具支援在後臺執行,同時監視檔案系統變化,然後在檔案發生更改時觸發操作。對於 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,這樣任務才能在後臺持續執行。
一個完整的tasks.json檔案,用於在監視模式下執行tsc任務,看起來如下
{
"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 架構 - 您可以檢視完整的
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"
}
有關後臺任務的更多資訊,請訪問後臺/監視任務。
執行任務時為什麼會出現“命令未找到”?
當您嘗試執行的任務命令未被您的終端識別為可執行時,會出現“命令未找到”訊息。最常見的原因是該命令配置為您的 shell 啟動指令碼的一部分。任務以非登入和非互動方式執行,這意味著您的 shell 的啟動指令碼不會執行。特別是 nvm 以使用啟動指令碼作為其配置的一部分而聞名。
有幾種方法可以解決此問題
- 確保您的命令在您的路徑中,並且不需要啟動指令碼才能新增到您的路徑。這是解決問題的最徹底的方法,也是推薦的解決方案。
- 您可以為任務進行一次性修復,使其作為登入或互動式任務執行。不推薦這樣做,因為它可能產生其他後果。但是,對於單個任務來說,這也可以是一個快速簡便的修復。下面是一個執行此操作的示例任務,使用
bash作為 shell
{
"type": "npm",
"script": "watch",
"options": {
"shell": {
"args": ["-c", "-l"]
}
}
}
上面的 npm 任務將像任務系統預設執行的那樣,使用命令 (-c) 執行 bash。但是,此任務還將 bash 作為登入 shell (-l) 執行。