Typescript conditional import











up vote
1
down vote

favorite












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?










share|improve this question




























    up vote
    1
    down vote

    favorite












    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?










    share|improve this question


























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      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?










      share|improve this question















      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?







      typescript webpack






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 19 at 14:14

























      asked Nov 19 at 11:15









      Balázs Édes

      9,09223056




      9,09223056
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          1
          down vote



          accepted










          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






          share|improve this answer























          • Hey, thanks for the answer, can you show an example about substituting files? I don't quite understand how I would do that.
            – Balázs Édes
            Nov 19 at 14:12












          • @BalázsÉdes, I updated the answer.
            – Daniil Andreyevich Baunov
            Nov 19 at 15:41











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53373443%2ftypescript-conditional-import%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          1
          down vote



          accepted










          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






          share|improve this answer























          • Hey, thanks for the answer, can you show an example about substituting files? I don't quite understand how I would do that.
            – Balázs Édes
            Nov 19 at 14:12












          • @BalázsÉdes, I updated the answer.
            – Daniil Andreyevich Baunov
            Nov 19 at 15:41















          up vote
          1
          down vote



          accepted










          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






          share|improve this answer























          • Hey, thanks for the answer, can you show an example about substituting files? I don't quite understand how I would do that.
            – Balázs Édes
            Nov 19 at 14:12












          • @BalázsÉdes, I updated the answer.
            – Daniil Andreyevich Baunov
            Nov 19 at 15:41













          up vote
          1
          down vote



          accepted







          up vote
          1
          down vote



          accepted






          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






          share|improve this answer














          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







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 19 at 15:41

























          answered Nov 19 at 11:25









          Daniil Andreyevich Baunov

          1,027527




          1,027527












          • Hey, thanks for the answer, can you show an example about substituting files? I don't quite understand how I would do that.
            – Balázs Édes
            Nov 19 at 14:12












          • @BalázsÉdes, I updated the answer.
            – Daniil Andreyevich Baunov
            Nov 19 at 15:41


















          • Hey, thanks for the answer, can you show an example about substituting files? I don't quite understand how I would do that.
            – Balázs Édes
            Nov 19 at 14:12












          • @BalázsÉdes, I updated the answer.
            – Daniil Andreyevich Baunov
            Nov 19 at 15:41
















          Hey, thanks for the answer, can you show an example about substituting files? I don't quite understand how I would do that.
          – Balázs Édes
          Nov 19 at 14:12






          Hey, thanks for the answer, can you show an example about substituting files? I don't quite understand how I would do that.
          – Balázs Édes
          Nov 19 at 14:12














          @BalázsÉdes, I updated the answer.
          – Daniil Andreyevich Baunov
          Nov 19 at 15:41




          @BalázsÉdes, I updated the answer.
          – Daniil Andreyevich Baunov
          Nov 19 at 15:41


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53373443%2ftypescript-conditional-import%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          "Incorrect syntax near the keyword 'ON'. (on update cascade, on delete cascade,)

          Alcedinidae

          Origin of the phrase “under your belt”?