Skip to content

Configuring Visual Studio

Joseph M. Deming edited this page Mar 15, 2017 · 13 revisions

This document at time of writing documents Visual Studio 2015.

This is one set of options to tie in the tasks necessary to run the ESLint installation and run a check on desired files during build.

SUMMARY AND PRE-REQUISITES

There are 2 essential 'steps' that are outlined in the documents below:

  1. Install ESLint (in these examples to the project directory)
  2. Run ESLint during a build of a given project

Pre-requisites:

  1. Install node.js/npm on the machine if it is not available**: https://nodejs.org/en/download/
  2. Install this VisualStudio extension (either via link/extensions in VS or chocolatey)

This requires node.js/npm to be installed and available on PATH on the dev machine (and teamcity agent). We do not install this during our setup scripts because the version of node that is installed can be sensitive for different developers environments.

What you get:

  • ESLint node package runners will be installed when you open the solution
  • ESLint checks based off of shared-repository TSC settings will be respected
  • Settings you wish to override for your environment will be available
  • On each build, ESLint checks will be run
  • Any errors will fail the build and show up in the 'Error Console' where they can be double-clicked to find/fix
  • The same checks will be done in teamcity build with teamcity-formatted output similar to failed tests in build log

What you don't get:

  • You will not get IntelliSense highlighting in the editor frame while you are editing a file
  • You will not get an up-to-date output of issues in the 'Error' window while you are editing
  • You will not know about errors that exist in JS until you do a build essentially
  • Based on my research this is where VS fall short at this time, I expect that VS2017 will allow some of this integration to be improved

Add ESLint Installation and ESLint Runner .bat scripts

Add ESLint Installation to repository and solution

Add this batch script that does ESLint installation somewhere in the repository and add it to solution.

set SOLUTIONDIR=%1

cd %SOLUTIONDIR%

call npm set loglevel error
call npm install eslint
call npm install eslint-config-techsmith

Add ESLint Runner to repository and solution

Note that this script is somewhat targeted at the Presentation directory structure design. It assumes the location of the 'Scripts' directory relative to the project root and the .eslintrc file relative to the project root. However, it should be apparent how to make those dynamic arguments to the script or how modify the script below to hardcode them for your solution. (technically, using this recipe you do not have to add this file to the solution if you wish to keep it out of the .sln file for some reason, but you do need it in the GH repository)

set SOLUTIONDIR=%1
set PROJECTNAME=%2
set ESLINTCONFIGPATH=%PROJECTNAME%\Scripts\.eslintrc
set ESLINTSCRIPTFILTER=%PROJECTNAME%\Scripts\**\*.js
set OUTPUTMODE=%3
if %OUTPUTMODE% == teamcity (
   set OUTPUTFORMAT=node_modules/eslint-teamcity/index.js
) else (
   set OUTPUTFORMAT=visualstudio
)

cd %SOLUTIONDIR%

call node_modules\.bin\eslint --format %OUTPUTFORMAT% -c %ESLINTCONFIGPATH% %ESLINTSCRIPTFILTER%

Add .eslintrc file to your solution

Add this file somewhere near the top-level of where your .js scripts are located in your project(s).

{
   "extends": "techsmith",
   "env": {
      "browser": true
   },
   "rules": {
      // comment this in to turn the 'linebreak-style' TSC setting from error to off
      //"linebreak-style": [ "off" ],
      // comment this in to turn the 'vars-on-top' TSC setting from error to warn
      //"vars-on-top": [ "warn" ]
   },
   "globals": {
      //here you define globals that may be valid in your JS environment to prevent 'no-globals' from warning about the items in this list specifically
      //"angular": true,
      //"$": true,
      //"_": true,
      //"moment": true
   }
}

Above are some commented out examples you may wish to tune for your environment.

Note: in the script above the .eslintrc is in the solution located at '%PROJECTNAME%\Scripts.eslintrc' and the related .js scripts are in '%PROJECTNAME%\Scripts'; if your directory structure and/or location of .eslintrc varies from this modify the script above accordingly.

Hook up 'ESLint Installation' script as a TaskRunner task to be run on 'Project Open'

  1. Inside Visual Studio, with project open, RClick on the 'ESLint Installation' .bat script in your solution
  2. Add to Task Runner (if this does not show up you need to restart VS after installing the VS extension above)
  3. View --> Other Windows --> Task Runner Explorer
  4. Inside the 'Task Runner Explorer' you should be able to see your script in the hierarchy
  5. RClick on the script and select Bindings --> 'Project Open'
  6. At this point you should have something very similar to the 'commands.json' below now in your solution where you will have to modify it manually to add the '$(SolutionDir)' argument to the script
  7. (Optional) As a side-test at this time you can 'Run' the script from from 'Task Explorer' to see if it installs as expected

