Define multiple tasks in VSCode

Just in case it helps someone... . If you don't have/want gulp/grunt/etc... or an extra shell script to proxy out your task commands , "npm run" is there already .

this is for webpack and mocha as in "Build and Test" , Shift+Ctrl+B, Shift+Ctrl+T

.vscode/tasks.json:

{
  "name": "npmTask",
  //...
  "suppressTaskName": true,
  "command": "npm",
  "isShellCommand": true,
  "args": [
    "run"
  ],
  "tasks": [
    {
      //Build Task
      "taskName": "webpack",
      //Run On Shift+Ctrl+B
      "isBuildCommand": true,
      //Don't run when Shift+Ctrl+T
      "isTestCommand": false,
      // Show the output window if error any
      "showOutput": "silent",
      //Npm Task Name
      "args": [
        "webpack"
      ],
      // use 2 regex:
      // 1st the file, then the problem       
      "problemMatcher": {
        "owner": "webpack",
        "severity": "error",
        "fileLocation": "relative",
        "pattern": [
          {
            "regexp": "ERROR in (.*)",
            "file": 1
          },
          {
            "regexp": "\\((\\d+),(\\d+)\\):(.*)",
            "line": 1,
            "column": 2,
            "message": 3
          }
        ]
      }
    },
    {
      //Test Task   
      "taskName": "mocha",
      // Don't run on Shift+Ctrl+B
      "isBuildCommand": false,
      // Run on Shift+Ctrl+T
      "isTestCommand": true,
      "showOutput": "always",
      "args": [
        "mocha"
      ]
    }
  ]
}

package.json:

{
  ...
  "scripts": {
    "webpack": "webpack",
    "mocha": "/usr/bin/mocha"
  },
  ...
}

Try this

{
    "version": "0.1.0",
    "command": "cmd",
    "isShellCommand": true,
    "args": ["/C"],
    "tasks": [
        {
            "taskName": "install",
            "args": ["npm install"]
        },
        {
            "taskName": "build",
            "args": ["gulp build"],
            "isBuildCommand": true,
            "problemMatcher": "$gulp-tsc"
        }
    ]
}

What helped me understand this better is the sequence of arguments passed to the command. It may be obvious to some but it is not clear in the documentation.

Omitting some fields to only focus on the command being sent:

{ "command": "myCommand"
  "args": ["myCommandArguments"],
  "tasks" : [ 
    { "taskName": "myTask",
      "args": ["myTaskArguments"],
      "suppressTaskName": false,
    }
  ]
}

The above definition will result in the following command:

myCommand myCommandArguments myTaskArguments myTask

The task name myTask is always last. Since version 0.4 it can be omitted with "suppressTaskName": true.


I use the following tasks.json file to run multiple TypeScript build scenarios. I put a tsconfig.json file in each folder, so that allows me to tune each folder's output individually. Just make sure you suppress the task name, because it tries to put it in the command string.

{
    "version": "0.1.0",
    "command": "tsc",
    "showOutput": "always",
    "isShellCommand": true,
    "args": [],
    "windows": {
        "command": "tsc",
        "showOutput": "always",
        "isShellCommand": true
    },
    "tasks": [
        {
            "taskName": "Build the examples",
            "suppressTaskName": true,
            "isBuildCommand": false,            
            "args": ["-p", "./source/examples", "--outDir", "./script/examples"],
            "problemMatcher": "$tsc"
        },
        {
            "taskName": "Build the solution",            
            "suppressTaskName": true,
            "isBuildCommand": false,        
            "args": ["-p", "./source/solution", "--outDir", "./script/solution"],
            "problemMatcher": "$tsc"
        }   
    ]
}

This is what the folder structure looks like, where /script is the output root and /source is the input root. Both folders reference type declarations in the /typingd folder and /typings folder. TypeScript is somewhat limited to using relative paths in external references, so it helps simplify things if these folder structures are similar.

TypeScript Multi-Build Folder Structure

Oh yea, it makes it easier to launch them selectively if you mark them as non build and override the build key to select a specific task from a list, like so..

// Place your key bindings in this file to overwrite the defaults
[
    { "key": "ctrl+shift+b", "command": "workbench.action.tasks.runTask" }
]

Update: You can always just go entirely rogue, if you want. There may be better ways to handle the args, but this works for me under OSX at the moment.

{
  "version": "0.1.0",
  "isShellCommand": true,
  "linux": { "command": "sh", "args": ["-c"] },
  "osx": { "command": "sh", "args": ["-c"] },
  "windows": { "command": "powershell", "args": ["-Command"] },
  "tasks": [
    {
      "taskName": "build-models",
      "args": ["gulp build-models"],
      "suppressTaskName": true,
      "isBuildCommand": false,
      "isTestCommand": false
    },
    {
      "taskName": "run tests",
      "args": ["mocha ${workspaceRoot}/test"],
      "suppressTaskName": true,
      "isBuildCommand": false,
      "isTestCommand": false
    }
  ]
}

I don't know the proper answer to this (and would also like to know), but my ugly workaround in case it helps anyone. I'm on Windows, I've ended up creating myself a simple batch script which could contain simply

"%1" "%2"

Then my tasks.json looks something like

{
    "version": "0.1.0",
    "command": "c:\\...\\mytasks.bat"
    "tasks" : [
        {
            "taskName": "myFirstTask",
            "args": "c:\\...\\task1.exe", "${file}"],
        },
        {
            "taskName": "mySecondTask",
            "args": "c:\\...\\task2.exe", "${file}"],
        },
    ]
}