2

I have an API with the following interface (just for the sake of example)

export type FrogAPI = {
  getFrogs(): Promise<Frog[]>
  putFrogs(frogs: Frog[]): Promise<void>
}

I have 2 versions of this, 1 mock version which reads and writes from localStorage:

export class LocalStorageFrogAPI implements FrogAPI {
  getFrogs(): Promise<Frog[]> {
    return Promise.resolve(JSON.parse(localStorage.getItem('@frogApi/frogs')))
  }
  // ...
}

And a real version which works with remote apis:

export class HttpFrogAPI implements FrogAPI {
  getFrogs(): Promise<Frog[]> {
    return fetch('/frogs').then((res) => res.json())
  }
  // ...
}

For development I'm using the localStorage one, for production the http one.

Question: How do I conditional import the right one, so at build time only the right sources are included in the output js? This is important because both files became quite bulky. I also don't want to expose the localStorage version at all in production for security reasons.

If I do this:

const ApiConstructor = process.env.ENV === 'development' 
    ? require('./LocalStorageFrogAPI')
    : require('./HttpFrogAPI')

export const API = new ApiConstructor() as FrogAPI

Both sources will still be included in the generated output. What's the right way of only having the right one in the output js? Is possible with some webpack config?

1 Answer 1

1

I had a similar requirement in the project I was working on. There are 2 main options as I found. First - is to use async import like:

const ApiConstructor = await import("./LocalStorageFrogAPI");

This can be done conditionally. But there could be problems with race conditions here. Especially in the development. When all the imports will be loaded and cached except for this one. Could lead to errors.

The solution we ended up with is to create 2 versions of the file that uses that conditional import. So, in your case one file (for dev) would use

const ApiConstructor = require("./LocalStorageFrogAPI");

and for prod:

const ApiConstructor = require("./HttpFrogAPI");

The rest of the code will be the same.

And then you just substitute files using webpack depending on the build (dev/prod).

You could use NormalModuleReplacementPlugin for the substitution. Or otherwise, this article gives a good overview of how to separate dev and prod dependencies using webpack: Managing Dev and Production Builds with Webpack

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

1 Comment

Hey, thanks for the answer, can you show an example about substituting files? I don't quite understand how I would do that.

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.