12

Is there a way to conditionally change imports based on an environment variable in [email protected]? I'm trying to do it in a way that doesn't require code changes in how services are imported in client code, but when needed I can specify a build flag to swap in mock services.

There is a pattern I tried using from this post:

File structure:

MyService
    MyServiceMock.ts
    MyServiceReal.ts
    index.ts

And in your index.ts, you can have the following:

import { environment} from '../environments/environment';

export const MyService = environment.mock ?
    require('./MyServiceMock').MyServiceMock:
    require('./MyServiceReal').MyServiceReal;

And in your client code, import MyService:

import MyService from './myservice/index';

The page loads, and I can see the dependency getting injected when stepping through the code, however there are compilation errors (which I believe are TypeScript errors) along the lines of Cannot find name 'MyService'.

2 Answers 2

14

You're going about it completely wrong. Angular can handle this use case with the use of factories when you configure the providers

providers: [
  Any,
  Dependencies
  {
    provide: MyService, 
    useFactory: (any: Any, dependencies: Dependencies) => {
      if (environment.production) {
        return new MyService(any, dependencies);
      } else {
        return new MockMyService(any, dependencies);
      }
    },
    deps: [ Any, Dependencies ]
]

Now you can just inject MyService everywhere because of the provide: MyService, but in development, you will get the mock, and in production you will get the real service.

See Also:

Sign up to request clarification or add additional context in comments.

5 Comments

This approach works well, but has a drawback, that mock services are included into production package
How exactly do I inject the provider when it's created this way? Normally I would import from the file the service lives in, but in this case it could one of two files. How do I tell Angular I want the provider from the provided factory function?
@Valevalorin by the token (the provide), which is MyService. That's what you inject.
I need to know specifically what the line beginning with import looks like.
@Enargit list the mock and the real service in a module and then conditionally load that module in the imports section. Also look at, where I got this answer from: stackoverflow.com/a/51772549/2733437
0

Change your MyService import to:

import { MyService } from './myservice/index';

The surrounding {} will tell the compiler to import a single export from the file. If you want to be able to import like:

import MyService from './myservice/index';

Then you must have a default export in index.ts e.g:

export default MyService; .

More information on TypeScript modules can be found here: https://www.typescriptlang.org/docs/handbook/modules.html

1 Comment

Thank you for the idea. I am still running into the same error though, with Cannot find name 'MyService'. Also potentially of note: the static analysis of the typescript in VS Code echos the same error, indicating that the import is resolving, but when attempting to do dependency injection in the constructor it is not resolving the name.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.