A couple weeks ago I noticed my laptop fans running non-stop as I was working on a .Net Core web application. It's an ASP.Net Core 2.2 web app running a react front-end and it's wired to dual launch .Net and the react dev server when we start debugging (based on the SPA template from Visual Studio).
Diagnosing the problem
My first stop was Task Manager to see what was eating the CPU.
I'm not currently debugging, but node.js is really chewing up the CPU. If it wasn't the debugger, than it could only be NCrunch, but why?
It turns out we have a common target in our project to npm install
when
we build in DEBUG:
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build"
Condition=" '$(Configuration)' == 'Debug'">
<!-- ... important tasks here ... -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
</Target>
When I touch nearly any code file in the solution, NCrunch rebuilds
all of the projects downstream from that change. This task runs before
each of those builds, adding npm install
CPU usage and delay each
time.
There are two ways to fix this:
- Only
npm install
ifnode_modules
is missing - Ignore the
npm install
if I'm running from NCrunch
If you use an ASP.Net template to start your project, you get that first option out of the box. The original Condition looks like this:
Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
However, I'm coding as a member of a small full-stack development team,
which means on any given day I'm merging my changes in with other
changes, switching between branches, rebasing, and so on. Where possible,
I want my tools to magically take care of things for me, so you can see
we removed the !Exists
condition so that when we start debugging
npm just takes care of itself.
Even if you choe to leave that condition, however, it would still slow down NCrunch on initial builds of workspaces.
Luckily, NCrunch provides guidance on NCrunch-Specific Overrides, one of which is an environment variable that it sets for each build.
So we can alter the csproj like so:
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build"
Condition=" '$(Configuration)' == 'Debug' And '$(NCrunch)' != '1'">
<!-- ... important tasks here ... -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
</Target>
And now when NCrunch builds, it skips the npm
step and our CPU stays low
(and we get results faster):
If you're using NCrunch, it's worth scanning your project files for tasks that are pure overhead during an NCrunch run and skipping them.