Skip to content

JavaScriptServices does not find ClientApp when run in IISExpress #6342

@ryanbrandenburg

Description

@ryanbrandenburg

Full details here.

TLDR

Because IISExpress has the CurrentDirectory as where IIS is installed (probably "C:\Program Files\IIS Express") the WorkingDirectory for running npm gets expanded to "C:\Program Files\IIS Express\ClientApp", which is a folder that doesn't exist. An exception is thrown, which JavaScriptServices reports as a problem with NPM, and we get an error page that says:

Ensure that 'npm' is installed and can be found in one of the PATH directories.
Current PATH enviroment variable is: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\dotnet\;C:\Program Files\Microsoft SQL Server\130\Tools\Binn\;C:\Program Files\nodejs\;C:\Users\v-jieliu\AppData\Local\Microsoft\WindowsApps;
Make sure the executable is in one of those directories, or update your PATH.

but the real rub is hidden in the InnerException:

System.ComponentModel.Win32Exception: The directory name is invalid.

Issues

I see two issues here:

  1. JavaScriptServices reports any failure in the call to npm as a PATH problem for NPM, when it's reasonably probable (if not more likely) that the real problem is the SourcePath was set to a directory that doesn't exist.
  2. Our Templates SourcePath of "ClientApp" does not work in all circumstances.

Solutions

For 1 I think the obvious resolution is to catch multiple more specific exceptions and do something useful with them. IE, if we get the "directory name is invalid" exception we should tell them that their SourcePath is probably wrong, if the message matches npm not being on the path, give the existing error message, otherwise give a more generic message with the raw exception in there.

For 2 I see three possible solutions.

  1. Change the templates to pass a more complete path to SourcePath. Path.Join(env.ContentRootPath, "ClientApp") did the job locally, but there might be scenarios I didn't consider there.
  2. Make JavaScriptServices set the WorkingDirectory here to a more specific value (possibly Path.Join(env.ContentRootPath, workingDirectory)) if the value is not absolute.
  3. Declare that it is expected that our JS templates don't work without modification in scenarios where the CurrentDirectory of your process does not contain the ClientApp, and document this somewhere (probably in Startup.cs).

I think 3 is the least desirable since I believe IIS Express is the default runner for VS, but if there's not a value we can pass for SourcePath which works in all scenarios it may be the only solution. 2 would be nice because it fixes this scenario for existing projects which update to our newer versions without a code change, but I can see an argument that it's being "too smart", and it is technically a breaking change. 1 keeps JavaScriptServices "pure" at the cost of increased complexity in our Templates, but prevents a breaking change to the behavior of SourcePath.

CC @mkArtakMSFT

Metadata

Metadata

Labels

DoneThis issue has been fixedarea-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templates

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions