Chris W.
Chris W.

Reputation: 23290

Use environment to set proxy.config.js property for ng serve

Title pretty much sums it up. I've got a proxy.conf.js file that gets hit on ng serve and I just want to grab the target url from the environment ts file, or a json file, or I don't really care at this point, I just want one place to store the URL that feeds the others respectively...

So environment.congif.ts (which is not included in any configurations, just a file to store the settings object that currently feeds environment.dev.ts and is failing to feed proxy.conf.js);

export const environment = {
    production: false,
    apiUrl: 'http://localhost:12345'
};

Then proxy.conf.js;

var settings = require('./src/environments/environment.config');

const PROXY_CONFIG = [{
    "/restapi/*": {
      "target": settings.environment.apiUrl,
      "secure": false,
      "changeOrigin": true,
      "logLevel": "debug"
    }
}]

module.exports = PROXY_CONFIG

Which for some reason I obviously don't understand (especially since intellisense fills in the path just fine for both the file and the property) I get error on ng serve;

Cannot find module './src/environments/environment.config'
Error: Cannot find module './src/environments/environment.config'
    at Function.Module._resolveFilename (module.js:547:15)
    at Function.Module._load (module.js:474:25)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
........

So my question is, why can it not resolve this way? I just want one file to set the target URL on that feeds the places it's needed from environment.config.ts

ADDENDUM : So the environment.*.ts files sit in /src/environments like with any default installation. The proxy.conf.js sits in the project root with other default files like package.json or angular.json. The paths are all correct, intellisense will even fill in the values but for whatever reason proxy.conf.js will not play nice when importing the const object from the environment (at build, though like I said intellisense finds everything just fine). So just like the title conveys, the only issue I'm having is reading the url into the proxy js file from the environment ts file so that I have only one file to maintain the apiurl in.

Upvotes: 4

Views: 15096

Answers (4)

Campadrenalin
Campadrenalin

Reputation: 243

In-memory transpile (how I solved it)

There are no good solutions here, because Angular wants environment files to be TypeScript and proxy configs to be JavaScript (or JSON). There's a couple ways you can bridge that gap. My approach was to in-memory-transpile the environment file - they're generally tiny, simple, and well-contained, and you have TypeScript installed anyways. This is the top of my src/proxy.conf.js, before actually using the values from environment:

/*
 * Based on reference here:
 * https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API#a-simple-transform-function
 *
 * Loads, transpiles, and executes a Typescript module.
 * This is very simple, literally just enough for an environment.ts file.
 */
function load_ts(filename) {
    const fs = require('fs');
    const ts = require('typescript');

    // Load and transpile to JS
    let ts_code = fs.readFileSync(filename, 'utf-8');
    let js_code = ts.transpileModule(ts_code, {
        compilerOptions: { module: ts.ModuleKind.CommonJS }
    }).outputText;

    // Execute JS. We need 'exports' to exist, or this breaks.
    let exports = {};
    return eval(js_code);
}

const environment = load_ts('./src/environments/environment.ts');

// ...

This has some advantages in running just when you need it, being seamless with ng serve (assuming you're pointing to it in angular.json), and just generally having a low impact on workflow. It also means that if you need your proxy config to be JavaScript instead of JSON (for JS-exclusive features), it's pretty straightforward to think about. But it assumes that your environment.ts file doesn't do anything too exciting or clever - usually a fair assumption, but if you're doing imports in environment.ts, you might want a different approach.


Out-of-band compile (an alternative)

If you are wrapping your commands in npm run ... instead of using ng serve directly, you have the option to write your proxy config in TypeScript, and compile it before running ng serve:

/*   src/proxy.conf.ts   */
import * as environment from './environments/environment';
  
export = {
    '/api': {
        target: (<any>environment).api_server || 'http://example.com',
        changeOrigin: true,
        logLevel: "debug",
        // ...
    }
}

And in your package.json (only including relevant parts)...

{
  "scripts": {
    "start": "npm run proxy-config && ng serve",
    "proxy-config": "tsc --types node --module commonjs src/proxy.conf.ts"
  }
}

And of course, you point your angular config at the generated file src/proxy.conf.js.

This has a few obnoxious traits (generates src/environments/environment.js, is a bit slower on startup, doesn't run unless you wrap your commands, easier to get wrong), but is probably the most flexible option available.

A very similar variant (transpile src/environments/environment.js ONLY, hand-write src/proxy.conf.js with a JS import) has similar benefits, but is left as an exercise to the reader.

Upvotes: -1

Chris W.
Chris W.

Reputation: 23290

So the problem here turned out to be the version of typescript and its lack of import vs require support. If you're using anything like v3 you won't encounter the same issue. Thanks for looking!

Upvotes: 1

Sergey
Sergey

Reputation: 7692

You could do it in a similar way https://stackblitz.com/edit/angular-2uz6n8

I've done this simply by placing both environment variables in one file.


Why don't you just use predefined environment variables? You can easily add some properties to environment.ts and environment.prod.ts and access these properties via import { environment } from './environment'; and then simply envoronment.ANY_KEY_YOU_WANT corresponding environment file will be used.

Upvotes: 0

Ahmed hussien
Ahmed hussien

Reputation: 43

Hey Chris If you need to configure proxy all you need to create a custom file called proxyconfig.json and put it in the app directory which will be out of the src folder of your app.

1- simulate that you need to get some data from this endpoint before you configure your proxy file

this.http.get('http://locahost:3000/api/v1/people')
  

2- proxyconfig.json will contain this json

{
  "/api/*": { // 
    "target": "http://localhost:3000", // the target url for backend endpoint
    "secure": false,
    "logLevel": "debug",
    "changeOrigin": true
  }
}

3- you need to get some changes in your package.json

   "scripts": {
      "start": "ng serve -- --proxy-config ../../proxyconfig.json",
      ...
   }
} 

4- the endpoint in your service should be changed to be

this.http.get('/api/v1/people')
  

5- run ng serve the proxy will be working successfully

i hope that helps :))

Upvotes: -1

Related Questions