Add file named commands.json in at the

{
   "commands": {
      "ESLintInstall": {
         "fileName": "cmd.exe",
         "workingDirectory": ".",
         "arguments": "/c ..\\BuildScripts\\ESLintInstall.bat $(SolutionDir)"
      }
   },
   "-vs-binding": { "ProjectOpened": [ "ESLintInstall" ] }
}

Hook up 'ESLint Runner' script as a new 'Target' in the build process for each project where we wish to run

  1. RClick on target project and click 'Unload Project'
  2. Open the unloaded project .csproj file in Visual Studio (or editor) to directly edit it's contents
  3. (Suggested toward the bottom) Insert this snippet at the same level as other 'Target' nodes
  4. Modify the path to the .bat file relative to your own
  5. Tune the arguments passed into the script if they end up varying from the example above
<!-- SolutionDir == '*Undefined*' when package-pusher is making the project, wed dont want to run this rule in that case -->
  <Target Name="BeforeBuild" Condition=" '$(SolutionDir)' != '' And '$(SolutionDir)' != '*Undefined*' ">
    <Exec Command="$(SolutionDir)..\BuildScripts\ESLintRunner.bat $(SolutionDir) $(ProjectName) visualstudio" IgnoreExitCode="false" />
  </Target>

End of VS and repository changes

  • Commit all of these changes and check them in
  • You will have to restart VS yourself to have the 'Task Runner' task install the NPM modules (unless you ran it manually as a test)
  • NOTE 'Task Runner' takes 60 secs to complete asynchronously when you open project the first time, it is possible for a person to click 'Build Solution' too quickly and get NPM module missing or ESLint cmd not found if they open and 'Build' too quickly. If you get this type of error check the 'Task Runner Explorer' console to see the status of the on-load installation steps. If/when they complete with code '0' simply run build again.

Configure TeamCity to do builds that install and run ESLint

  1. Add a 'Command Line' build step named something like 'Install ESLint', the commands should be about as follows
cd ./src
call npm set loglevel error
call npm install eslint
call npm install eslint-config-techsmith
call npm install eslint-teamcity
  1. Add a 'Command Line' build step proceeding that named something like 'Run ESLint', the command should be about as follows (modify the path to point the the 'ESLint Runner' .bat file in your .sln, also modify arguments if applicable). If you had multiple projects for which you wished to process ESLint rules there would be multiple lines like the following.
BuildScripts\ESLintRunner.bat <relative-path-to-your-sln-here> <your-project-name-here> teamcity
  1. Order these 2 build steps before the 'Build Solution' step (or any step that runs MSBuild). MSBuild will also run ESLint and fail internally if rules fail, but hitting these 2 steps first will cause the output to be more readable and formatted for TeamCity and the build to not even try MSBuild effort if the rules will fail anyway.

Things above to re-address or improve going forward

  1. Use a package.json file to manage the node packages instead of hardcoding things like npm install eslint in scripts
  2. Use 'Task Runner' to run the 'ESLint Runner' on build similar to how we hook up the 'ESLint Installer' script but trigger 'On Build' instead. This currently works but will NOT show the errors found in the 'Error Console', they will show up in 'Output Console' but are not link-able. Here https://blogs.msdn.microsoft.com/webdev/2016/01/06/task-runners-in-visual-studio-2015/ there is a 'Comment' from the author describing how you currently cannot hook up 'Task Runner' output to the 'Error Console' but it will be coming in a new version of 'Task Runner'. So... maybe VS2017 helps us again? This improvement would deprecate the steps where you manually 'hack' the .csproj file.
  3. Revisit the eslint VS built-in settings to enhance intellisense and while-editing error console info once VS improves it's native eslint support. As of now (2017-03) VS2015 has it 'built-in' but broken (one note of ongoing issue is here https://github.com/aspnet/Tooling/issues/727). I suspect that VS2017 will improve this native functionality and it will no longer be an optional 'Preview' extension to install.
  4. Explore alternatives to using commandtaskrunner. Grunt and Gulp taskrunners are built in, webpack is another task-runner option that may be more future-thinking and possibly built-in to VS2017. This may remove the annoyance of having to install the commandtaskrunner extension and provide better flexibility for the task-runner using more node-oriented approach.