Renaming some SPA Middleware variables to be package manager agnostic
This commit is contained in:
parent
751882cf3c
commit
7c7dd6569f
|
|
@ -21,20 +21,20 @@ namespace Microsoft.AspNetCore.SpaServices.AngularCli
|
||||||
{
|
{
|
||||||
private static TimeSpan RegexMatchTimeout = TimeSpan.FromSeconds(5); // This is a development-time only feature, so a very long timeout is fine
|
private static TimeSpan RegexMatchTimeout = TimeSpan.FromSeconds(5); // This is a development-time only feature, so a very long timeout is fine
|
||||||
|
|
||||||
private readonly string _npmScriptName;
|
private readonly string _scriptName;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs an instance of <see cref="AngularCliBuilder"/>.
|
/// Constructs an instance of <see cref="AngularCliBuilder"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="npmScript">The name of the script in your package.json file that builds the server-side bundle for your Angular application.</param>
|
/// <param name="scriptName">The name of the script in your package.json file that builds the server-side bundle for your Angular application.</param>
|
||||||
public AngularCliBuilder(string npmScript)
|
public AngularCliBuilder(string scriptName)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(npmScript))
|
if (string.IsNullOrEmpty(scriptName))
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Cannot be null or empty.", nameof(npmScript));
|
throw new ArgumentException("Cannot be null or empty.", nameof(scriptName));
|
||||||
}
|
}
|
||||||
|
|
||||||
_npmScriptName = npmScript;
|
_scriptName = scriptName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -47,37 +47,36 @@ namespace Microsoft.AspNetCore.SpaServices.AngularCli
|
||||||
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)}.");
|
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 logger = LoggerFinder.GetOrCreateLogger(
|
var logger = LoggerFinder.GetOrCreateLogger(
|
||||||
spaBuilder.ApplicationBuilder,
|
spaBuilder.ApplicationBuilder,
|
||||||
nameof(AngularCliBuilder));
|
nameof(AngularCliBuilder));
|
||||||
var npmScriptRunner = new NodeScriptRunner(
|
var scriptRunner = new NodeScriptRunner(
|
||||||
sourcePath,
|
sourcePath,
|
||||||
_npmScriptName,
|
_scriptName,
|
||||||
"--watch",
|
"--watch",
|
||||||
null,
|
null,
|
||||||
pkgManagerName);
|
pkgManagerName);
|
||||||
npmScriptRunner.AttachToLogger(logger);
|
scriptRunner.AttachToLogger(logger);
|
||||||
|
|
||||||
using (var stdOutReader = new EventedStreamStringReader(npmScriptRunner.StdOut))
|
using (var stdOutReader = new EventedStreamStringReader(scriptRunner.StdOut))
|
||||||
using (var stdErrReader = new EventedStreamStringReader(npmScriptRunner.StdErr))
|
using (var stdErrReader = new EventedStreamStringReader(scriptRunner.StdErr))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await npmScriptRunner.StdOut.WaitForMatch(
|
await scriptRunner.StdOut.WaitForMatch(
|
||||||
new Regex("Date", RegexOptions.None, RegexMatchTimeout));
|
new Regex("Date", RegexOptions.None, RegexMatchTimeout));
|
||||||
}
|
}
|
||||||
catch (EndOfStreamException ex)
|
catch (EndOfStreamException ex)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
$"The NPM script '{_npmScriptName}' exited without indicating success.\n" +
|
$"The {pkgManagerName} script '{_scriptName}' exited without indicating success.\n" +
|
||||||
$"Output was: {stdOutReader.ReadAsString()}\n" +
|
$"Output was: {stdOutReader.ReadAsString()}\n" +
|
||||||
$"Error output was: {stdErrReader.ReadAsString()}", ex);
|
$"Error output was: {stdErrReader.ReadAsString()}", ex);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException ex)
|
catch (OperationCanceledException ex)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
$"The NPM script '{_npmScriptName}' timed out without indicating success. " +
|
$"The {pkgManagerName} script '{_scriptName}' timed out without indicating success. " +
|
||||||
$"Output was: {stdOutReader.ReadAsString()}\n" +
|
$"Output was: {stdOutReader.ReadAsString()}\n" +
|
||||||
$"Error output was: {stdErrReader.ReadAsString()}", ex);
|
$"Error output was: {stdErrReader.ReadAsString()}", ex);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.SpaServices.AngularCli
|
||||||
|
|
||||||
public static void Attach(
|
public static void Attach(
|
||||||
ISpaBuilder spaBuilder,
|
ISpaBuilder spaBuilder,
|
||||||
string npmScriptName)
|
string scriptName)
|
||||||
{
|
{
|
||||||
var pkgManagerName = spaBuilder.Options.PackageManagerName;
|
var pkgManagerName = spaBuilder.Options.PackageManagerName;
|
||||||
var sourcePath = spaBuilder.Options.SourcePath;
|
var sourcePath = spaBuilder.Options.SourcePath;
|
||||||
|
|
@ -32,15 +32,15 @@ namespace Microsoft.AspNetCore.SpaServices.AngularCli
|
||||||
throw new ArgumentException("Cannot be null or empty", nameof(sourcePath));
|
throw new ArgumentException("Cannot be null or empty", nameof(sourcePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(npmScriptName))
|
if (string.IsNullOrEmpty(scriptName))
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Cannot be null or empty", nameof(npmScriptName));
|
throw new ArgumentException("Cannot be null or empty", nameof(scriptName));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start Angular CLI and attach to middleware pipeline
|
// Start Angular CLI and attach to middleware pipeline
|
||||||
var appBuilder = spaBuilder.ApplicationBuilder;
|
var appBuilder = spaBuilder.ApplicationBuilder;
|
||||||
var logger = LoggerFinder.GetOrCreateLogger(appBuilder, LogCategoryName);
|
var logger = LoggerFinder.GetOrCreateLogger(appBuilder, LogCategoryName);
|
||||||
var angularCliServerInfoTask = StartAngularCliServerAsync(sourcePath, npmScriptName, pkgManagerName, logger);
|
var angularCliServerInfoTask = StartAngularCliServerAsync(sourcePath, scriptName, pkgManagerName, logger);
|
||||||
|
|
||||||
// Everything we proxy is hardcoded to target http://localhost because:
|
// Everything we proxy is hardcoded to target http://localhost because:
|
||||||
// - the requests are always from the local machine (we're not accepting remote
|
// - the requests are always from the local machine (we're not accepting remote
|
||||||
|
|
@ -63,27 +63,27 @@ namespace Microsoft.AspNetCore.SpaServices.AngularCli
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<AngularCliServerInfo> StartAngularCliServerAsync(
|
private static async Task<AngularCliServerInfo> StartAngularCliServerAsync(
|
||||||
string sourcePath, string npmScriptName, string pkgManagerName, ILogger logger)
|
string sourcePath, string scriptName, string pkgManagerName, ILogger logger)
|
||||||
{
|
{
|
||||||
var portNumber = TcpPortFinder.FindAvailablePort();
|
var portNumber = TcpPortFinder.FindAvailablePort();
|
||||||
logger.LogInformation($"Starting @angular/cli on port {portNumber}...");
|
logger.LogInformation($"Starting @angular/cli on port {portNumber}...");
|
||||||
|
|
||||||
var npmScriptRunner = new NodeScriptRunner(
|
var scriptRunner = new NodeScriptRunner(
|
||||||
sourcePath, npmScriptName, $"--port {portNumber}", null, pkgManagerName);
|
sourcePath, scriptName, $"--port {portNumber}", null, pkgManagerName);
|
||||||
npmScriptRunner.AttachToLogger(logger);
|
scriptRunner.AttachToLogger(logger);
|
||||||
|
|
||||||
Match openBrowserLine;
|
Match openBrowserLine;
|
||||||
using (var stdErrReader = new EventedStreamStringReader(npmScriptRunner.StdErr))
|
using (var stdErrReader = new EventedStreamStringReader(scriptRunner.StdErr))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
openBrowserLine = await npmScriptRunner.StdOut.WaitForMatch(
|
openBrowserLine = await scriptRunner.StdOut.WaitForMatch(
|
||||||
new Regex("open your browser on (http\\S+)", RegexOptions.None, RegexMatchTimeout));
|
new Regex("open your browser on (http\\S+)", RegexOptions.None, RegexMatchTimeout));
|
||||||
}
|
}
|
||||||
catch (EndOfStreamException ex)
|
catch (EndOfStreamException ex)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
$"The NPM script '{npmScriptName}' exited without indicating that the " +
|
$"The {pkgManagerName} script '{scriptName}' exited without indicating that the " +
|
||||||
$"Angular CLI was listening for requests. The error output was: " +
|
$"Angular CLI was listening for requests. The error output was: " +
|
||||||
$"{stdErrReader.ReadAsString()}", ex);
|
$"{stdErrReader.ReadAsString()}", ex);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
|
@ -20,10 +20,10 @@ namespace Microsoft.AspNetCore.SpaServices.AngularCli
|
||||||
/// sure not to enable the Angular CLI server.
|
/// sure not to enable the Angular CLI server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="spaBuilder">The <see cref="ISpaBuilder"/>.</param>
|
/// <param name="spaBuilder">The <see cref="ISpaBuilder"/>.</param>
|
||||||
/// <param name="npmScript">The name of the script in your package.json file that launches the Angular CLI process.</param>
|
/// <param name="scriptName">The name of the script in your package.json file that launches the Angular CLI process.</param>
|
||||||
public static void UseAngularCliServer(
|
public static void UseAngularCliServer(
|
||||||
this ISpaBuilder spaBuilder,
|
this ISpaBuilder spaBuilder,
|
||||||
string npmScript)
|
string scriptName)
|
||||||
{
|
{
|
||||||
if (spaBuilder == null)
|
if (spaBuilder == null)
|
||||||
{
|
{
|
||||||
|
|
@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.SpaServices.AngularCli
|
||||||
throw new InvalidOperationException($"To use {nameof(UseAngularCliServer)}, you must supply a non-empty value for the {nameof(SpaOptions.SourcePath)} property of {nameof(SpaOptions)} when calling {nameof(SpaApplicationBuilderExtensions.UseSpa)}.");
|
throw new InvalidOperationException($"To use {nameof(UseAngularCliServer)}, you must supply a non-empty value for the {nameof(SpaOptions.SourcePath)} property of {nameof(SpaOptions)} when calling {nameof(SpaApplicationBuilderExtensions.UseSpa)}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
AngularCliMiddleware.Attach(spaBuilder, npmScript);
|
AngularCliMiddleware.Attach(spaBuilder, scriptName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer
|
||||||
|
|
||||||
public static void Attach(
|
public static void Attach(
|
||||||
ISpaBuilder spaBuilder,
|
ISpaBuilder spaBuilder,
|
||||||
string npmScriptName)
|
string scriptName)
|
||||||
{
|
{
|
||||||
var pkgManagerName = spaBuilder.Options.PackageManagerName;
|
var pkgManagerName = spaBuilder.Options.PackageManagerName;
|
||||||
var sourcePath = spaBuilder.Options.SourcePath;
|
var sourcePath = spaBuilder.Options.SourcePath;
|
||||||
|
|
@ -31,15 +31,15 @@ namespace Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer
|
||||||
throw new ArgumentException("Cannot be null or empty", nameof(sourcePath));
|
throw new ArgumentException("Cannot be null or empty", nameof(sourcePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(npmScriptName))
|
if (string.IsNullOrEmpty(scriptName))
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Cannot be null or empty", nameof(npmScriptName));
|
throw new ArgumentException("Cannot be null or empty", nameof(scriptName));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start create-react-app and attach to middleware pipeline
|
// Start create-react-app and attach to middleware pipeline
|
||||||
var appBuilder = spaBuilder.ApplicationBuilder;
|
var appBuilder = spaBuilder.ApplicationBuilder;
|
||||||
var logger = LoggerFinder.GetOrCreateLogger(appBuilder, LogCategoryName);
|
var logger = LoggerFinder.GetOrCreateLogger(appBuilder, LogCategoryName);
|
||||||
var portTask = StartCreateReactAppServerAsync(sourcePath, npmScriptName, pkgManagerName, logger);
|
var portTask = StartCreateReactAppServerAsync(sourcePath, scriptName, pkgManagerName, logger);
|
||||||
|
|
||||||
// Everything we proxy is hardcoded to target http://localhost because:
|
// Everything we proxy is hardcoded to target http://localhost because:
|
||||||
// - the requests are always from the local machine (we're not accepting remote
|
// - the requests are always from the local machine (we're not accepting remote
|
||||||
|
|
@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<int> StartCreateReactAppServerAsync(
|
private static async Task<int> StartCreateReactAppServerAsync(
|
||||||
string sourcePath, string npmScriptName, string pkgManagerName, ILogger logger)
|
string sourcePath, string scriptName, string pkgManagerName, ILogger logger)
|
||||||
{
|
{
|
||||||
var portNumber = TcpPortFinder.FindAvailablePort();
|
var portNumber = TcpPortFinder.FindAvailablePort();
|
||||||
logger.LogInformation($"Starting create-react-app server on port {portNumber}...");
|
logger.LogInformation($"Starting create-react-app server on port {portNumber}...");
|
||||||
|
|
@ -72,11 +72,11 @@ namespace Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer
|
||||||
{ "PORT", portNumber.ToString() },
|
{ "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
|
{ "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 NodeScriptRunner(
|
var scriptRunner = new NodeScriptRunner(
|
||||||
sourcePath, npmScriptName, null, envVars, pkgManagerName);
|
sourcePath, scriptName, null, envVars, pkgManagerName);
|
||||||
npmScriptRunner.AttachToLogger(logger);
|
scriptRunner.AttachToLogger(logger);
|
||||||
|
|
||||||
using (var stdErrReader = new EventedStreamStringReader(npmScriptRunner.StdErr))
|
using (var stdErrReader = new EventedStreamStringReader(scriptRunner.StdErr))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -84,13 +84,13 @@ namespace Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer
|
||||||
// it doesn't do so until it's finished compiling, and even then only if there were
|
// 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
|
// no compiler warnings. So instead of waiting for that, consider it ready as soon
|
||||||
// as it starts listening for requests.
|
// as it starts listening for requests.
|
||||||
await npmScriptRunner.StdOut.WaitForMatch(
|
await scriptRunner.StdOut.WaitForMatch(
|
||||||
new Regex("Starting the development server", RegexOptions.None, RegexMatchTimeout));
|
new Regex("Starting the development server", RegexOptions.None, RegexMatchTimeout));
|
||||||
}
|
}
|
||||||
catch (EndOfStreamException ex)
|
catch (EndOfStreamException ex)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
$"The NPM script '{npmScriptName}' exited without indicating that the " +
|
$"The {pkgManagerName} script '{scriptName}' exited without indicating that the " +
|
||||||
$"create-react-app server was listening for requests. The error output was: " +
|
$"create-react-app server was listening for requests. The error output was: " +
|
||||||
$"{stdErrReader.ReadAsString()}", ex);
|
$"{stdErrReader.ReadAsString()}", ex);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,10 @@ namespace Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer
|
||||||
/// sure not to enable the create-react-app server.
|
/// sure not to enable the create-react-app server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="spaBuilder">The <see cref="ISpaBuilder"/>.</param>
|
/// <param name="spaBuilder">The <see cref="ISpaBuilder"/>.</param>
|
||||||
/// <param name="npmScript">The name of the script in your package.json file that launches the create-react-app server.</param>
|
/// <param name="scriptName">The name of the script in your package.json file that launches the create-react-app server.</param>
|
||||||
public static void UseReactDevelopmentServer(
|
public static void UseReactDevelopmentServer(
|
||||||
this ISpaBuilder spaBuilder,
|
this ISpaBuilder spaBuilder,
|
||||||
string npmScript)
|
string scriptName)
|
||||||
{
|
{
|
||||||
if (spaBuilder == null)
|
if (spaBuilder == null)
|
||||||
{
|
{
|
||||||
|
|
@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer
|
||||||
throw new InvalidOperationException($"To use {nameof(UseReactDevelopmentServer)}, you must supply a non-empty value for the {nameof(SpaOptions.SourcePath)} property of {nameof(SpaOptions)} when calling {nameof(SpaApplicationBuilderExtensions.UseSpa)}.");
|
throw new InvalidOperationException($"To use {nameof(UseReactDevelopmentServer)}, you must supply a non-empty value for the {nameof(SpaOptions.SourcePath)} property of {nameof(SpaOptions)} when calling {nameof(SpaApplicationBuilderExtensions.UseSpa)}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactDevelopmentServerMiddleware.Attach(spaBuilder, npmScript);
|
ReactDevelopmentServerMiddleware.Attach(spaBuilder, scriptName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue