Last Updated: 7/24/2016

Within an older blog post, entitled “Webpackin’ your ES 2015 / Angular 1.x SPA“, I explained how to use npm scripts to execute Webpack commands. To quickly recap, this approach took advantage of custom scripts in the package.json file, as depicted in the gist below.


"scripts": {
"dev-build": "webpack -d –display-modules –progress",
"dist-build": "webpack -p –display-modules –progress"
}

view raw

package.json

hosted with ❤ by GitHub

As an avid Visual Studio (VS) Code user, I found myself yearning for a more seamless means of integrating Webpack with the editor. Why? Truthfully, I had been spoiled by Task Runner Explorer in Visual Studio 2015. Surely Microsoft had pondered how to solve the problem of task management in their latest modern web, cross-platform editor venture. At least that was my expectation. Thankfully, there is a viable alternative to the npm scripts approach which leverages an editor extensibility point for integrating with third-party tools.

The aforementioned extensibility point in VS Code is a JSON-based configuration file known as tasks.json. You can read more about its purpose and uses here. As of VS Code 0.8.0, this file should be placed within a .vscode folder at the project’s root. In versions prior to 0.8.0, the .vscode folder was named .settings. While VS Code lacks a rich item-templating system such as that available in full-blown Visual Studio, it does assist us in creating this file.

To create a new tasks.json file, open Command Palette (via Ctrl + Shift + P on Windows), and type “configure”. The “Tasks: Configure Task Runner” option will appear. Select it, and you’re presented with a list of templates. Select “Others”, and notice that an unassuming configuration file is stubbed out for you. Full IntelliSense is provided via Ctrl + Space to help guide you to the correct solution.

Configuring the Extensibility Point: tasks.json

Below is a sample tasks.json file exhibiting the Webpack integration. It replicates the functionality of the two npm scripts appearing above, verbatim.


{
"version": "0.1.0",
"command": "${workspaceRoot}/node_modules/.bin/webpack",
"isShellCommand": true,
"args": [
"–display-modules",
"–progress"
],
"echoCommand": true,
"tasks": [
{
"args": [
"-d"
],
"suppressTaskName": true,
"taskName": "webpack dev",
"isBuildCommand": true
},
{
"args": [
"-p"
],
"suppressTaskName": true,
"taskName": "webpack dist",
"isBuildCommand": false
}
]
}

view raw

tasks.json

hosted with ❤ by GitHub

Here’s a summary of the crucial properties appearing within the JSON file:

1. command

This property value references the webpack binary stored in the project’s local node_modules folder. It uses a predefined variable in VS Code, called ${workspaceRoot}. This variable expands to the absolute path of the folder which is opened in VS Code. If you come from an MSBuild background, this may remind you of the $(MSBuildProjectDirectory) variable that would be accessed in an AfterBuild target, for example.

2. isShellCommand

When set to true, this property value signals VS Code to execute the associated command in the shell. Change its value to false, and an error such as the following will appear:

running command> c:\working_folder\sample_apps\webpack-angular-es2015/node_modules/.bin/webpack --display-modules --progress -d
Failed to launch external program ${workspaceRoot}/node_modules/.bin/webpack --display-modules --progress.
spawn c:\working_folder\sample_apps\webpack-angular-es2015/node_modules/.bin/webpack ENOENT

3. args

There are a few distinct renditions of this property in our example. The top-level instance, appearing at line 5, contains parameters which will cascade down to all task configurations. In regards to overall maintainability of this configuration file, the top-level instance allows us to keep things DRY. The lower-level instances, appearing at lines 12 and 20, apply to their respective local task configurations. In other words, when executing the webpack dist task, both the top- and the lower-level values will be disbursed to the shell as CLI arguments.

Speaking of CLI arguments, how would one know what’s available in Webpack? The options are documented here. Using this knowledge, one could easily create a new task configuration object literal which makes use of Webpack’s –watch CLI option. Or maybe it makes the most sense to add –watch as a second entry in the args array for the webpack dev task.

4. echoCommand

