private static async Task <int> StartVueDevServerAsync( string sourcePath, string npmScriptName, ILogger logger) { var portNumber = TcpPortFinder.FindAvailablePort(); logger.LogInformation($"Starting Vue dev server on port {portNumber}..."); var npmScriptRunner = new NpmScriptRunner( sourcePath, npmScriptName, $"--port {portNumber} --host localhost", null); npmScriptRunner.AttachToLogger(logger); Match startDevelopmentServerLine; using (var stdErrReader = new EventedStreamStringReader(npmScriptRunner.StdErr)) { try { startDevelopmentServerLine = await npmScriptRunner.StdOut.WaitForMatch( new Regex("DONE", RegexOptions.None, RegexMatchTimeout)); } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The NPM script '{npmScriptName}' exited without indicating that the " + $"vue development server was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } } return(portNumber); }
private static async Task <int> StartCreateVueCliAppServerAsync( string sourcePath, string nodeScriptName, ILogger logger, string packageManager) { var portNumber = TcpPortFinder.FindAvailablePort(); logger.LogInformation($"Starting vue-cli-service server on port {portNumber}..."); string arguments = $"--port {portNumber}"; var envVars = new Dictionary <string, string> { }; var nodeScriptRunner = new NodeScriptRunner(sourcePath, nodeScriptName, arguments, envVars, packageManager); using (var stdErrReader = new EventedStreamStringReader(nodeScriptRunner.StdErr)) { try { // Although the dev server may eventually tell us the URL it's listening on, // it doesn't do so until it's finished compiling, and even then only if there were // no compiler warnings. So instead of waiting for that, consider it ready as soon // as it starts listening for requests. await nodeScriptRunner.StdOut.WaitForMatch(new Regex("App running at:", RegexOptions.None, RegexMatchTimeout)); } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The node script '{nodeScriptName}' exited without indicating that the " + $"node server was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } } return(portNumber); }
private static async Task <(string scheme, int port)> StartServerAsync( IApplicationBuilder appBuilder, string sourcePath, string npmScriptName, string packageManager, ILogger logger) { var scheme = "http"; var portNumber = TcpPortFinder.FindAvailablePort(); logger.LogInformation($"Starting vue-cli-service server on port {portNumber}..."); //var envVars = new Dictionary<string, string> //{ // { "PORT", portNumber.ToString() }, // { "BROWSER", "none" }, // We don't want vue-cli-service to open its own extra browser window pointing to the internal dev server port //}; var diagnosticSource = appBuilder.ApplicationServices.GetRequiredService <DiagnosticSource>(); #if NETCOREAPP2_1 || NETCOREAPP2_2 var applicationStoppingToken = appBuilder.ApplicationServices.GetRequiredService <IApplicationLifetime>().ApplicationStopping; #else var applicationStoppingToken = appBuilder.ApplicationServices.GetRequiredService <IHostApplicationLifetime>().ApplicationStopping; #endif var npmScriptRunner = new NodeScriptRunner( sourcePath, npmScriptName, $"--port {portNumber}", null, packageManager, diagnosticSource, applicationStoppingToken); npmScriptRunner.AttachToLogger(logger); using (var stdErrReader = new EventedStreamStringReader(npmScriptRunner.StdErr)) { try { // Although the dev server may eventually tell us the URL it's listening on, // it doesn't do so until it's finished compiling, and even then only if there were // no compiler warnings. So instead of waiting for that, consider it ready as soon // as it starts listening for requests. await npmScriptRunner.StdOut.WaitForMatch( new Regex("App running at", RegexOptions.None, RegexMatchTimeout)); string nextLine = await npmScriptRunner.StdOut.ReadLine(); if (nextLine.Contains("https://")) { scheme = "https"; } } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The {packageManager} script '{npmScriptName}' exited without indicating that the " + $"vue-cli-service server was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } } return(scheme, portNumber); }
private static async Task <int> StartVueDevServerAsync( IApplicationBuilder appBuilder, string sourcePath, string npmScriptName, ILogger logger) { var portNumber = TcpPortFinder.FindAvailablePort(); logger.LogInformation($"Starting Vue dev server on port {portNumber}..."); // Inject address of .NET app as the ASPNET_URL env variable and read it in vue.config.js from process.env // as opposed to hardcoding https://localhost:5001 as the address of the dotnet web server // NOTE: When running with IISExpress this will be empty, so you will need to hardcode the URL in IISExpress as a fallbacl // when ASPNET_URL is empty var addresses = appBuilder.ServerFeatures.Get <IServerAddressesFeature>().Addresses; var envVars = new Dictionary <string, string> { { "ASPNET_URL", addresses.Count > 0 ? addresses.First() : "" }, }; var npmScriptRunner = new NpmScriptRunner( sourcePath, npmScriptName, $"--port {portNumber} --host localhost", envVars); npmScriptRunner.AttachToLogger(logger); Match startDevelopmentServerLine; using (var stdErrReader = new EventedStreamStringReader(npmScriptRunner.StdErr)) { try { // Although the Vue dev server may eventually tell us the URL it's listening on, // it doesn't do so until it's finished compiling, and even then only if there were // no compiler warnings. So instead of waiting for that, consider it ready as soon // as it starts listening for requests. //startDevelopmentServerLine = await npmScriptRunner.StdOut.WaitForMatch( // new Regex(" - Local: (http\\S+)", RegexOptions.None, RegexMatchTimeout)); startDevelopmentServerLine = await npmScriptRunner.StdOut.WaitForMatch( new Regex("DONE", RegexOptions.None, RegexMatchTimeout)); logger.LogInformation($"Vue dev server ready at http://localhost:{portNumber}"); } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The NPM script '{npmScriptName}' exited without indicating that the " + $"vue development server was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } } return(portNumber); }
private static async Task <AngularCliServerInfo> StartAngularCliServerAsync( string sourcePath, string npmScriptName, ILogger logger) { var portNumber = TcpPortFinder.FindAvailablePort(); logger.LogInformation($"Starting @angular/cli on port {portNumber}..."); var npmScriptRunner = new NpmScriptRunner( sourcePath, npmScriptName, $"--port {portNumber}", null); npmScriptRunner.AttachToLogger(logger); Match openBrowserLine; using (var stdErrReader = new EventedStreamStringReader(npmScriptRunner.StdErr)) { try { openBrowserLine = await npmScriptRunner.StdOut.WaitForMatch( new Regex("open your browser on (http\\S+)", RegexOptions.None, RegexMatchTimeout), StartupTimeout); } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The NPM script '{npmScriptName}' exited without indicating that the " + $"Angular CLI was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } catch (TaskCanceledException ex) { throw new InvalidOperationException( $"The Angular CLI process did not start listening for requests " + $"within the timeout period of {StartupTimeout.Seconds} seconds. " + $"Check the log output for error information.", ex); } } var uri = new Uri(openBrowserLine.Groups[1].Value); var serverInfo = new AngularCliServerInfo { Port = uri.Port }; // Even after the Angular CLI claims to be listening for requests, there's a short // period where it will give an error if you make a request too quickly await WaitForAngularCliServerToAcceptRequests(uri); return(serverInfo); }
private static async Task <int> StartCreateReactAppServerAsync( string sourcePath, string npmScriptName, ILogger logger) { var portNumber = TcpPortFinder.FindAvailablePort(); logger.LogInformation($"Starting create-react-app server on port {portNumber}..."); var envVars = new Dictionary <string, string> { { "PORT", portNumber.ToString() }, { "BROWSER", "none" }, // We don't want create-react-app to open its own extra browser window pointing to the internal dev server port }; var npmScriptRunner = new NpmScriptRunner( sourcePath, npmScriptName, null, envVars); npmScriptRunner.AttachToLogger(logger); using (var stdErrReader = new EventedStreamStringReader(npmScriptRunner.StdErr)) { try { // Although the React dev server may eventually tell us the URL it's listening on, // it doesn't do so until it's finished compiling, and even then only if there were // no compiler warnings. So instead of waiting for that, consider it ready as soon // as it starts listening for requests. await npmScriptRunner.StdOut.WaitForMatch( new Regex("Starting the development server", RegexOptions.None, RegexMatchTimeout), StartupTimeout); } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The NPM script '{npmScriptName}' exited without indicating that the " + $"create-react-app server was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } catch (TaskCanceledException ex) { throw new InvalidOperationException( $"The create-react-app server did not start listening for requests " + $"within the timeout period of {StartupTimeout.Seconds} seconds. " + $"Check the log output for error information.", ex); } } return(portNumber); }
private static async Task <int> StartWebpackDevServerAsync( string sourcePath, string npmScriptName, ILogger logger, int socketPortNumber) { var portNumber = TcpPortFinder.FindAvailablePort(); logger.LogInformation($"Starting webpack-dev-server on port {portNumber}..."); // Use option "--stdin" so nodejs process with webpack-dev-server stops when the webapp stops: // https://webpack.js.org/configuration/dev-server/#devserverstdin---cli-only var arguments = $"--port {portNumber} --sockPort {socketPortNumber} --stdin"; var envVars = new Dictionary <string, string> { }; var npmScriptRunner = new NpmScriptRunner( sourcePath, npmScriptName, arguments, envVars); npmScriptRunner.AttachToLogger(logger); using (var stdErrReader = new EventedStreamStringReader(npmScriptRunner.StdErr)) { try { // Although the webpack-dev-server may eventually tell us the URL it's listening on, // it doesn't do so until it's finished compiling, and even then only if there were // no compiler warnings. So instead of waiting for that, consider it ready as soon // as it starts listening for requests. #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task await npmScriptRunner.StdOut.WaitForMatch( new Regex("Project is running at", RegexOptions.None, RegexMatchTimeout)); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The NPM script '{npmScriptName}' exited without indicating that the " + $"webpack-development server was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } } return(portNumber); }
private static async Task <AngularCliServerInfo> StartAngularCliServerAsync( string sourcePath, string scriptName, string pkgManagerCommand, int portNumber, ILogger logger) { if (portNumber == default(int)) { portNumber = TcpPortFinder.FindAvailablePort(); } logger.LogInformation($"Starting @angular/cli on port {portNumber}..."); var scriptRunner = new NodeScriptRunner( sourcePath, scriptName, $"--port {portNumber}", null, pkgManagerCommand); scriptRunner.AttachToLogger(logger); Match openBrowserLine; using (var stdErrReader = new EventedStreamStringReader(scriptRunner.StdErr)) { try { openBrowserLine = await scriptRunner.StdOut.WaitForMatch( new Regex("open your browser on (http\\S+)", RegexOptions.None, RegexMatchTimeout)); } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The {pkgManagerCommand} script '{scriptName}' exited without indicating that the " + $"Angular CLI was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } } var uri = new Uri(openBrowserLine.Groups[1].Value); var serverInfo = new AngularCliServerInfo { Port = uri.Port }; // Even after the Angular CLI claims to be listening for requests, there's a short // period where it will give an error if you make a request too quickly await WaitForAngularCliServerToAcceptRequests(uri); return(serverInfo); }
private static async Task <int> StartCreateVueAppServerAsync( string sourcePath, string scriptName, string pkgManagerCommand, int portNumber, ILogger logger, DiagnosticSource diagnosticSource, CancellationToken applicationStoppingToken) { if (portNumber == default) { portNumber = TcpPortFinder.FindAvailablePort(); } logger.LogInformation($"Starting vue-cli server on port {portNumber}..."); var envVars = new Dictionary <string, string> { { "PORT", portNumber.ToString() }, { "BROWSER", "none" }, // We don't want vue-cli to open its own extra browser window pointing to the internal dev server port }; var scriptRunner = new NodeScriptRunner( sourcePath, scriptName, null, envVars, pkgManagerCommand, diagnosticSource, applicationStoppingToken); scriptRunner.AttachToLogger(logger); using (var stdErrReader = new EventedStreamStringReader(scriptRunner.StdErr)) { try { // Although the Vue dev server may eventually tell us the URL it's listening on, // it doesn't do so until it's finished compiling, and even then only if there were // no compiler warnings. So instead of waiting for that, consider it ready as soon // as it starts listening for requests. await scriptRunner.StdOut.WaitForMatch( new Regex(CLI_SERVE_COMPLETION_REGEX, RegexOptions.None, RegexMatchTimeout)); } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The {pkgManagerCommand} script '{scriptName}' exited without indicating that the " + $"vue-cli server was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } } return(portNumber); }
private static async Task <AureliaCliServerInfo> StartAureliaCliServerAsync( string sourcePath, string npmScriptName, ILogger logger) { var portNumber = TcpPortFinder.FindAvailablePort(); logger.LogInformation($"Starting aurelia-cli on port {portNumber}..."); var npmScriptRunner = new NpmScriptRunner( sourcePath, npmScriptName, $" --port {portNumber}", null); npmScriptRunner.AttachToLogger(logger); Match openBrowserLine; using (var stdErrReader = new EventedStreamStringReader(npmScriptRunner.StdErr)) { try { openBrowserLine = await npmScriptRunner.StdOut.WaitForMatch( new Regex(".*Compiled.*successfully.*", RegexOptions.None, RegexMatchTimeout)) .ConfigureAwait(false); } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The NPM script '{npmScriptName}' exited without indicating that the " + $"Aurelia CLI was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } } var uri = new Uri($"http://localhost:{portNumber}");//openBrowserLine.Groups[1].Value); var serverInfo = new AureliaCliServerInfo { Port = uri.Port }; // Even after the Aurelia CLI claims to be listening for requests, there's a short // period where it will give an error if you make a request too quickly await WaitForAureliaCliServerToAcceptRequests(uri).ConfigureAwait(false); return(serverInfo); }
private static async Task <VueCliServerInfo> StartVueCliServerAsync( string sourcePath, string npmScriptName, ILogger logger) { var portNumber = TcpPortFinder.FindAvailablePort(); logger.LogInformation($"Starting @Vue/cli on port {portNumber}..."); var npmScriptRunner = new NpmScriptRunner( sourcePath, npmScriptName, $"--port {portNumber}", null); npmScriptRunner.AttachToLogger(logger); Match openBrowserLine; using (var stdErrReader = new EventedStreamStringReader(npmScriptRunner.StdErr)) { try { openBrowserLine = await npmScriptRunner.StdOut.WaitForMatch( new Regex(" - Local: (http\\S+)", RegexOptions.None, RegexMatchTimeout)); } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The NPM script '{npmScriptName}' exited without indicating that the " + $"Vue CLI was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } } var uri = new Uri(openBrowserLine.Groups[1].Value); var serverInfo = new VueCliServerInfo { Port = uri.Port, Host = uri.Host, Scheme = uri.Scheme }; // Even after the Vue CLI claims to be listening for requests, there may be a short // period where it will give an error if you make a request too quickly await WaitForVueCliServerToAcceptRequests(uri); return(serverInfo); }
private static async Task <CliServerInfo> StartBlazorWasmCliServerAsync(string sourcePath, string startScript, ILogger logger) { var portNumber = TcpPortFinder.FindAvailablePort(); logger.LogInformation($"Starting Blazor Wasm Cli on port {portNumber}..."); var scriptRunner = new DotnetScriptRunner( sourcePath, startScript, $"--urls=\"http://localhost:{portNumber}\"", null); scriptRunner.AttachToLogger(logger); Match openBrowserLine; using (var stdErrReader = new EventedStreamStringReader(scriptRunner.StdErr)) { try { openBrowserLine = await scriptRunner.StdOut.WaitForMatch(new Regex("Now listening on: (http\\S+)", RegexOptions.None, RegexMatchTimeout)); } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The NPM script '{startScript}' exited without indicating that the " + $"Angular CLI was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } } var uri = new Uri(openBrowserLine.Groups[1].Value); var serverInfo = new CliServerInfo { Port = uri.Port, PublicPath = uri.AbsolutePath.TrimEnd('/') }; // Even after the Angular CLI claims to be listening for requests, there's a short // period where it will give an error if you make a request too quickly await WaitForCliServerToAcceptRequests(uri); return(serverInfo); }
private static async Task <int> StartVueCliServerAsync( string sourcePath, string npmScriptName, ILogger logger, int portNumber) { if (portNumber < 80) { portNumber = TcpPortFinder.FindAvailablePort(); } logger.LogInformation($"Starting server on port {portNumber}..."); var envVars = new Dictionary <string, string> { { "PORT", portNumber.ToString() }, { "DEV_SERVER_PORT", portNumber.ToString() }, // vue cli 3 uses --port {number}, included below { "BROWSER", "none" }, // We don't want vue-cli to open its own extra browser window pointing to the internal dev server port }; var npmScriptRunner = new NpmScriptRunner(sourcePath, npmScriptName, $"--port {portNumber}", envVars); npmScriptRunner.AttachToLogger(logger); using (var stdErrReader = new EventedStreamStringReader(npmScriptRunner.StdErr)) { try { // Although the Vue dev server may eventually tell us the URL it's listening on, // it doesn't do so until it's finished compiling, and even then only if there were // no compiler warnings. So instead of waiting for that, consider it ready as soon // as it starts listening for requests. await npmScriptRunner.StdOut.WaitForMatch( new Regex("running at", RegexOptions.None, RegexMatchTimeout)); } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The NPM script '{npmScriptName}' exited without indicating that the " + $"server was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } } return(portNumber); }
private static async Task <int> StartCreateVueAppServerAsync( string sourcePath, string npmExe, string npmScriptName, ILogger logger) { var portNumber = TcpPortFinder.FindAvailablePort(); logger.LogInformation($"Starting create-vue-app server on port {portNumber}..."); var envVars = new Dictionary <string, string> { { "PORT", portNumber.ToString() }, { "BROWSER", "none" }, // We don't want create-vue-app to open its own extra browser window pointing to the internal dev server port }; //var arguments = $"--port={portNumber}"; var npmScriptRunner = new NpmScriptRunner( sourcePath, npmExe, npmScriptName, null, envVars); npmScriptRunner.AttachToLogger(logger); using (var stdErrReader = new EventedStreamStringReader(npmScriptRunner.StdErr)) { try { // 尽管vue dev服务器最终可能会告诉我们它监听的URL, // 在编译完成之前,它不会这样做,即使在没有编译器警告的情况下也不会这样做。 // 所以与其等着,还不如在它开始倾听请求时尽快准备好。 await npmScriptRunner.StdOut.WaitForMatch( new Regex("App running at", RegexOptions.None, RegexMatchTimeout)); } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The NPM script '{npmScriptName}' exited without indicating that the " + $"create-vue-app server was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } } return(portNumber); }
private static async Task <int> StartVueDevServerAsync( string sourcePath, string npmScriptName, ILogger logger) { var portNumber = TcpPortFinder.FindAvailablePort(); logger.LogInformation($"Starting Vue dev server on port {portNumber}..."); var npmScriptRunner = new NpmScriptRunner( sourcePath, npmScriptName, $"--port {portNumber} --host localhost", null); npmScriptRunner.AttachToLogger(logger); Match startDevelopmentServerLine; using (var stdErrReader = new EventedStreamStringReader(npmScriptRunner.StdErr)) { try { // Although the Vue dev server may eventually tell us the URL it's listening on, // it doesn't do so until it's finished compiling, and even then only if there were // no compiler warnings. So instead of waiting for that, consider it ready as soon // as it starts listening for requests. //startDevelopmentServerLine = await npmScriptRunner.StdOut.WaitForMatch( // new Regex(" - Local: (http\\S+)", RegexOptions.None, RegexMatchTimeout)); startDevelopmentServerLine = await npmScriptRunner.StdOut.WaitForMatch( new Regex("DONE", RegexOptions.None, RegexMatchTimeout)); } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The NPM script '{npmScriptName}' exited without indicating that the " + $"vue development server was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } } return(portNumber); }
private static async Task <VueCliServerInfo> StartVueCliServerAsync( string sourcePath, string npmScriptName, ILogger logger) { var portNumber = 8080;//default port for vue cli: 8080 if (portNumber < 80) { portNumber = TcpPortFinder.FindAvailablePort(); } else { // if the port we want to use is occupied, terminate the process utilizing that port. // this occurs when "stop" is used from the debugger and the middleware does not have the opportunity to kill the process PidUtils.KillPort((ushort)portNumber); } logger.LogInformation($"Starting @Vue/cli on port {portNumber}..."); var envVars = new Dictionary <string, string> { { "PORT", portNumber.ToString() }, { "DEV_SERVER_PORT", portNumber.ToString() }, // vue cli 3 uses --port {number}, included below { "BROWSER", "none" }, // We don't want vue-cli to open its own extra browser window pointing to the internal dev server port }; var npmScriptRunner = new NpmScriptRunner( sourcePath, npmScriptName, $"--port {portNumber}", envVars); AppDomain.CurrentDomain.DomainUnload += (s, e) => npmScriptRunner?.Kill(); AppDomain.CurrentDomain.ProcessExit += (s, e) => npmScriptRunner?.Kill(); AppDomain.CurrentDomain.UnhandledException += (s, e) => npmScriptRunner?.Kill(); npmScriptRunner.AttachToLogger(logger); Match openBrowserLine; using (var stdErrReader = new EventedStreamStringReader(npmScriptRunner.StdErr)) { try { openBrowserLine = await npmScriptRunner.StdOut.WaitForMatch( new Regex(" - Local: (http\\S+)", RegexOptions.None, RegexMatchTimeout)); } catch (EndOfStreamException ex) { throw new InvalidOperationException( $"The NPM script '{npmScriptName}' exited without indicating that the " + $"Vue CLI was listening for requests. The error output was: " + $"{stdErrReader.ReadAsString()}", ex); } } var uri = new Uri(openBrowserLine.Groups[1].Value); var serverInfo = new VueCliServerInfo { Port = uri.Port, Host = uri.Host, Scheme = uri.Scheme }; // Even after the Vue CLI claims to be listening for requests, there may be a short // period where it will give an error if you make a request too quickly await WaitForVueCliServerToAcceptRequests(uri); return(serverInfo); }