透過工作整合外部工具
有許多工具可用於自動化工作,例如程式碼檢查、建置、封裝、測試或部署軟體系統。範例包括 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'、空白鍵 和命令名稱來執行工作。在此案例中,為 'task lint'。
可以使用以下設定停用工作自動偵測
{
"typescript.tsc.autoDetect": "off",
"grunt.autoDetect": "off",
"jake.autoDetect": "off",
"gulp.autoDetect": "off",
"npm.autoDetect": "off"
}
自訂工作
並非所有工作或指令碼都可以在您的工作區中自動偵測到。有時,必須定義您自己的自訂工作。假設您有一個指令碼可以在正確設定某些環境的情況下執行測試。該指令碼儲存在您工作區內部的 script 資料夾中,Linux 和 macOS 名稱為 test.sh
,Windows 名稱為 test.cmd
。從全域 終端機 功能表執行 設定工作,然後選取 從範本建立 tasks.json 檔案 項目。這會開啟以下選擇器
注意: 如果您沒有看到工作執行器範本的清單,則您的資料夾中可能已經有一個
tasks.json
檔案,且其內容將在編輯器中開啟。關閉該檔案,然後刪除或重新命名它以用於此範例。
我們正在努力提供更多自動偵測支援,因此此清單在未來將會越來越短。由於我們想要編寫自己的自訂工作,因此請從清單中選取 其他。這會開啟 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:定義如何在使用者介面中處理工作輸出。在此範例中,永遠會顯示顯示輸出的整合式終端機,並且每次執行工作時都會建立
new
終端機。 - options:覆寫
cwd
(目前工作目錄)、env
(環境變數) 或shell
(預設 shell) 的預設值。選項可以針對每個工作設定,也可以全域或針對每個平台設定。在此處設定的環境變數只能從您的工作指令碼或處理序中參考,如果它們是您的 args、command 或其他工作屬性的一部分,則不會解析。 - runOptions:定義何時以及如何執行工作。
- hide:從執行工作快速選取中隱藏工作,這對於非獨立可執行之複合工作的元素可能很有用。
您可以在 tasks.json
檔案中使用 IntelliSense 查看完整的工作屬性和值集。使用 觸發建議 (⌃Space (Windows、Linux Ctrl+Space)) 叫出建議,並閱讀懸停時或使用 閱讀更多... ('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)) 存取工作命令。您可以篩選「工作」,並查看各種與工作相關的命令。
複合工作
您也可以使用 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
中列出的順序執行。任何在 dependsOn
中使用 "dependsOrder": "sequence"
的背景/監看工作都必須有一個問題比對器來追蹤它們何時「完成」。以下工作依序執行工作二、工作三,然後執行工作一。
{
"label": "One",
"type": "shell",
"command": "echo Hello ",
"dependsOrder": "sequence",
"dependsOn": ["Two", "Three"]
}
使用者層級工作
您可以使用 工作:開啟使用者工作 命令來建立未繫結至特定工作區或資料夾的使用者層級工作。此處只能使用 shell
和 process
工作,因為其他工作類型需要工作區資訊。
輸出行為
有時您會想要控制整合式終端機面板在執行工作時的行為。例如,您可能會想要最大化編輯器空間,並且只有在您認為有問題時才查看工作輸出。終端機的行為可以使用工作的 presentation
屬性來控制。它提供以下屬性
- reveal:控制是否將整合式終端機面板帶到前景。有效值為
always
- 永遠將面板帶到前景。這是預設值。never
- 使用者必須使用 檢視 > 終端機 命令 (⌃` (Windows、Linux Ctrl+`)) 明確地將終端機面板帶到前景。silent
- 僅當未掃描輸出是否有錯誤和警告時,才會將終端機面板帶到前景。
- revealProblems:控制在執行此工作時是否顯示「問題」面板。優先於選項
reveal
。預設值為never
。always
- 在執行此工作時永遠顯示「問題」面板。onProblem
- 僅在找到問題時才顯示「問題」面板。never
- 在執行此工作時永遠不顯示「問題」面板。
- focus:控制終端機是否取得輸入焦點。預設值為
false
。 - echo:控制是否在終端機中回顯執行的命令。預設值為
true
。 - showReuseMessage:控制是否顯示「終端機將由工作重複使用,按任意鍵關閉它」訊息。
- 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 工作並新增自訂 執行測試 工作的 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:控制透過 重新執行上次工作 命令執行工作時,變數的評估方式。預設值為
true
,表示在重新執行工作時將重新評估變數。當設定為false
時,將會使用上次工作執行中解析的變數值。 - runOn:指定何時執行工作。
default
- 工作只會在透過 執行工作 命令執行時執行。folderOpen
- 工作將在包含資料夾開啟時執行。第一次開啟包含具有folderOpen
的工作的資料夾時,系統會詢問您是否要允許在該資料夾中自動執行工作。您可以稍後使用 管理自動工作 命令並在 允許自動工作 和 不允許自動工作 之間進行選取來變更您的決定。
- instanceLimit - 允許同時執行的工作執行個體數目。預設值為
1
。
自訂自動偵測到的工作
如上所述,您可以在 tasks.json
檔案中自訂自動偵測到的工作。您通常會這樣做來修改呈現屬性,或將問題比對器附加到掃描工作輸出是否有錯誤和警告。您可以直接從 執行工作 清單中自訂工作,方法是按一下右側的齒輪圖示,以將對應的工作參考插入 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
) 或修改呈現設定。
使用問題比對器處理工作輸出
VS Code 可以使用問題比對器處理工作的輸出。問題比對器會掃描工作輸出文字中已知的警告或錯誤字串,並在編輯器中和「問題」面板中內嵌報告這些字串。VS Code 隨附多個「開箱即用」的問題比對器
- TypeScript:
$tsc
假設輸出中的檔案名稱是相對於開啟的資料夾。 - TypeScript 監看:
$tsc-watch
比對以監看模式執行時,從tsc
編譯器報告的問題。 - JSHint:
$jshint
假設檔案名稱報告為絕對路徑。 - JSHint Stylish:
$jshint-stylish
假設檔案名稱報告為絕對路徑。 - ESLint Compact:
$eslint-compact
假設輸出中的檔案名稱是相對於開啟的資料夾。 - ESLint Stylish:
$eslint-stylish
假設輸出中的檔案名稱是相對於開啟的資料夾。 - Go:
$go
比對從go
編譯器報告的問題。假設檔案名稱是相對於開啟的資料夾。 - CSharp 和 VB 編譯器:
$mscompile
假設檔案名稱報告為絕對路徑。 - Lessc 編譯器:
$lessc
假設檔案名稱報告為絕對路徑。 - Node Sass 編譯器:
$node-sass
假設檔案名稱報告為絕對路徑。
您也可以建立自己的問題比對器,我們將在稍後的章節中討論。
將鍵盤快速鍵繫結至工作
如果您需要經常執行工作,您可以為工作定義鍵盤快速鍵。
例如,若要將 Ctrl+H
繫結至上述的 執行測試 工作,請將以下內容新增至您的 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}
命令。
如果簡單的變數替換不足,您也可以透過將 inputs
區段新增至您的 tasks.json
檔案,從工作使用者取得輸入。
如需有關 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)),然後執行 工作:開啟使用者工作 命令。
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 的編碼。
如果您只需要針對特定工作調整它,則新增作業系統特定的命令,以變更編碼為工作命令列所需的編碼。以下範例適用於 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 - 如果問題位置是 line 或 line,column 或 startLine,startColumn,endLine,endColumn,則可以使用我們的通用位置比對群組。
- endLine - 問題結束行的比對群組索引。如果編譯器未提供結束行值,則可以省略。
- endColumn - 問題結束欄的比對群組索引。如果編譯器未提供結束欄值,則可以省略。
- code - 問題程式碼的比對群組索引。如果編譯器未提供程式碼值,則可以省略。
您也可以定義一個僅擷取檔案的問題比對器。若要執行此操作,請定義一個具有選用 kind
屬性設定為 file
的 pattern
。在這種情況下,無需提供 line
或 location
屬性。
注意: 如果
kind
屬性設定為file
,則功能模式必須至少提供file
和message
的比對群組。如果未提供kind
屬性,或kind
屬性設定為location
,則功能模式也必須提供line
或location
屬性。
注意: 問題比對器僅剖析來自給定命令的輸出。如果您想要剖析寫入到個別檔案(例如記錄檔)的輸出,請讓您執行的命令在完成執行之前,印出個別檔案中的行。
定義多行問題比對器
某些工具會將在來源檔案中找到的問題分散在多行中,尤其是在使用樣式化報告器時。一個範例是 ESLint;在樣式化模式下,它會產生如下輸出
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 樣式化模式的輸出 - 但仍然有一個小問題需要我們在接下來解決。以下程式碼具有第一個正規表示式來擷取檔案名稱,第二個正規表示式擷取行、欄、嚴重性、訊息和錯誤碼
{
"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 樣式問題
{
"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
,以便任務保持在背景中執行。
適用於在監看模式下執行的 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 結構描述 - 您可以檢閱完整的
tasks.json
結構描述和描述。 - 基本編輯 - 了解功能強大的 VS Code 編輯器。
- 程式碼導覽 - 在您的原始碼中快速移動。
- 語言支援 - 了解我們支援的程式設計語言,包括 VS Code 隨附的和透過社群擴充功能提供的。
- 偵錯 - 直接在 VS Code 編輯器中偵錯您的原始碼。
常見問題
任務可以使用與為整合式終端機指定的 shell 不同的 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 啟動腳本的一部分。任務以非登入和非互動方式執行,這表示 shell 的啟動腳本不會執行。特別是 nvm
以使用啟動腳本作為其組態的一部分而聞名。
有幾種方法可以解決此問題
- 請確保您的命令位於您的路徑中,並且不需要啟動腳本即可新增到您的路徑中。這是解決問題最徹底的方法,也是建議的解決方案。
- 您可以對您的任務進行一次性修復,以登入或互動方式執行。不建議這樣做,因為它可能會產生其他後果。但是,對於單個任務來說,這也可能是一個快速簡便的修復方法。以下是一個使用
bash
作為 shell 執行此操作的任務範例
{
"type": "npm",
"script": "watch",
"options": {
"shell": {
"args": ["-c", "-l"]
}
}
}
上述 npm
任務將使用命令 (-c
) 執行 bash
,就像任務系統預設所做的那樣。但是,此任務也會將 bash
作為登入 shell (-l
) 執行。