New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Overview page for SPAs #26373
Comments
@javiercn can you write the overview page for SPAs ? |
Architecture of Single Page Application templatesThe SPA templates for Angular and React offer the ability to develop Angular and React applications that are hosted inside a .NET backend server. At publish time, the files of the Angular and React app are copied to the wwwroot folder and are served via the static files middleware. A fallback route handles unknown requests to the backend and serves the index.html for the SPA. During development, the application is setup to leverage the frontend proxy provided by React and Angular (which is in fact the same). When the app launches, we open the index page in the browser. There, a special middleware that is only plugged in during development, intercepts the incoming requests, checks whether the proxy is running, and redirects to the URL for the proxy if its running or launches a new instance and returns a page to the browser that will autorefresh every few seconds until the proxy is up and the browser is redirected. sequenceDiagram
participant Browser
participant Proxy
participant Server
Browser->>Server: GET /
alt Proxy is running
Server->>Browser: 301 Redirect <<Proxy-URL>>
else Proxy is not running
Server->>Proxy: Launch
par Browser checks with server if the proxy is running
loop Until SPA proxy is running
Server->>Browser: 200 OK <html>...</html>
Browser->>Browser: Wait
Browser->>Server: GET /
end
and Server checks if proxy is ready
loop Until SPA proxy is ready
Server->>Proxy: GET <<Proxy-Url>>
alt Proxy not ready
Proxy->>Server: Error
else Proxy ready
Proxy->>Server: 200 OK <html>...</html>
end
end
end
Server->>Browser: 301 Redirect <<Proxy-URL>>
end
Browser->>Proxy: GET <<Proxy-URL>>
Proxy->>Browser: 200 OK <html>...</html>
loop Other resources and requests
Browser->>Proxy: HTTP Request
Proxy->>Browser: HTTP Response
end
The main work that our templates do during development (other than launching the proxy if it is not already running) consists of setting up HTTPS and configuring some requests to be proxied back to the backend ASP.NET Core server. When the browser sends a request for a backend endpoint, like sequenceDiagram
participant Browser
participant Proxy
participant Server
Browser->>Proxy: GET /weatherforecast
Proxy->>Server: GET <<Server-Url>>/weatherforecast
Server->>Proxy: 200 OK <<json>>
Proxy->>Browser: 200 OK <<json>>
Published Single Page ApplicationsAs mentioned in the beginning of the document. When the application is published, the SPA becomes a collection of files inside the wwwroot folder. There is no runtime component required to serve the app.
When we publish the app via <Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
</Target>
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build -- --configuration production" />
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="$(SpaRoot)dist\**; $(SpaRoot)dist-server\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
</Project> Developing Single Page ApplicationsThe project file defines a few properties that control the behavior of the app during development. These properties are:
The package It uses a Hosting Startup Assembly defined inside Setup for the client ApplicationThis setup is specific to the frontend framework the app is using, however many aspects of the configuration are similar. Angular setup
{
"prestart": "node aspnetcore-https",
"start": "run-script-os",
"start:windows": "ng serve --port 44416 --ssl --ssl-cert %APPDATA%\\ASP.NET\\https\\%npm_package_name%.pem --ssl-key %APPDATA%\\ASP.NET\\https\\%npm_package_name%.key",
"start:default": "ng serve --port 44416 --ssl --ssl-cert $HOME/.aspnet/https/${npm_package_name}.pem --ssl-key $HOME/.aspnet/https/${npm_package_name}.key",
}
Inside
proxy.conf.js is included in the project and defines the routes that need to be proxied back to the server backend. The general set of options is defined https://github.com/chimurai/http-proxy-middleware for react and angular since they both use the same proxy under the hood. The snippet below uses logic based on the environment variables set during development to determine the port the backend is running on. const target = env.ASPNETCORE_HTTPS_PORT ? `https://localhost:${env.ASPNETCORE_HTTPS_PORT}` :
env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'http://localhost:8141'; React setup
{
"prestart": "node aspnetcore-https && node aspnetcore-react",
"start": "rimraf ./build && react-scripts start",
}
Inside the Finally, inside The snippet below uses logic based on the environment variables set during development to determine the port the backend is running on. const target = env.ASPNETCORE_HTTPS_PORT ? `https://localhost:${env.ASPNETCORE_HTTPS_PORT}` :
env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'http://localhost:8141'; |
I guess these can be linked #25028 |
@Rick-Anderson reassigning this to you, as there isn't pending work for @javiercn here. Thanks! |
@javiercn FWIW your comment here detailing the proxy functionality (specifically the need to modify |
I'll take care of that in #28047 |
@ghidalgo3 the intention of opening and detailing these issues is to update the docs, we collaborate with our docs teams to figure out the language, grammar, etc. Since we are not professional writers. |
Can we provide an overview page for SPAs so that we can add common information about SPA development with ASP.NET Core? As well as docs on how the templates work during development and production? (I will be providing the content).
Could we also remove the JavaScript Services section from the docs, since that is not something we longer recommend?
/cc @danroth27
Document Details
⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.
Associated WorkItem - 58766
The text was updated successfully, but these errors were encountered: