diff --git a/Blazor.sln b/Blazor.sln
index c942c3baa9..c28a955771 100644
--- a/Blazor.sln
+++ b/Blazor.sln
@@ -32,6 +32,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Blazor.DevHost",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorStandalone", "samples\BlazorStandalone\BlazorStandalone.csproj", "{754BBACA-E05B-4DAE-ACFC-1B3B429AE43F}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Blazor.BuildTools", "src\Microsoft.Blazor.BuildTools\Microsoft.Blazor.BuildTools.csproj", "{BB34336F-E68E-4411-9805-CAAA919F5EA1}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -74,6 +76,10 @@ Global
{754BBACA-E05B-4DAE-ACFC-1B3B429AE43F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{754BBACA-E05B-4DAE-ACFC-1B3B429AE43F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{754BBACA-E05B-4DAE-ACFC-1B3B429AE43F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BB34336F-E68E-4411-9805-CAAA919F5EA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BB34336F-E68E-4411-9805-CAAA919F5EA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BB34336F-E68E-4411-9805-CAAA919F5EA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BB34336F-E68E-4411-9805-CAAA919F5EA1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -89,6 +95,7 @@ Global
{58D2DF2E-4181-4B16-9C69-A3F3EDB89B28} = {B867E038-B3CE-43E3-9292-61568C46CDEB}
{EE690312-2353-4DD0-9250-EE5EDAC6D4F7} = {B867E038-B3CE-43E3-9292-61568C46CDEB}
{754BBACA-E05B-4DAE-ACFC-1B3B429AE43F} = {F5FDD4E5-6A52-4A86-BE5E-5E42CB1DC8DA}
+ {BB34336F-E68E-4411-9805-CAAA919F5EA1} = {B867E038-B3CE-43E3-9292-61568C46CDEB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {504DA352-6788-4DC0-8705-82167E72A4D3}
diff --git a/src/Microsoft.Blazor.Browser/Microsoft.Blazor.Browser.csproj b/src/Microsoft.Blazor.Browser/Microsoft.Blazor.Browser.csproj
index 320d3d14af..50d8c67d62 100644
--- a/src/Microsoft.Blazor.Browser/Microsoft.Blazor.Browser.csproj
+++ b/src/Microsoft.Blazor.Browser/Microsoft.Blazor.Browser.csproj
@@ -15,16 +15,18 @@
+
+
+
+
+
-
-
-
-
+
-
+
diff --git a/src/Microsoft.Blazor.BuildTools/Cli/CheckNodeJsInstalled.cs b/src/Microsoft.Blazor.BuildTools/Cli/CheckNodeJsInstalled.cs
new file mode 100644
index 0000000000..a3c7dc0bcb
--- /dev/null
+++ b/src/Microsoft.Blazor.BuildTools/Cli/CheckNodeJsInstalled.cs
@@ -0,0 +1,93 @@
+using Microsoft.Extensions.CommandLineUtils;
+using System;
+using System.Diagnostics;
+using System.Text.RegularExpressions;
+
+namespace Microsoft.Blazor.BuildTools.Cli
+{
+ class CheckNodeJsInstalled
+ {
+ private static Regex NodeVersionRegex = new Regex(@"^v(\d+\.\d+\.\d+)");
+
+ public static void Command(CommandLineApplication command)
+ {
+ command.Description = "Asserts that Node.js is installed.";
+ command.HelpOption("-?|-h|--help");
+
+ var minVersionOption = command.Option(
+ "-v|--version",
+ "Specifies a minimum acceptable version of Node.js.",
+ CommandOptionType.SingleValue);
+
+ command.OnExecute(() =>
+ {
+ var foundNodeVersion = GetInstalledNodeVersion();
+ if (foundNodeVersion == null)
+ {
+ return 1;
+ }
+
+ if (minVersionOption.HasValue())
+ {
+ var minVersion = new Version(minVersionOption.Value());
+ if (foundNodeVersion < minVersion)
+ {
+ Console.WriteLine($"ERROR: The installed version of Node.js is too old. Required version: {minVersion}; Found version: {foundNodeVersion}.");
+ return 1;
+ }
+ }
+
+ Console.WriteLine($"Found Node.js version {foundNodeVersion}");
+ return 0;
+ });
+ }
+
+ private static Version GetInstalledNodeVersion()
+ {
+ var versionString = InvokeNodeVersionCommand();
+ if (versionString == null)
+ {
+ return null;
+ }
+
+ var versionStringMatch = NodeVersionRegex.Match(versionString);
+ if (!versionStringMatch.Success)
+ {
+ Console.WriteLine($"ERROR: Got unparseable Node.js version string: {versionStringMatch}");
+ return null;
+ }
+
+ return new Version(versionStringMatch.Groups[1].Value);
+ }
+
+ private static string InvokeNodeVersionCommand()
+ {
+ try
+ {
+ var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "node",
+ Arguments = "-v",
+ RedirectStandardOutput = true
+ });
+ process.WaitForExit();
+
+ if (process.ExitCode != 0)
+ {
+ Console.WriteLine($"ERROR: The command 'node -v' exited with code {process.ExitCode}.");
+ return null;
+ }
+ else
+ {
+ return process.StandardOutput.ReadToEnd();
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("ERROR: Node.js was not found. Ensure that Node.js is installed and that 'node' is present on the system PATH.");
+ Console.WriteLine("The underlying error was: " + ex.Message);
+ return null;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Blazor.BuildTools/Microsoft.Blazor.BuildTools.csproj b/src/Microsoft.Blazor.BuildTools/Microsoft.Blazor.BuildTools.csproj
new file mode 100644
index 0000000000..d0d4f56387
--- /dev/null
+++ b/src/Microsoft.Blazor.BuildTools/Microsoft.Blazor.BuildTools.csproj
@@ -0,0 +1,12 @@
+
+
+
+ netcoreapp2.0
+ Exe
+
+
+
+
+
+
+
diff --git a/src/Microsoft.Blazor.BuildTools/Program.cs b/src/Microsoft.Blazor.BuildTools/Program.cs
new file mode 100644
index 0000000000..15f04c04fb
--- /dev/null
+++ b/src/Microsoft.Blazor.BuildTools/Program.cs
@@ -0,0 +1,30 @@
+using Microsoft.Blazor.BuildTools.Cli;
+using Microsoft.Extensions.CommandLineUtils;
+using System;
+
+namespace Microsoft.Blazor.BuildTools
+{
+ static class Program
+ {
+ static int Main(string[] args)
+ {
+ var app = new CommandLineApplication
+ {
+ Name = "blazor-buildtools"
+ };
+ app.HelpOption("-?|-h|--help");
+
+ app.Command("checknodejs", CheckNodeJsInstalled.Command);
+
+ if (args.Length > 0)
+ {
+ return app.Execute(args);
+ }
+ else
+ {
+ app.ShowHelp();
+ return 0;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Blazor.BuildTools/local.props b/src/Microsoft.Blazor.BuildTools/local.props
new file mode 100644
index 0000000000..901679b7a6
--- /dev/null
+++ b/src/Microsoft.Blazor.BuildTools/local.props
@@ -0,0 +1,7 @@
+
+
+
+
+ dotnet run --no-build --project $(MSBuildThisFileDirectory)
+
+