npm package: @okode/ngx-multienvironment
Description: Angular library to manage multiple environments without rebuilding the application.
Latest version: 1.1.2

# Multienvironment Management for Angular

Angular library to manage multiple environments without rebuilding the application.

# Install

```shell
npm i @okode/ngx-multienvironment
```

# Usage

### Create a environments.json file

Here you can set all your multienv configuration. You can create your own custom environments.

```json
{
  "dev": {},
  "pre": {},
  "pro": {},
  "custom": {}
}
```

### Setup on bootstrap

Add `provideEnvironment()` to your `app.config.ts` providers list.

```typescript

import { ApplicationConfig } from '@angular/core';
import { EnvironmentConfig, provideEnvironment } from '@okode/ngx-multienvironment/core';

// Receives env key and environment config as method
export const getAppConfig: (config: {
  env: string;
  envConfig: EnvironmentConfig;
}) => ApplicationConfig = config => ({
  providers: [
    ...,
    provideEnvironment(config.env, config.envConfig), //<- Add this
  ],
});

```

At `main.ts` you can initialize the multienvironment service and obtain the selected environment on the application bootstrap.

```typescript
//main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { getAppConfig } from './app/app.config';
import { initMultiEnvironmentApp } from '@okode/ngx-multienvironment/core';

async function bootstrapApp() {
  // Init multienvironmet service.
  const { env, envConfig } = await initMultiEnvironmentApp();
  bootstrapApplication(
    AppComponent,
    // Propagates env key and config to build application config
    getAppConfig({
      env,
      envConfig,
    })
  ).catch(err => console.error(err));
}

bootstrapApp();
```

### Setup on server

For Server Side Rendering (SSR) applications. First, add `provideServerMultienvironment()` to `serverConfig` providers list.

```typescript
// app.config.server.ts
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
import { provideServerRendering } from '@angular/platform-server';
import { EnvironmentConfig } from '@okode/ngx-multienvironment/core';
import { provideServerMultienvironment } from '@okode/ngx-multienvironment/server';
import { getAppConfig } from './app.config';

const serverConfig: ApplicationConfig = {
  providers: [
    provideServerRendering(),
    provideServerMultienvironment(), // <- Add this provider
  ],
};

// Receives env key and environment config as method
export const getConfig: (config: {
  params;
  env: string;
  envConfig: EnvironmentConfig;
}) => ApplicationConfig = config =>
  mergeApplicationConfig(
    // Propagates env key and config to build application config
    getAppConfig({
      env: config.env,
      envConfig: config.envConfig,
    }),
    serverConfig
  );
```

Then you will need to set a `APP_ENVIRONMENT` to provide a selected environment on to the `main.server.ts`.

```typescript
// main.server.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { getConfig } from './app/app.config.server';
import environments from '../src/assets/environments.json';

const bootstrap = () => {
  const env =
    (process.env['APP_ENVIRONMENT'] as keyof typeof environments) ?? 'pro';
  const envConfig = environments[env];
  return bootstrapApplication(AppComponent, getConfig({ env, envConfig })); // <- Bootstrap the application with the given environment
};
export default bootstrap;
```

### Use the CONFIG InjectionToken

To retrieve the environment configuration in your app.

```typescript
import { CONFIG, EnvironmentConfig } from '@okode/ngx-multienvironment/core';

@Injectable({ providedIn: 'root'})
export class SomeService() {
constructor (@Inject(CONFIG) environmentConfig: EnvironmentConfig) {}
...
}
```

## Run multienvironment

### Launching Single Page Application (SPA)

On the first bootstrap of your SPA, you will see an **environment selector** to choose your environment on runtime.
Your choice will be saved on the navigator local storage.

This selector **won't appear if there's only one evironment** on the `environments.json` configuration.

![Environment Selector](./docs/assets/selector.gif)

### Launching Server-Side Rendering (SSR)

To enable Server-Side Rendering (SSR) for your application, specify the `APP_ENVIRONMENT` key when using the SSR serve command.

Execute the following command in your terminal:

```zsh
APP_ENVIRONMENT=pro node dist/server/main.js
```

This ensures that your SSR setup runs with the specified environment configuration.

## Environment deployment

### SPA's

To deploy your application without displaying the environment selector, you must make adjustments to the `environments.json` configuration in your Continuous Deployment (CD) setup.
For example, if you want to deploy on the `production`environment, the artifact that you will be publishing must be modified in order to let the `prod` configuration only.

To do that in your command-line (for a CD pipeline) you can run something like this:

```bash
unzip my-app-0.0.1-production.zip
cd my-app-0.0.1-production/assets
jq '.pro' environments.json > temp.json && mv temp.json environments.json
```

### Server (SSR)

For SSR applications it's not necesary to modify the file. You just need to indicate on the server machine or container an `APP_ENVIRONMENT` env var.

For example, you can run your Docker container with any evironment running something like this:

```bash
docker run --env APP_ENVIRONMENT=pro my-doc-container
```

# API

- [Core](#api-core)
- [Server](#api-server)

## API Core

- [Models](#models)
  - [EnvironmentConfig](#environmentconfig)
- [Functions](#functions)
  - [initMultiEnvironmentApp](#initmultienvironmentapp)
- [TOKENS](#tokens)
  - [ENVIRONMENT_CONFIG](#environment_config)
  - [ENVIRONMENT](#environment)
- [Provider Functions](#provider-functions)
  - [provideEnvironment(...)](#provideenvironment)

### Models

#### EnvironmentConfig

```typescript
type Record<string, unknown>
```

---

### Functions

#### initMultiEnvironmentApp

```typescript
initMultiEnvironmentApp(opts?: { environmentsJsonFilePath?: string }) => Promise<{ env: string; envConfig: EnvironmentConfig }>;
```

| Param  |       Type        |
| :----: | :---------------: |
| environmentsJsonFilePath | string |

It reads environments json file and if there are more than one selector, then it shows an environment selector. Once the user presses on a selector option, then the method will return the releated environment key and configuration.

---

### TOKENS

#### ENVIRONMENT_CONFIG

```typescript
InjectionToken<EnvironmentConfig>('ENVIRONMENT_CONFIG');
```

#### ENVIRONMENT

```typescript
InjectionToken<EnvironmentConfig>('ENVIRONMENT_NAME');
```

---

### Provider Functions

#### provideEnvironment(...)

```typescript
provideEnvironment(env:string, config: EnvironmentConfig) => EnvironmentsProviders
```

Provides the EnvironmentProviders given a selected environment from a EnvironmentConfig.

| Param  |       Type        |
| :----: | :---------------: |
|  env   |      string       |
| config | EnvironmentConfig |

---

## API Server

- [Provider Functions](#provider-functions)
  - [provideServerMultienvironment()](#provideservermultienvironment)
- [Express Middlewares](#express-middlewares)
  - [blockEnvironmentsFileRequest](#blockEnvironmentFileRequest)

### Provider Functions

#### provideServerMultienvironment()

```typescript
provideServerMultienvironment() => EnvironmentProviders
```

In a SSR application, provides the EnvironmentProviders given a selected environment from a EnvironmentConfig.

### Express middlewares

#### blockEnvironmentsFileRequest

Example of usage:

```typescript
server.use(blockEnvironmentsFileRequest());
```

It blocks all requests to download the environments file.