4

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.

Chris W.
  • 22,835
  • 3
  • 60
  • 94
  • Your problem seems strange enough. But I really like to know did you change the name of `environment.ts` which is by default to `environment.dev.ts` for any specific purpose? I am not sure if it is because of that but in `angular.json` it is mentioned that this file will be replace by `environment.prod.ts` during production build. This error not supposed to be there as that command executes during production build, but still try to go with default `environment.ts` to see it the error still persist. And of-course these two files are for setting production and development configs only. – sndpkpr Dec 26 '18 at 15:56
  • Did you try using it as environment.dev.js? I don't think webpack-server is willing to transpile ts. – lossleader Dec 26 '18 at 16:31
  • @Sandeep. Ya environment.ts gets replaced by the configuration of the build. So for instance `ng build --prod` would replace environment.ts with environment.prod.ts, I do have a completely separate file in there not included in any build config with the specific intent of using it to store the dev configurations (anything without the --prod flag) which is what I'm trying to use to feed the proxy.conf.js and the environment.dev.ts, the environment.dev.ts imports it just fine for its settings, the problem is the proxy.conf.js require. :/ – Chris W. Dec 26 '18 at 17:19
  • @lossleader ya it imports into the environment.dev.ts fine, see previous comment for a little more detail. For whatever reason the require in the proxy.conf.js is a culprit that doesn't want to seem to read the object that contains the settings. Maybe some es6 vs commonjs syntax ignorance? Am not sure at this point. – Chris W. Dec 26 '18 at 17:21
  • By webpack-server I mean webpack-dev-server.. it reads the proxy conf and does not understand ts. – lossleader Dec 26 '18 at 17:25
  • @lossleader ya I had also tried just a json flat file to feed it with a require(..), I know there's some fixes in typescript ^2.9.2 that allow it but I'm still on typescript 2.7.2 that a bit of refactoring would need to happen to upgrade from at the moment. I was hoping it was just ignorance in regards to the nuances of typescript versioning or something silly I was missing. – Chris W. Dec 26 '18 at 17:28
  • @ChrisW. can you try out `import { environment } from './src/environments/environment.config';` instead of `var settings = require('./src/environments/environment.config');` ? – sndpkpr Dec 26 '18 at 17:40
  • @Sandeep ya that just throws a `SyntaxError: Unexpected token import` at me though which is where my issue lies so even if I try just a generic `import * as blah from './path/to/environment.config'` I just get the same error, which may be part of the typescript version issue? That's where I'm unsure unfortunately as I am no version guru lol. – Chris W. Dec 26 '18 at 17:52
  • 1
    @Sandeep the `require` would just be in the .js file, anything .ts handles an import from another ts file just fine. – Chris W. Dec 26 '18 at 18:03
  • Hey @ChrisW. I think it can be that the `js` extension files in angular can be imported like this `const { SpecReporter } = require('jasmine-spec-reporter');` I read it from default `protractor.conf.js`. Give it a try. Woo! but i almost forgot we can use `js` extension in angular lol. typescript – sndpkpr Dec 26 '18 at 18:03
  • I think you can either switch to environment.config.js as the shared format or have your IDE set to transpile in the same directory to have it read js for the proxy and TS in the built modules. – lossleader Dec 26 '18 at 18:03
  • Can you edit your question to include your file structure and angular.json file? it looks like this is only a 'wrong path' issue – benshabatnoam Dec 31 '18 at 09:13
  • If I understand your problem right you want to somehow catch your config with URIs when app starts so that you can use its values elsewhere? – Sergey Dec 31 '18 at 10:38
  • @benshabatnoam added some more info, however the file structure is default with angular.json etc at project root with proxy.conf.js as sibling, environment files in /src/environments, and intellisense will read the path and even the object attributes just fine. However on build it gives me the issue on the proxy.conf.JS – Chris W. Dec 31 '18 at 15:05

4 Answers4

1

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 :))

Ahmed hussien
  • 47
  • 1
  • 7
  • 1
    Howdy! Ya I have the proxy up and running fine if I have the url directly in my proxy.conf.js file, but what I'm trying to do is have it read the url from the environments settings (src/environments/environment.ts) since I have it confgured to replace it depending on the environment. So for example environment.dev.ts already has the proxy url in it as shown, I want to read (require) that value into the proxy.conf.js so there's only one file that a dev needs to update the url:port in that feeds everything that needs it. However thanks for trying to help! – Chris W. Dec 21 '18 at 15:41
  • @ChrisW. your could place your config in some JSON. Then get it via http.get as it's described. Then you may use value according to the environment (in Angular there is a method to get know which environment is running) – Sergey Dec 31 '18 at 10:42
1

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!

Chris W.
  • 22,835
  • 3
  • 60
  • 94
0

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.

Sergey
  • 7,184
  • 13
  • 42
  • 85
  • The environment files all work fine, I currently have varying configurations all setup and working properly. The issues is in the proxy.conf.js file that I'm trying to also import settings from the environment*.ts file but thanks for trying to help :) – Chris W. Dec 31 '18 at 14:58
  • @ChrisW. are you sure that you have to import exactly .js file? It's not really configurable. If you want to import `environment` and use it's variable it's worth to use `import { environment } from '...'` It looks like you've combined different module approaches and thus it results in error, since `export const NAME` requires `import { NAME } from ''` – Sergey Dec 31 '18 at 16:39
-1

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.

Campadrenalin
  • 243
  • 1
  • 7