TransWikia.com

Como crear variables de compilacion dinamicas en Angular?

Stack Overflow en español Asked by Andrus Diaz on August 26, 2021

El Problema:
Hola buenas, actualmente tengo un proyecto en Angular 10, el cual se compila para diferentes companys en sus propios servidores con sus variables personalizadas.
Es decir tienen su:

export const environment = {
  API_URL:'https://server-company.com'
};

La variable API_URL debe ser una constante distinta por company, ya que es compilada explícitamente para cada cliente por separado.

La solucion ideal:
Quisiera saber si exite alguna forma de enviar variables por el comando de compilación, ejemplo:
ng build --prod -var API_URL="https://cosa.com"
Ya que seria un gran problema editar el proyecto por cada company que se subscriba

One Answer

Traducido y resumido de este post


Es posible lograrlo simulando un enviroment de la siguiente manera:

  1. Creas un archivo llamado env.js con la siguiente estructura (no con cli) a la misma altura que el index.html
(function (window) {
  window.__env = window.__env || {};

  // API url
  window.__env.apiUrl = 'http://dev.your-api.com';

  // Whether or not to enable debug mode
  // Setting this to false will disable console output
  window.__env.enableDebug = true;
}(this));

Esto creara una variable global __env en el navegador conteniendo las variables de ambiente (enviroment) para nuestra aplicación.

  1. Agregamos una etiqueta <script> al elemento <head> en nuestro indexh.html para cargar env.js antes de que angular sea cargado.
<html ng-app="app">

  <head>
    <!-- Cargar variables de ambiente -->
    <script src="env.js"></script>
  </head>

  <body>
    ...
    <!-- El código de Angular se carga aquí -->
  </body>  

</html>  

  1. Le decimos a angular que al hacer ng build incluya este archivo:
{
  "projects": {
    "app-name": {
      "architect": {
        "build": {
          "options": {
            "assets": [
              "src/favicon.ico",
              "src/assets",
              "src/env.js" // <= Agregamos aqui nuestro fichero
            ]
          }
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              // ...
            }
          }
        }
      }
    }
  }
}

  1. Notificamos a angular de este nuevo archivo generando un servicio que cargue las variables en el scope de angular:

$ ng generate service env

Y reemplazamos el contenido:

export class EnvService {
  // Los valores que sean definidos aqui son los valores por defecto
  // que pueden ser sobreescritos por evn.js

  // API url
  public apiUrl = '';

  // Habilitar o no el modo debug. 
  public enableDebug = true;

  constructor() {
  }

}
  1. Creamos un nuevo fichero manualmente llamado env.service.provider.ts en el mismo directorio del servicio que contenga lo siguiente:
import { EnvService } from './env.service';

export const EnvServiceFactory = () => {  
  // Creamos el ambiente
  const env = new EnvService();
  // Leemos las variables de ambiente desde la ventana del navegador
  const browserWindow = window || {};
  const browserWindowEnv = browserWindow['__env'] || {};
  
  // Asignamos las variables de ambiente desde el navegador hacia env
  // En la implementacion actual, las propiedades de env.js sobreescriben los
  // valores por default en el EnvService
  // Si lo necesitas, aquí se puede realizar una fusión profunda para fusionar propiedades en lugar de sobrescribirlas

  for (const key in browserWindowEnv) {
    if (browserWindowEnv.hasOwnProperty(key)) {
      env[key] = window['__env'][key];
    }
  }

  return env;
};

export const EnvServiceProvider = {  
  provide: EnvService, //Importamos este servicio definido con anterioridad
  useFactory: EnvServiceFactory, //Exportamos el factory que crea la instancia de EnvService y copia los valores del objeto `window.__env` en la instancia de EnvService
  deps: [],
};

  1. Agregamos EnvServiceProvider a los providers para usar la inyección de dependencias de angular de esta manera:
import { NgModule } from '@angular/core';  
import { EnvServiceProvider } from './env.service.provider';

@NgModule({
  imports: [ // ... ],
  providers: [EnvServiceProvider],
})
export class AppModule {}  

Con estos pasos deberías de ser capaz de acceder a los datos en el fichero env.js y modificarlos aun con tu código compilado.

Ejemplo de uso:

import { Component } from '@angular/core';  
import { EnvService } from '../env.service';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss'],
})
export class HomeComponent {  
  constructor(
    private env: EnvService
  ) {
    if(env.enableDebug) {
      console.log('Debug mode enabled!');
    }
  }
}

Cabe señalar que en el link que te pongo hace una demostración sobre cómo es posible modificar el fichero env.js directamente en los archivos compilados para lograr lo que tu quieres sin necesidad de volver a compilar.

Correct answer by Legna on August 26, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP