I have an angular 9 application in which I read the api url from an assets folder:
@Injectable()
export class ConfigService {
private configUrl = '../../../assets/config/config.json';
constructor(private loggerService: LoggerService) { }
public async loadConfig(): Promise<any> {
try {
const response = await fetch(this.configUrl);
if (!response.ok) {
throw new Error(response.statusText);
}
return await response.json();
} catch (err) {
this.loggerService.error(`ConfigService 'loadConfig' threw an error on calling ${this.configUrl} : ${err.tostring()}`);
}
}
}
Method used for reading configuration file is described in Configuring angular production files after build.
environment.ts
is
export const environment = {
production: false,
apiUrl: "https://localhost/api/",
};
environment.prod.ts
is
export const environment = {
production: true,
apiUrl: "https://server/api/",
};
config.json
is
{
"apiUrl": "http://someTestServer/api/"
}
The incomplete script to copy apiUrl
to config.json
var fs = require("fs");
fs.readFile(`./src/environments/environment.${process.env.CONFIG}.ts`, 'utf8', function (err, data) {
fs.writeFile('./src/assets/config/config.json', data, function (err) {
if (err) throw err;
console.log('complete');
});
});
My script section of package.json looks like following:
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"build-test": "CONFIG=test node update-config.js && npm run build",
"build-prod": "CONFIG=prod node update-config.js && npm run predeploy",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"predeploy": "ng build --prod",
"deploy": "node ftpdeploy.js"
}
Considering above: How can I automatically populate the contents of my config.json
file based on different environment variable prior build so I don't need to manually copy and paste a json file to the \dist
folder?
Update 1: Now I can copy the contents of my enviroment.xxx.ts into the config.json file. There is one problem remaining: When I copy the contents from environment.xxx.ts it copies the entire contents of environment.xxx.ts into the config.json (It also copies the import section of my enviroment.xxx.ts) however the expected result is to read the environment
(export const environment
) into an object and update the config.json according to the source environment
object. How can I achieve this?
Changing the pre-build script as:
const fs = require("fs");
fs.readFile(`/src/environments/${process.env.CONFIG}.ts`, (err, content) => {
fs.writeFile("/src/assets/config/config.json", JSON.stringify(versionObject), () => { });
});
then from command line (I assume npm run build
is the command to build, otherwise change it with your build command):
$ CONFIG=environment npm run build
should solve yuor problem.
Edit:
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
// add more lines as you need like this, one for each build environment
"build-test": "CONFIG=test node update-config.js && npm run build",
"build-prod": "CONFIG=prod node update-config.js && npm run predeply",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"predeploy": "ng build --prod",
"deploy": "node ftpdeploy.js"
},
I noticed a \
in your question, probably you are running under Windows, make sure to use a bash
: add a file called .npmrc
with only following line script-shell=bash
Edit: if you want to read the environment file with fetch
and parse it with await response.json()
, the file should be a json file, not a ts file:
{
production: true,
apiUrl: "https://server/api/",
}
Hope this helps.
From what you indicated in your updated posts and comments, what you want to achieve is not possible.
Basically, you want to copy an object (environment
) value to a json file, but this object imports some of its values from somewere else
So you have something like this
somewhere.ts
export const constantValue = "myValue";
environment.xx.ts
import {constantValue} from "./somewhere";
export const environment = {
production: false,
apiUrl: "https://localhost/api/",
otherValue: constantValue
};
Problem: before the build, you cannot access the value for constantValue
, so you cannot really make it a prebuild script.
After the build, the environment
object will be included in main-es2015XXX.js
. However, the value for otherValue
will be resolved only if you enabled buildOptimizer
in your angular.json
config, as shown below:
With buildOptimizer : false
, the value is not resolved yet, it will be at run time. So you cannot use these values to write your json file.
The environment
variable will look like this:
const environment = {
production: false,
apiUrl: "https://localhost/api/",
otherValue: _somewhere__WEBPACK_IMPORTED_MODULE_0__["constantValue"]
};
With buildOptimizer : true
, the value for constants can be resolved at build time. The value wll look like this
const i={production:!1,apiUrl:"https://localhost/api/",otherValue:"myValue"}
However, the code in mainXXX.js
is minified/uglified and I doubt that you'll be able to parse/extract the config value above...
So either remove all imports (use hard coded values) and use Daniele Ricci's answer, or manually create your json files.
Note
I did not fully understand your reason for doing that, but my feeling is that in your code you should use:
environment.ts
for values that do not change after the buildconfig.json
for values that can change after the buildIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With