When set to true, this property value instructs VS Code to print the command-to-be-executed in the console. Did you notice the following line in the console output?

running command> c:\working_folder\sample_apps\webpack-angular-es2015/node_modules/.bin/webpack --display-modules --progress -p

5. tasks

This property’s value is an array of the possible task configurations. Each task configuration is defined as an object literal. In this example, a development and a production-grade build task were defined. The development build task necessitates a “-d” CLI argument, while the production-grade build task requires a “-p” argument. To support this behavior, there is clearly a need for two separate configurations. This is the justification for the two object literals in the tasks array.

6. suppressTaskName

When set to true, this property will prevent the taskName value from being appended to the command executed in the shell. If we were to execute the webpack dist task configuration with this property value set to false, the following command would be sent to the shell for execution:

running command> c:\working_folder\sample_apps\webpack-angular-es2015/node_modules/.bin/webpack --display-modules --progress -p webpack dist

Note the bolded portion of that command. A problem is impending. Consequently, this command will result in an error containing a message similar to:

ERROR in multi main
Module not found: Error: Cannot resolve module 'webpack dist' in c:\working_folder\sample_apps\webpack-angular-es2015/app
@ multi main

7. taskName

This property value represents the alias by which the task configuration is referenced in VS Code. Launch Command Palette, type “task”, select the “Tasks: Run Task” option in the search results, and notice that the names appearing correspond to the taskName property values.

8. isBuildCommand

A build command is invoked using the Ctrl + Shift + B key combination on Windows. Alternatively, selecting the “Tasks: Run Build Task” option from Command Palette accomplishes the same thing. In the tasks.json file provided, the webpack dev task configuration is marked as the default build command. Setting the isBuildCommand property to true for the webpack dist task configuration would have no effect, In fact, the editor will honor only the first occurrence. Order is paramount here.

Running a Webpack Task via Command Palette

Using VS Code’s Command Palette, the task configurations defined within this file’s tasks property can be discovered and launched. Simply choose Command Palette’s “Tasks: Run Task” option. In the following screenshot, note that two task aliases appear after selecting the “Tasks: Run Task” option. These correspond to the taskName property values within tasks.json’s tasks array.

Command Palette

Upon selecting the webpack dist task alias from the drop-down, the task runs, and the following output appears:

webpack dist task output

As was explained in the isBuildCommand property’s description above, Ctrl + Shift + B is an even more convenient way to launch the default build task.

Conclusion

With VS Code’s robust task integration support, the possibilities are truly endless. Think of all the other tools you’re invoking from the command line today to augment your development workflow. Maybe it’s Grunt, Gulp, MSBuild, ESLint, Babel, or the TypeScript compiler. Now these tools can be invoked without leaving the comfort of the editor. That’s a huge win in terms of developer productivity!

For a deeper dive into VS Code’s task functionality, I highly recommend watching John Papa’s Visual Studio Code course on Pluralsight. In fact, this is where I first learned the inner workings of this feature.

