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);
        }
示例#3
0
        /// <inheritdoc />
        public async Task Build(ISpaBuilder spaBuilder)
        {
            var pkgManagerCommand = spaBuilder.Options.PackageManagerCommand;
            var sourcePath        = spaBuilder.Options.SourcePath;

            if (string.IsNullOrEmpty(sourcePath))
            {
                throw new InvalidOperationException($"To use {nameof(AngularCliBuilder)}, you must supply a non-empty value for the {nameof(SpaOptions.SourcePath)} property of {nameof(SpaOptions)} when calling {nameof(SpaApplicationBuilderExtensions.UseSpa)}.");
            }

            var appBuilder = spaBuilder.ApplicationBuilder;
            var applicationStoppingToken = appBuilder.ApplicationServices.GetRequiredService <IHostApplicationLifetime>().ApplicationStopping;
            var logger = LoggerFinder.GetOrCreateLogger(
                appBuilder,
                nameof(AngularCliBuilder));
            var diagnosticSource = appBuilder.ApplicationServices.GetRequiredService <DiagnosticSource>();
            var scriptRunner     = new NodeScriptRunner(
                sourcePath,
                _scriptName,
                "--watch",
                null,
                pkgManagerCommand,
                diagnosticSource,
                applicationStoppingToken);

            scriptRunner.AttachToLogger(logger);

            using (var stdOutReader = new EventedStreamStringReader(scriptRunner.StdOut))
                using (var stdErrReader = new EventedStreamStringReader(scriptRunner.StdErr))
                {
                    try
                    {
                        await scriptRunner.StdOut.WaitForMatch(
                            new Regex("Date", RegexOptions.None, RegexMatchTimeout));
                    }
                    catch (EndOfStreamException ex)
                    {
                        throw new InvalidOperationException(
                                  $"The {pkgManagerCommand} script '{_scriptName}' exited without indicating success.\n" +
                                  $"Output was: {stdOutReader.ReadAsString()}\n" +
                                  $"Error output was: {stdErrReader.ReadAsString()}", ex);
                    }
                    catch (OperationCanceledException ex)
                    {
                        throw new InvalidOperationException(
                                  $"The {pkgManagerCommand} script '{_scriptName}' timed out without indicating success. " +
                                  $"Output was: {stdOutReader.ReadAsString()}\n" +
                                  $"Error output was: {stdErrReader.ReadAsString()}", ex);
                    }
                }
        }
        /// <inheritdoc />
        public async Task Build(ISpaBuilder spaBuilder)
        {
            //var pkgManagerCommand = spaBuilder.Options.PackageManagerCommand; // todo: use this for .netcore >3.x
            var pkgManagerCommand = "npm";
            var sourcePath        = spaBuilder.Options.SourcePath;

            if (string.IsNullOrEmpty(sourcePath))
            {
                throw new InvalidOperationException($"To use {nameof(ChikoAngularCliBuilder)}, you must supply a non-empty value for the {nameof(SpaOptions.SourcePath)} property of {nameof(SpaOptions)} when calling {nameof(SpaApplicationBuilderExtensions.UseSpa)}.");
            }

            var logger = spaBuilder.ApplicationBuilder.ApplicationServices.GetService <ILoggerFactory>()
                         ?.CreateLogger <ChikoAngularCliBuilder>();
            var scriptRunner = new NodeScriptRunner(
                sourcePath,
                _scriptName,
                "",
                // "--watch", // todo: make it configurable
                null,
                pkgManagerCommand);

            scriptRunner.AttachToLogger(logger);

            using (var stdOutReader = new EventedStreamStringReader(scriptRunner.StdOut))
                using (var stdErrReader = new EventedStreamStringReader(scriptRunner.StdErr))
                {
                    try
                    {
                        await scriptRunner.StdOut.WaitForMatch(
                            new Regex("chunk", RegexOptions.None, RegexMatchTimeout));
                    }
                    catch (EndOfStreamException ex)
                    {
                        throw new InvalidOperationException(
                                  $"The {pkgManagerCommand} script '{_scriptName}' exited without indicating success.\n" +
                                  $"Output was: {stdOutReader.ReadAsString()}\n" +
                                  $"Error output was: {stdErrReader.ReadAsString()}", ex);
                    }
                    catch (OperationCanceledException ex)
                    {
                        throw new InvalidOperationException(
                                  $"The {pkgManagerCommand} script '{_scriptName}' timed out without indicating success. " +
                                  $"Output was: {stdOutReader.ReadAsString()}\n" +
                                  $"Error output was: {stdErrReader.ReadAsString()}", ex);
                    }
                }
        }
        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);
        }