# 11.1: Configuring for Deployment

Right now our projects are running separately. We run the API from the `.API` project using `dotnet watch run` and we run the Angular application from the `SPA` project with `ng serve`.

When using this command, Angular transpiles our `TypeScript` files and bundles them together. However, the bundles are only held in memory. They're also much larger than ideal.

Make note of the file sizes when running `ng serve` (particularly the `vendor.bundle.js` file):

![DevBundles](/files/-LEoXE0MvJJ5JKT6Gu46)

## A Note About Deployment

Deployment can be tricky. There can be a number of things that can (and will!) go wrong. Every possibility cannot be covered here as many problems can result from individual machines, configurations, and too many variables to account for.

Don't get frustrated if you run into an error! Read through the messages and google and stackoverflow are your friend!

This will be good practice for solving problems without a step-by-step guide to follow.

## Configuring Angular for Deployment

Instead of using the development server - we can run the `ng build` command and the Angular CLI will generate the files for us, instead of holding them in memory.

We can also add configuration to this in the `.angular-cli.json` file located in the `/src/` directory of your `SPA` project.

By default, the output directory `outDir` is set to a folder called `dist`:

```javascript
{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "efconnect-spa"
  },
  "apps": [
    {
      "root": "src",
      "outDir": "dist",                                         //    <--- here
      "assets": [
        "assets",
        "favicon.ico"
      ],
```

Running the `ng build` command with the default configuration will generate a folder called `dist` at the root level of the `SPA` project. That could work depending on how you're planning to deploy.

We're going to configure the output directory to be the `wwwwroot` folder in our `.API`. This is a folder mentioned briefly at the beginning of the tutorial. It's for holding static content like `HTML`, `CSS`, and `Javascript`. It's currently empty.

Update `angular-cli.json` and change the `outDir` value to the relative path to the `wwwroot` folder in your `.API` project:

```javascript
{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "efconnect-spa"
  },
  "apps": [
    {
      "root": "src",
      "outDir": "../EFConnect.API/wwwroot",                     //  <--- here
      "assets": [
        "assets",
        "favicon.ico"
      ],
```

Run `ng build`.

After it has finished running - take a look at the new files generated in the `.API/wwwroot` folder:

![DevBuild](/files/-LEoXE0eXg5NABqu2C-y)

This is still a development build. The files are larger and not as optimized (through minification, tree shaking, etc.) as they will be for deployment.

## Configuring API Project for Static Files

Our `.API` isn't serving any static files and it is unaware that we want it to. We need to do a little bit of configuration to allow it to serve the Angular static files. We'll do this in our middleware pipeline.

In the `Configure()` method of the `Startup.cs` class - add two methods:

1. `app.UseDefaultFiles();` - this tells the Kestrel server ASP.NET uses to use the default file names - so, it will know to look for a file called `index.html`.
2. `app.UseStateicFiles();` - as you could guess - this is to configure the application to serve static files.

```csharp
app.UseAuthentication();
app.UseDefaultFiles();                  //  <--- Added
app.UseStaticFiles();                   //  <--- Added
app.UseMvc();
```

Now, we should be able to run `dotnet watch run` and navigate to port 5000 instead of port 4200 to access our Angular application!

![Angular5000](/files/-LEoXE0p-qtUR5U-rzQL)

However, what happens if you login and refresh the page?

Ugh.

![Angular404](/files/-LEoXE0rEyXhH4oZR15E)

Why is this?

ASP.NET Core thinks this is working like a `Razor` front end. It sees we're trying to navigate to `/members` - and thinks there should be a `MembersController` with an `Index()` method to render the view. It can't find it, so it `404`s.

Fortunately, ASP.NET Core comes with a handy solution to this problem. We can tell our application - that if it encounters **any** route to hand over routing to Angular.

Again, in the `Configure()` method of the `Startup.cs` class add the following to the existing `app.UseMvc()` method:

```csharp
app.UseMvc(routes => {
    routes.MapSpaFallbackRoute(
        name: "spa-fallback",
        defaults: new { controller = "Fallback", action = "Index" }
    );
});
```

Now, we need to create the Controller that we specified in the above configuration.

In the `Controllers` folder, add a new class called `FallbackController`. We'll add a single `Index()` method that returns a physical file - our `index.html` file in the `wwwroot` folder:

```csharp
public class FallbackController : Controller
{
    public IActionResult Index()
    {
        return PhysicalFile(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "index.html"), "text/HTML");
    }
}
```

Now our application should be working as expected from port 5000.

## Publishing Angular App

We're still currently serving a development Angular application. Now, we're going to run a production build.

We need to do a bit more configuration in our Angular application before, though.

First, we need to add the `apiUrl` to the `enviroment.prod.ts` file.

```typescript
export const environment = {
  production: true,
  apiUrl: `api/`
};
```

We also need to change the `app.module.ts` file because we can't use a function inside our imports array for a production build. Currently, we have one where we're importing the `JwtModule`.

At the top of the file, under the import statements and above `@NgModule`, add the following:

```typescript
export function getAccessToken(): string {
  return localStorage.getItem('token');
}

export const jwtConfig = {
  tokenGetter: getAccessToken,
  whiteListedDomains: ['localhost:5000']
};

@NgModule({
    //  ...
```

Now, in the imports array - we can use this `jwtConfig` variable instead of passing in a function:

```typescript
imports: [
    BrowserModule,
    FormsModule,
    HttpClientModule,
    NgxGalleryModule,
    FileUploadModule,
    ButtonsModule.forRoot(),
    PaginationModule.forRoot(),
    RouterModule.forRoot(appRoutes),
    BsDropdownModule.forRoot(),
    TabsModule.forRoot(),
    JwtModule.forRoot({
      config: jwtConfig                                 //  <--- Modified
    })
  ],
```

Now we'll try running a production build. This is a place where things can get tricky. The `TypeScript` and `Angular` compiler will be much more strict now. Things it let us do before without an error, much less breaking our application, can break our application now.

In your terminal, run `ng build --prod`.

Hopefully it compiles without any errors. Again, if you get errors - read it carefully, think about what may be causing it, and google for solutions. Don't panic - it may just be a few small changes like changing a private member to public.

Once successful - notice the much smaller bundle sizes compared to our development build:

![ProdBuild](/files/-LEoXE1LfsJ1ipPqrfTp)

Restart your `.API` project - and, verify that the app is still working using our production Angular files.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://eleven-fifty-academy.gitbook.io/dotnet-302-core/11-appendix/11.1-configuring-for-deployment.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