14 Comments »

  1. For the new version of VS Code after selecting the task runner config you have a list o different presets. To satisfy the requirements for this post you need to select ‘other’ which will then stub out the task.json file that you can just copy and past the task.json listed above.

    Like

  2. Thanks for this helpful post. I am getting up and running with Typescript, VS Code, React, and Webpack all for the first time and this really helped.

    > Using VS Code’s Command Palette, the task configurations defined within this file’s tasks property can be discovered and launched. In the following screenshot, note that two task aliases appear after typing “task”.

    Just a heads up to anyone else, this has changed. If you open the *Command Palette* as stated here, then you will have to type `task` and select `Run Task` first, then you will see a list of your tasks. However if instead you use the *Quick Open* option, you can just type `task` followed by a space as stated.

    Also an side to the author, if you see this. I don’t know why, or if you even care, but your website for some reason acts oddly with Safari. If I switch to another tab then back here, Safari spins for a moment. Doesn’t do that normally so I don’t know what is up, but certainly annoying.

    Like

    • Thank you for the feedback, John! I’ve updated that portion of the blog post to reflect the behavior of the latest stable release (1.3.1). I will definitely look into that Safari issue.

      Like

  3. has anyone figured out how to use intellisense with webpack’s aliases? I still can’t get code peek to work when using alias for my folder structure. Any help would be greatly appreciated! Thanks again

    Like

      • Hey, thanks for the quick reply! Sorry I wasn’t clear, I was more interested in using code peek from VS code. So currently I have
        import TestService from ‘services/test-service’
        instead of:
        import TestService from ‘../../../../services/test-service’

        I do this by setting resolve alias inside the webpack config file, but I can’t seem to get VS Code to resolve those paths. Thanks again for all your help!

        Like

  4. I follow you now. Thanks for clarifying! I’m not aware of a way to support that in VS Code, since it would require knowledge of the Webpack config file’s resolve.alias property. I was hoping to see a setting for this in jsconfig.json, but I’m not seeing such a thing.

    I’d highly recommend opening an issue here. If nobody is able to help there, it would at least serve as great feedback for the product team. Who knows…maybe they’ll add it to the product backlog too.

    Like

  5. >you can enable IntelliSense in the webpack.config.js file
    This is exactly what I’d like to do but I’m having trouble. Steps I’ve taken:
    1. Created jsconfig.json from VS Code’s lightbulb (at bottom right)
    2. ‘typings init`
    3. `typings install dt~webpack -SG`
    The more I research and learn about typings, the more I think I won’t get Intellisense for the exported object in webpack.config.js. A basic webpack.config.js might look like this:
    module.exports = {
    entry: ‘./lib/app.js’,
    output: {
    path: ‘./bin’,
    filename: ‘bundle.js’
    }
    }
    What I’d like to do is type a comma in this object and see what webpack configuration options are available, but there’s no indication to VS Code here that it’s dealing with webpack. Am I wrong?

    Like

  6. I also do not think that’s possible. What I was trying to convey about IntelliSense is that you can do something like the following in webpack.config.js:

    const webpack = require('webpack');
    webpack.

    Once you type that period after “webpack”, IntelliSense will show you what’s available (assuming you have jsconfig.json and the type definitions installed via Typings). If you try to achieve the same inside of the object literal being exported, you’re correct that VS Code isn’t going to know anything about Webpack.

    Sean Larkin, a member of the Webpack core team, was researching ways to support this with a schema hosted on the SchemaStore project. Unfortunately, that wouldn’t work either since this is JavaScript, not JSON. I’d recommend pinging Sean on Twitter (https://twitter.com/TheLarkInn) to see if he has ideas.

    Like

  7. Hi, When I tried to do this – I got errors forisShellCommand isBuildCommand and in the tasks.json file as below,

    The property isShellCommand is deprecated. Use the type property of the task and the shell property in the options instead. See also the 1.14 release notes.
    Specifies whether the command is a shell command or an external program. Defaults to false if omitted.

    The property isBuildCommand is deprecated. Use the group property instead. See also the 1.14 release notes.
    Maps this task to Code’s default build command.

    I followed the instruction here
    https://code.visualstudio.com/docs/editor/tasks
    and came up with – still testing to see if it works – it runs but the window in which it runs (in windows 10) closes when it completes so I’m not sure if it works or not…..I’m really new at this

    “version”: “2.0.0”,
    “command”: “${workspaceRoot}/node_modules/.bin/webpack”,
    “args”: [
    “–display-modules”,
    “–progress”
    ],
    “echoCommand”: true,
    “tasks”: [
    {
    “args”: [
    “-d”
    ],
    “suppressTaskName”: true,
    “taskName”: “webpack dev”,
    “type”: “shell”,
    “group”: “build”
    },
    {
    “args”: [
    “-p”
    ],
    “suppressTaskName”: true,
    “taskName”: “webpack dist”,
    “type”: “shell”,
    “group”: “build”
    },
    {
    “type”: “npm”,
    “script”: “install”,
    “group”: {
    “kind”: “build”,
    “isDefault”: true
    }
    }
    ]
    }

    Like

Leave a comment