任務(wù)系統(tǒng)的知識(shí)體系相對(duì)復(fù)雜,今天繼續(xù)介紹任務(wù)系統(tǒng)的內(nèi)容:任務(wù)配置的更多參數(shù)以及任務(wù)結(jié)果的分析功能。
在自定義的任務(wù)里可以使用 command 屬性,并在這個(gè)屬性里指定我們想要運(yùn)行的腳本或者程序。但是有的時(shí)候我們運(yùn)行這個(gè)腳本的時(shí)候需要傳入一些參數(shù),這時(shí)候就可以簡(jiǎn)單地把這些參數(shù)全部寫(xiě)在 command 里,比如說(shuō)在運(yùn)行 echo ‘Hello World’ 這樣的腳本時(shí),我們可以把它直接放入 command 這個(gè)屬性的值中:
{
"label": "echo",
"type": "shell",
"command": "echo 'Hello World'"
}
JSON
我們也可以使用一個(gè)新的屬性,叫做args。它是一個(gè)字符串的數(shù)組,在運(yùn)行指定 command 的時(shí)候,args 里的每個(gè)值都會(huì)被當(dāng)作其參數(shù)傳入,所以就上面的例子,我們還可以寫(xiě)為:
{
"label": "echo",
"type": "shell",
"command": "echo",
"args": [
"hello world"
]
}
JSON
但這里要注意的是,因?yàn)槲覀兪褂玫氖?JSON 來(lái)存儲(chǔ)這些參數(shù),而 JSON 的數(shù)據(jù)格式并不一定能夠滿足 shell 的要求,比如不同的 shell 對(duì)空白符、$ 符之類的都有不同的解析方式,這時(shí)候就需要對(duì)這些符號(hào)進(jìn)行轉(zhuǎn)義。我們可以將參數(shù)調(diào)整為下面的格式:
"args": [
{
"value": "Hello World",
"quoting": "escape"
}
]
JSON
我們可以看到,args 里的值,從一個(gè)字符串,變成一個(gè)對(duì)象。它的第一個(gè)鍵是 value 值,也就是原先的字符串,而第二個(gè)鍵 quoting 則決定了該如何處理這段字符串。
quoting在默認(rèn)情況下是使用escape轉(zhuǎn)義,也就是說(shuō)任務(wù)系統(tǒng)會(huì)根據(jù)我們所使用的 shell 的要求,對(duì)這段字符串進(jìn)行轉(zhuǎn)義。比如說(shuō),bash 下我們使用\來(lái)轉(zhuǎn)義特殊字符,那么當(dāng)我們執(zhí)行這個(gè)任務(wù)時(shí),真正運(yùn)行的腳本如下:
echo Hello\ World
Shell
從上面的代碼示例里,你可以看到空格被轉(zhuǎn)義成了 \ 。
除此之外,quoting 這個(gè)參數(shù)還有另外兩個(gè)值。第一個(gè)是 strong,那么在 bash里, 我們將會(huì)使用單引號(hào)包裹這段字符串,然后傳給腳本,那么最終執(zhí)行的腳本是:
echo 'Hello World'
Shell
另一個(gè)值是 weak,在 bash 里我們則會(huì)使用雙引號(hào)來(lái)包裹這段字符串。如:
echo "Hello World"
Shell
strong 和 weak 分別對(duì)應(yīng)了 shell 不同的使用引號(hào)的策略,而bash、cmd、powershell 也都有各自的策略。如果你不熟悉,可以搜索 “quoting mechanism” 來(lái)查找,當(dāng)然我們?cè)?a rel="external nofollow" target="_blank" target="_blank">VS Code關(guān)于 Task 參數(shù)轉(zhuǎn)義部分的文檔也有涉及。
對(duì)了,當(dāng)你在 VS Code 里編輯這個(gè) tasks.json 文件的時(shí)候是提供了自動(dòng)補(bǔ)全和提示的,所以你可以看看它還支持什么別的屬性,也可以試著根據(jù)提示進(jìn)行修改。我們?cè)谖恼碌淖詈?,還會(huì)介紹幾個(gè)其他重要的屬性的。
到這里我已經(jīng)基本把任務(wù)系統(tǒng)是如何設(shè)置的、如何運(yùn)行的跟你簡(jiǎn)單地介紹了一遍,相信你已經(jīng)可以將一些簡(jiǎn)單的腳本用任務(wù)系統(tǒng)來(lái)執(zhí)行了。但是如果說(shuō)任務(wù)系統(tǒng)只是提供一種新的運(yùn)行腳本的方式,或者說(shuō)幾個(gè)快捷鍵進(jìn)行一鍵的腳本運(yùn)行的話,那跟集成終端比只能說(shuō)是往前邁了小小的一步。
不過(guò),任務(wù)系統(tǒng)還有一個(gè)真正的威力,就是我們可以自動(dòng)地去分析任務(wù)運(yùn)行的結(jié)果。
任務(wù)運(yùn)行的結(jié)果是由 tasks.json 里任務(wù)的一個(gè)屬性 problemMatcher 來(lái)控制的。我們可以選擇 VS Code 內(nèi)置的,或者其他插件提供的結(jié)果分析器,甚至可以自己書(shū)寫(xiě)結(jié)果分析器來(lái)分析任務(wù)運(yùn)行結(jié)果,然后將其中出現(xiàn)的錯(cuò)誤或者警告,顯示在問(wèn)題面板中。
比如說(shuō)我們跑一個(gè)構(gòu)建腳本,有的時(shí)候代碼寫(xiě)的不對(duì)了,構(gòu)建腳本就會(huì)打印出在哪個(gè)文件的第幾行有一個(gè)什么類型的錯(cuò)誤,然后我們?cè)俳柚线m的結(jié)果分析器,去解析相對(duì)冗余的結(jié)果日志,最后把它們?nèi)雴?wèn)題面板中。這樣我們?cè)跁?shū)寫(xiě)的過(guò)程當(dāng)中,就不需要到結(jié)果日志里去找錯(cuò)誤和警告了,只需要查看問(wèn)題面板,點(diǎn)擊錯(cuò)誤跳轉(zhuǎn)到代碼處,直接進(jìn)行修改就可以了。
另外,如果我們?cè)谶\(yùn)行一些腳本的時(shí)候使用了觀察模式 (watch mode),那么每次代碼有更新,就會(huì)重新運(yùn)行腳本輸出日志,這時(shí)一個(gè)實(shí)時(shí)分析日志并提供反饋的結(jié)果分析器就大大提升效率了。
VS Code 現(xiàn)在已經(jīng)自帶了以下幾種問(wèn)題分析器:
如果這些還不適用于你的項(xiàng)目,那你可以看看插件市場(chǎng)上有沒(méi)有問(wèn)題分析器相關(guān)的插件Search results – problem matcher | Visual Studio Code , Visual Studio Marketplace,或者看看你使用的語(yǔ)言插件是否已經(jīng)支持了相對(duì)應(yīng)的結(jié)果分析。
VS Code 還支持我們自己書(shū)寫(xiě)結(jié)果分析器,不過(guò)這個(gè)涉及一定的正則表達(dá)式的知識(shí),如果你已經(jīng)有所了解,那么可以繼續(xù)看下去。如果還未有涉及,還請(qǐng)學(xué)習(xí)正則表達(dá)式,然后閱讀下面的示例。
首先我們將下面的配置,放入任務(wù)配置文件 tasks.json。
{
"version": "2.0.0",
"tasks": [
{
"label": "echo",
"type": "shell",
"command": "echo",
"args": [
{
"value": "index.js:5:3: warning: unused variable",
"quoting": "escape"
}
],
"problemMatcher": {
"owner": "echo",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
}
]
}
JSON
這個(gè)示例,較之前我們介紹的示例,多一個(gè) problemMatcher,其他都是一樣的。但是這個(gè) problemMatcher 不再是一個(gè)字符串,而是一個(gè)對(duì)象;我們?cè)谶@個(gè)對(duì)象里,自定義了如何去分析任務(wù)運(yùn)行的結(jié)果。
這個(gè)任務(wù)執(zhí)行的腳本是:
echo index.js:5:3:\ warning:\ unused\ variable
Shell
在 bash 下執(zhí)行的結(jié)果如下:
index.js:5:3: warning: unused variable
這是我們通常能夠看到的構(gòu)建或者測(cè)試腳本報(bào)錯(cuò)時(shí)的輸出結(jié)果,我們需要從中把以下幾個(gè)信息提取出來(lái):
通過(guò)文件的地址、行號(hào)和列號(hào),我們能夠快速定位到錯(cuò)誤的位置,而錯(cuò)誤的級(jí)別和信息則能夠幫助我們了解錯(cuò)誤的具體情況。為了把這個(gè)信息提取出來(lái),我們將會(huì)使用正則表達(dá)式的捕獲組(group capture)。比如在我們的例子里,我們提供了一個(gè)正則表達(dá)式:
"^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$"
當(dāng)我們拿這個(gè)正則表達(dá)式去匹配下面的字符串時(shí),
index.js:5:3: warning: unused variable
捕獲組 1 對(duì)應(yīng)的是文件的名字,捕獲組 2 則是行號(hào),以此類推。然后我們通過(guò)給這個(gè)任務(wù)的 problemMatcher 設(shè)置 pattern 來(lái)告訴 VS Code,我們想使用什么樣的正則表達(dá)式去匹配,以及文件名 file、行號(hào) line 、列 column 等該從第幾個(gè)捕獲組讀取出來(lái)。
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
JSON
除了 pattern 這個(gè)屬性,我們還需要 fileLocation 文件位置來(lái)告訴 VS Code,如何在當(dāng)前文件夾下定位這個(gè)文件。比如我們從錯(cuò)誤信息里得到 index.js 是一個(gè)相對(duì)的地址,然后我們通過(guò)把 fileLocation 設(shè)置為 [“relative”, “${workspaceFolder}”] 來(lái)提示 VS Code,請(qǐng)把 index.js當(dāng)作相對(duì)地址,然后在當(dāng)前文件夾下定位。
最后,當(dāng)我們運(yùn)行了這個(gè)任務(wù),我們就能夠在問(wèn)題面板里看到這個(gè)錯(cuò)誤信息,而當(dāng)我們點(diǎn)擊這個(gè)錯(cuò)誤時(shí),則能夠在編輯器里打開(kāi) index.js 這個(gè)文件并跳轉(zhuǎn)到第五行。
上面就是一個(gè)非?;A(chǔ)的問(wèn)題分析器 problemMatcher 了。它能夠逐行使用正則表達(dá)式分析任務(wù)執(zhí)行的結(jié)果,并輸出給問(wèn)題面板。但是如果你的任務(wù)執(zhí)行的結(jié)果里,錯(cuò)誤信息橫跨多行,那么這個(gè)分析器就不起作用了。這時(shí)候你就需要一個(gè)更強(qiáng)大的多行結(jié)果分析器,這個(gè)我會(huì)在后面的 VS Code 高級(jí)定制章節(jié)里進(jìn)一步介紹,如果你非常感興趣現(xiàn)在就想動(dòng)手試一試的話,也可以閱讀Tasks in Visual Studio Code 自行學(xué)習(xí)。
很多時(shí)候,我們的項(xiàng)目并不只包含一種語(yǔ)言、一個(gè)框架,這導(dǎo)致我們需要同時(shí)使用多種不同的構(gòu)建或者測(cè)試工具,并需要額外寫(xiě)一些腳本把它們同時(shí)運(yùn)行起來(lái)。不過(guò)不用擔(dān)心,VS Code 的任務(wù)系統(tǒng)也為這種情況提供了便捷的任務(wù)定制方案。比如說(shuō)我們的項(xiàng)目里有前端和后端兩種代碼,然后我們希望同時(shí)把它們運(yùn)行起來(lái),這時(shí)我們就要首先為前、后端分別定義好各自的任務(wù),這里我們將它們稱為 “frontend”“backend”。我們可以新建一個(gè)任務(wù),內(nèi)容如下:
{
"taskName": "compile",
"dependsOn": [
"frontend",
"backend"
],
"group": {
"kind": "build",
"isDefault": true
}
}
JSON
這個(gè)任務(wù)有個(gè)新的屬性,叫做 dependsOn。它指定了“compile”這個(gè)任務(wù)依賴于 “frontend” 和 “backend” 這兩個(gè)腳本,而這個(gè)任務(wù)本身并沒(méi)有制定任何的命令 (command),同時(shí)我們還制定了這個(gè)任務(wù)為默認(rèn)的生成任務(wù)(build),所以當(dāng)我們按下 Cmd + Shift + B,我們就能夠看到“frontend” 和 “backend” 這兩個(gè)任務(wù)都被觸發(fā)執(zhí)行了。
通過(guò)多任務(wù)的設(shè)置,我們就真正做到一鍵運(yùn)行了。不過(guò)要注意,這個(gè)功能在 VS Code 里叫做 Compound tasks ,這可能并不是一個(gè)特別好記的英文名字。
以上就是我們今天的全部?jī)?nèi)容了。VS Code 的任務(wù)系統(tǒng),在我看來(lái),精髓全在這個(gè) tasks.json 的書(shū)寫(xiě),也就是說(shuō)一個(gè) JSON 對(duì)象,控制了任務(wù)的方方面面。而我只是根據(jù)我的理解和學(xué)習(xí)方式,為你做了一次梳理:
對(duì)一個(gè)個(gè)體而言,任務(wù)系統(tǒng)的優(yōu)勢(shì)可能還不明顯。但是如果你通過(guò)設(shè)置任務(wù)系統(tǒng)、添加錯(cuò)誤分析器,把工作流程針對(duì) VS Code 進(jìn)行一次優(yōu)化,這樣你的同事在使用 VS Code 的時(shí)候,也就可以直接使用 VS Code 的任務(wù)系統(tǒng)和問(wèn)題面板了,而無(wú)需為命令行腳本工具而煩惱了。
當(dāng)然,你熟悉完我上面所講的那些知識(shí)點(diǎn)后,可能還會(huì)有更多的問(wèn)題提出來(lái),我們可以在討論區(qū)里交流。另外,我也鼓勵(lì)你自己動(dòng)手調(diào)試這個(gè)文件,VS Code 為這個(gè)文件做了專門(mén)的自動(dòng)補(bǔ)全,所以你可以通過(guò)提示來(lái)研究學(xué)習(xí)。由于篇幅所限,我可能無(wú)法將任務(wù)系統(tǒng)的每個(gè)知識(shí)點(diǎn)都覆蓋到,比如說(shuō)任務(wù)系統(tǒng)的配置支持預(yù)定義參數(shù),但是這個(gè)知識(shí)點(diǎn)我們?cè)诮榻B代碼片段里涉及到了,如果你對(duì)代碼片段的預(yù)定義參數(shù)很熟悉,這個(gè)也就不陌生了。
更多建議: