-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Description
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:
- 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. - 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.
- 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. - Make JavaScriptServices set the WorkingDirectory here to a more specific value (possibly
Path.Join(env.ContentRootPath, workingDirectory)
) if the value is not absolute. - 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