简体   繁体   中英

How to have Nx environment variables in React app per environment?

Context

I have a three projects inside my Nx workspace, two applications which are react apps (both of them have shared logic, however they are intended for different platforms web and microsoft teams and must be separated) and a library which contains logic for an api client, which both of the applications use.

The api client project requires the variable base URL which is environment specific.

I can define environment variables and introduce file replacements in the build process for.ts files (eg environment.ts is replaced with environment.production.ts, when configuration is production), however I do not want to reference this file (environment.ts) in the api client project so as not to introduce two way dependencies.

What have I tried

From the api project I was not able to extract the logic which depends on the URL variable as this is tied to some code generation which is changeable.

I succeeded in providing this variable by using.env file in the root of the application project, the variable is in the format NX_MY_URL, and could be accessed with process.env.NX_MY_URL.

However I was not able to change this variable when changing the build configuration (eg development, test, production). I have tried adding a fileReplacements task such as

"configurations": {
        "development": {
          "fileReplacements": [
            {
              "replace": "apps/ra-web/src/environments/environment.ts",
              "with": "apps/ra-web/src/environments/environment.development.ts" //<----- This works fine
            },
            {
              "replace": "apps/ra-web/.env",
              "with": "apps/ra-web/.development.env" //<----- This does not work, .env values remain
            }
          ],

Question

How can.env files be replaced based on Nx target's configuration?

Why the mentioned approach does not work?

The reason of why the fileReplacements approach is not working is because those replacements are meant for the building process, which is the bundler the one in charge (webpack or vite, etc). That file content replacement is actually working, yet it doesn't happen at file system level but at memory level (for the bundling process). As your application code does not "import" that.env file (and you should not directly depend on it), then those file replacements make no difference in the build output.

On the other side, Nx is in charge of reading the .env file (at file-system level) and loading the data as environment variables so that when the bundling process starts, those are available. This a completely separate process than the fileReplacements done by the bundler.

How to achieve what you are looking for?

If you think about projects in libs as shareable/re-usable code, then you can imagine those are external dependencies added to your apps (or other libs). As those dependencies are external, they should rely on their implementor to get the data needed for them to work.

Having the above in mind, your lib public API (the main index.ts file) should be parametrized to receive that base URL that will depend on each application. With that you can keep working with the environment.ts file replacements, get the value in the app and pass it down to the lib .

Example:

// app's main.tsx
import { environment } from './environments/environment';
import { apiClient } from '@myorg/api-client';

apiClient.init({ baseUrl: environment.baseUrl });

// api-client's index.ts
export { apiClient } from './lib/api-client';

// api-client's api-client.ts

export const apiClient = {
   init: ({ baseUrl }) => { ... }
};

If you still need to work with the .env file (not trying to replace it), just the the env vars in the environment.ts as work with it as mentioned above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM