public static void UseVueDevelopmentServer(this ISpaBuilder spa) { spa.UseProxyToSpaDevelopmentServer(async() => { var loggerFactory = spa.ApplicationBuilder.ApplicationServices.GetService <ILoggerFactory> (); var logger = loggerFactory.CreateLogger("Vue"); if (IsRunning()) { return(DevelopmentServerEndpoint); } var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); var processInfo = new ProcessStartInfo { FileName = isWindows ? "cmd" : "npm", Arguments = $"{(isWindows ? "/c npm " : "")}run serve", WorkingDirectory = "client-app", RedirectStandardError = true, RedirectStandardInput = true, RedirectStandardOutput = true, UseShellExecute = false, }; var process = Process.Start(processInfo); var tcs = new TaskCompletionSource <int> (); _ = Task.Run(() => { try { string line; while ((line = process.StandardOutput.ReadLine()) != null) { logger.LogInformation(line); if (!tcs.Task.IsCompleted && line.Contains(DoneMessage)) { tcs.SetResult(1); } } } catch (EndOfStreamException ex) { logger.LogError(ex.ToString()); tcs.SetException(new InvalidOperationException("'npm run serve' failed.", ex)); } }); _ = Task.Run(() => { try { string line; while ((line = process.StandardError.ReadLine()) != null) { logger.LogError(line); } } catch (EndOfStreamException ex) { logger.LogError(ex.ToString()); tcs.SetException(new InvalidOperationException("'npm run serve' failed.", ex)); } }); var timeout = Task.Delay(Timeout); if (await Task.WhenAny(timeout, tcs.Task) == timeout) { throw new TimeoutException(); } return(DevelopmentServerEndpoint); }); }
public static void Attach( ISpaBuilder spaBuilder, string npmScriptName, string compiledSuccessfullyString) { var sourcePath = spaBuilder.Options.SourcePath; if (string.IsNullOrEmpty(sourcePath)) { throw new ArgumentNullException(nameof(sourcePath)); } if (string.IsNullOrEmpty(npmScriptName)) { throw new ArgumentNullException(nameof(npmScriptName)); } CompiledSuccessfullyString = compiledSuccessfullyString; var logger = LoggerFinder.GetOrCreateLogger(spaBuilder.ApplicationBuilder, LogCategoryName); var targetUriTask = StartCreateVueAppServerAsync(sourcePath, npmScriptName, logger) .ContinueWith(task => new UriBuilder("http", "127.0.0.1", task.Result).Uri); spaBuilder.UseProxyToSpaDevelopmentServer(() => { var startupTimeout = spaBuilder.Options.StartupTimeout; return(targetUriTask.WithTimeout(startupTimeout, $"在 {startupTimeout.Seconds} 秒钟的超时时间内,Vue服务器未开始侦听请求。 检查日志输出以获取错误信息")); }); }
public static void UseVueDevelopmentServer(this ISpaBuilder spa, string scriptName) { spa.UseProxyToSpaDevelopmentServer(async() => { var nodeRunner = new NodeProccessRunner(scriptName); return(await nodeRunner.LaunchProccess()); }); }
public static void UseVueDevelopmentServer(this ISpaBuilder spa) { spa.UseProxyToSpaDevelopmentServer(async() => { if (IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners().Select(x => x.Port).Contains(DEV_PORT)) { return(new Uri($"http://localhost:{DEV_PORT}")); } throw new InvalidOperationException($"Please serve the port {DEV_PORT}"); }); }
TimeSpan.FromSeconds(5); // This is a development-time only feature, so a very long timeout is fine public static void Attach( ISpaBuilder spaBuilder, string npmScriptName) { var sourcePath = spaBuilder.Options.SourcePath; if (string.IsNullOrEmpty(sourcePath)) { throw new ArgumentException("Cannot be null or empty", nameof(sourcePath)); } if (string.IsNullOrEmpty(npmScriptName)) { throw new ArgumentException("Cannot be null or empty", nameof(npmScriptName)); } // Start create-react-app and attach to middleware pipeline var appBuilder = spaBuilder.ApplicationBuilder; var logger = LoggerFinder.GetOrCreateLogger(appBuilder, LogCategoryName); var portTask = StartCreateVueAppServerAsync(sourcePath, npmScriptName, logger); // Everything we proxy is hardcoded to target http://localhost because: // - the requests are always from the local machine (we're not accepting remote // requests that go directly to the create-react-app server) // - given that, there's no reason to use https, and we couldn't even if we // wanted to, because in general the create-react-app server has no certificate var targetUriTask = portTask.ContinueWith( task => new UriBuilder("http", "localhost", task.Result).Uri ); spaBuilder.UseProxyToSpaDevelopmentServer( () => { // On each request, we create a separate startup task with its own timeout. That way, even if // the first request times out, subsequent requests could still work. var timeout = spaBuilder.Options.StartupTimeout; return(targetUriTask.WithTimeout( timeout, "The Vue development server did not start listening for requests " + $"within the timeout period of {timeout.Seconds} seconds. " + "Check the log output for error information." )); } ); }
public static ISpaBuilder CheckAndStartAngular(this ISpaBuilder spa, string url = "http://localhost:4200/") { try { using (HttpClient client = new HttpClient()) { var response = client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead).Result; spa.UseProxyToSpaDevelopmentServer(url); } } catch (Exception) { spa.UseAngularCliServer(npmScript: "start"); } return(spa); }
public static void Attach(ISpaBuilder spaBuilder) { string sourcePath = spaBuilder.Options.SourcePath; if (string.IsNullOrEmpty(sourcePath)) { throw new ArgumentException("Cannot be null or empty", "sourcePath"); } ILogger logger = spaBuilder.ApplicationBuilder.ApplicationServices.GetService <ILogger <AngularCliServerInfo> >(); Task <Uri> targetUriTask = AngularCliMiddleware.StartAngularCliServerAsync(sourcePath, logger).ContinueWith <Uri>((Func <Task <AngularCliMiddleware.AngularCliServerInfo>, Uri>)(task => new UriBuilder("http", "localhost", task.Result.Port).Uri)); spaBuilder.UseProxyToSpaDevelopmentServer((Func <Task <Uri> >)(() => { TimeSpan startupTimeout = spaBuilder.Options.StartupTimeout; return(targetUriTask.WithTimeout <Uri>(startupTimeout, "The Angular CLI process did not start listening for requests " + string.Format("within the timeout period of {0} seconds. ", (object)startupTimeout.Seconds) + "Check the log output for error information.")); })); }
private static readonly TimeSpan RegexMatchTimeout = TimeSpan.FromSeconds(5); // This is a development-time only feature, so a very long timeout is fine public static void Attach(ISpaBuilder spaBuilder, string scriptName) { var pkgManagerCommand = spaBuilder.Options.PackageManagerCommand; var sourcePath = spaBuilder.Options.SourcePath; var devServerPort = spaBuilder.Options.DevServerPort; if (string.IsNullOrEmpty(sourcePath)) { throw new ArgumentException("Cannot be null or empty", nameof(sourcePath)); } if (string.IsNullOrEmpty(scriptName)) { throw new ArgumentException("Cannot be null or empty", nameof(scriptName)); } // Start vue-cli-service serve and attach to middleware pipeline var appBuilder = spaBuilder.ApplicationBuilder; var applicationStoppingToken = appBuilder.ApplicationServices.GetRequiredService <IHostApplicationLifetime>().ApplicationStopping; var logger = LoggerFinder.GetOrCreateLogger(appBuilder, LOG_CATEGORY_NAME); var diagnosticSource = appBuilder.ApplicationServices.GetRequiredService <DiagnosticSource>(); var portTask = StartCreateVueAppServerAsync(sourcePath, scriptName, pkgManagerCommand, devServerPort, logger, diagnosticSource, applicationStoppingToken); // Everything we proxy is hardcoded to target http://localhost because: // - the requests are always from the local machine (we're not accepting remote // requests that go directly to the vue-cli-service server) // - given that, there's no reason to use https, and we couldn't even if we // wanted to, because in general the vue-cli-service server has no certificate var targetUriTask = portTask.ContinueWith( task => new UriBuilder("http", "localhost", task.Result).Uri); spaBuilder.UseProxyToSpaDevelopmentServer(() => { // On each request, we create a separate startup task with its own timeout. That way, even if // the first request times out, subsequent requests could still work. var timeout = spaBuilder.Options.StartupTimeout; return(targetUriTask.WithTimeout(timeout, $"The vue-cli server did not start listening for requests " + $"within the timeout period of {timeout.Seconds} seconds. " + $"Check the log output for error information.")); }); }
/// <summary> /// Handles requests by passing them through to an instance of the node dev server. /// This means you don't need to start node dev server manually. /// /// </summary> /// <param name="spaBuilder">The <see cref="ApplicationBuilder"/>.</param> /// <param name="command">The command or file name to start dev server.</param> /// <param name="arguments">Arguments to start dev server.</param> /// <param name="workingDirectory">WorkingDirectory for node dev server</param> /// <param name="envVars">Environment variables for node dev server</param> /// <param name="timeout">Timeout for node process waiting</param> /// <param name="timeoutExceedMessage">Message when timeout is exceeded</param> /// <param name="logInformation">Log node process output</param> /// <param name="logError">Log node js process error</param> /// <param name="unsubscribeWhenReady">Stop logging when nodejs process is ready</param> public static void UseAspSpaDevelopmentServer( this ISpaBuilder spaBuilder, string command, string arguments, string workingDirectory, Dictionary<string,string> envVars, TimeSpan timeout, string timeoutExceedMessage = "Timeout has been exceeded ", bool logInformation = true, bool logError = false, bool unsubscribeWhenReady = true) { if (spaBuilder == null) { throw new ArgumentNullException(nameof(spaBuilder)); } var logger = GetOrCreateLogger(spaBuilder.ApplicationBuilder, LogCategoryName); NodeRunner runner = GetNodeRunner(spaBuilder.ApplicationBuilder); if (runner == null) { runner = new NodeRunner(); } runner.Command = command; runner.Arguments = arguments; runner.WorkingDirectory = workingDirectory; runner.EnvVars = envVars; runner.Timeout = timeout; runner.TimeoutExceedMessage = timeoutExceedMessage; runner.Launch(logger); if (runner.Uri != null) { if (unsubscribeWhenReady) { runner.UnsubscribeLog(logger); } spaBuilder.UseProxyToSpaDevelopmentServer(runner.Uri); } else { } }
public static void UseVueDevelopmentServer(this ISpaBuilder spaBuilder) { spaBuilder.UseProxyToSpaDevelopmentServer(async() => { if (IsRunning()) { return(DevelopmentServerEndpoint); } _ = getRunnedTaskOutput(getProcess(), getLogger(spaBuilder), taskCompletionSource); _ = getRunnedTaskError(getProcess(), getLogger(spaBuilder), taskCompletionSource); if (await Task.WhenAny(Task.Delay(Timeout), taskCompletionSource.Task) == Task.Delay(Timeout)) { throw new TimeoutException(); } return(DevelopmentServerEndpoint); }); }
public static void UseVueDevelopmentServer(this ISpaBuilder spa, string url) { URI = new Uri(url); spa.UseProxyToSpaDevelopmentServer(async() => { var loggerFactory = spa.ApplicationBuilder.ApplicationServices.GetService <ILoggerFactory>(); var logger = loggerFactory.CreateLogger("Vue"); // if 'npm run serve' command was executed yourself, then just return the endpoint. if (IsRunning()) { return(URI); } // launch vue.js development server var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); var processInfo = new ProcessStartInfo { FileName = isWindows ? "cmd" : "npm", Arguments = $"{(isWindows ? "/c npm " : "")} run serve", WorkingDirectory = "Resources", RedirectStandardError = true, RedirectStandardInput = true, RedirectStandardOutput = true, UseShellExecute = false, }; var process = Process.Start(processInfo); var tcs = new TaskCompletionSource <int>(); _ = Task.Run(() => { try { string line; while ((line = process.StandardOutput.ReadLine()) != null) { logger.LogInformation(line); if (!tcs.Task.IsCompleted && line.Contains("DONE Compiled successfully in")) { tcs.SetResult(1); } } } catch (EndOfStreamException ex) { logger.LogError(ex.ToString()); tcs.SetException(new InvalidOperationException("'npm run serve' failed.", ex)); } }); _ = Task.Run(() => { try { string line; while ((line = process.StandardError.ReadLine()) != null) { logger.LogError(line); } } catch (EndOfStreamException ex) { logger.LogError(ex.ToString()); tcs.SetException(new InvalidOperationException("'npm run' failed.", ex)); } }); await Task.Delay(10); return(URI); }); }
/// <summary> /// Adds Connection to Vite Hosted VueApplication /// configured per <seealso cref="SpaOptions"/> on the <paramref name="spa"/>. /// NOTE: (this will create devcert.pfx and vite.config.js in your Vue Application on first run) /// </summary> /// <param name="spa"></param> public static void UseViteDevelopmentServer(this ISpaBuilder spa) { // Default HostingPort if (spa.Options.DevServerPort == 0) { spa.Options.DevServerPort = 3000; } var devServerEndpoint = new Uri($"https://localhost:{spa.Options.DevServerPort}"); var loggerFactory = spa.ApplicationBuilder.ApplicationServices.GetService <ILoggerFactory>(); var webHostEnvironment = spa.ApplicationBuilder.ApplicationServices.GetService <IWebHostEnvironment>(); var logger = loggerFactory.CreateLogger("Vue"); // Is this already running bool IsRunning = IPGlobalProperties.GetIPGlobalProperties() .GetActiveTcpListeners() .Select(x => x.Port) .Contains(spa.Options.DevServerPort); if (!IsRunning) { var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); // export dev cert var tempDir = webHostEnvironment.ContentRootPath; var tempPfx = Path.Combine(tempDir, spa.Options.SourcePath, "devcert.pfx"); var tempConfig = Path.Combine(tempDir, spa.Options.SourcePath, "vite.config.js"); if (!File.Exists(tempPfx) || !File.Exists(tempConfig)) { var pfxPassword = Guid.NewGuid().ToString("N"); logger.LogInformation($"Exporting dotnet dev cert to {tempPfx} for Vite"); logger.LogDebug($"Export password: {pfxPassword}"); var certExport = new ProcessStartInfo { FileName = isWindows ? "cmd" : "dotnet", Arguments = $"{(isWindows ? "/c dotnet " : "")}dev-certs https -v -ep {tempPfx} -p {pfxPassword}", RedirectStandardError = true, RedirectStandardInput = true, RedirectStandardOutput = true, UseShellExecute = false, }; var exportProcess = Process.Start(certExport); exportProcess.WaitForExit(); if (exportProcess.ExitCode == 0) { logger.LogInformation(exportProcess.StandardOutput.ReadToEnd()); } else { logger.LogError(exportProcess.StandardError.ReadToEnd()); } // create config File.WriteAllText(tempConfig, $"export default {{\r\nhttps:true,\r\nhttpsOptions: {{\r\npfx: '{Path.GetFileName(tempPfx)}',\r\npassphrase: '{pfxPassword}'\r\n}}\r\n}}"); logger.LogInformation($"Creating Vite config: {tempConfig}"); } // launch vue.js development server var processInfo = new ProcessStartInfo { FileName = isWindows ? "cmd" : "npm", Arguments = $"{(isWindows ? "/c npm " : "")}run dev", WorkingDirectory = spa.Options.SourcePath, RedirectStandardError = true, RedirectStandardInput = true, RedirectStandardOutput = true, UseShellExecute = false, }; var process = Process.Start(processInfo); var tcs = new TaskCompletionSource <int>(); _ = Task.Run(() => { try { string line; while ((line = process.StandardOutput.ReadLine()?.Trim()) != null) { if (!String.IsNullOrEmpty(line)) { logger.LogInformation(line); if (!tcs.Task.IsCompleted && line.Contains(DoneMessage)) { tcs.SetResult(1); } } } } catch (EndOfStreamException ex) { logger.LogError(ex.ToString()); tcs.SetException(new InvalidOperationException("'npm run dev' failed.", ex)); } }); _ = Task.Run(() => { try { string line; while ((line = process.StandardError.ReadLine()?.Trim()) != null) { logger.LogError(line); } } catch (EndOfStreamException ex) { logger.LogError(ex.ToString()); tcs.SetException(new InvalidOperationException("'npm run dev' failed.", ex)); } }); if (!tcs.Task.Wait(spa.Options.StartupTimeout)) { throw new TimeoutException(); } } spa.UseProxyToSpaDevelopmentServer(devServerEndpoint); }