Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Idiomatic Conditional TypeScript compilation in Angular

I'm using Angular 9 and I have some code like this:

(features.ts, autogenerated:)
// AUTO-GENERTATED FILE. DO NOT EDIT!
export const Features = {
  // Whether to reveal our Secret New Feature to the world
  ENABLE_SECRET_FEATURE: 1
};

(mycode.ts, app code)
import { Features } from 'generated/features.ts';

function doSomething() {
  if (Features.ENABLE_SECRET_FEATURE) {
    doAIBlockChainARThing();
  } else {
    doSomeBoringOldCRUDThing();
  }
}

I'd like the code emitted to be EITHER

function doSomething() {
    doAIBlockChainARThing();
}

OR

function doSomething() {
    doSomeBoringOldCRUDThing();
}

but not both.

Is there an invocation of ng build that would make this happen? I know uglify can sort of do this and Closure Compiler certainly can. My current invocation is: ng build --aot=true --stats-json --buildOptimizer=true --optimization=true --prod

After some experimentation I have see that the terser settings in Angular prod builds do what I want if I have code like:

const SECRET_FEATURE = true;
if (SECRET_FEATURE) {
  // code here is emitted
} else {
  // code here is NOT emitted
}

However if I try to do something like:

import {SECRET_FEATURE} from 'my-features';

if (SECRET_FEATURE) { // this conditional is emitted
  // this code is emitted
} else {
  // this code is also emitted
}

My thought is I'll have to use something like https://www.npmjs.com/package/tsickle for better dead-code elimination, along with a custom WebPack config to call it. I was hoping for a more Angular-centric path just so I don't have to create/document a lot of custom machinery for future engineers.

like image 553
Gavin Avatar asked Feb 29 '20 18:02

Gavin


People also ask

What are different types of compilation in angular?

Conclusion: You can compile your angular application in two ways: JIT and AOT.

What is TSC compiler in angular?

The Angular Compiler (which we call ngc ) is the tool used to compile Angular applications and libraries. ngc is built on the TypeScript compiler (called tsc ) and extends the process of compiling TypeScript code to add additional code generation related to Angular's capabilities.

What is compilation process in angular?

The Angular ahead-of-time (AOT) compiler converts your Angular HTML and TypeScript code into efficient JavaScript code during the build phase before the browser downloads and runs that code. Compiling your application during the build process provides a faster rendering in the browser.

How many compilers are there in angular?

Angular has two compilers: View Compiler. Module Compiler.

Is typescript a good choice for conditional compilation?

@sebas86 That's not really conditional compilation. If I have code that only compiles under certain circumstances (conditions), typescript will attempt to compile all if/else blocks and it will fail. But it works and for me and was good enough when I need something similar to preprocessor.

What are the different modes of compilation in angular?

In Angular, we have 2 modes of compilation: 1. JIT (Just In Time) Compilation 2. AOT (Ahead of Time) Compilation Until Angular 8, JIT compilation is the default compilation. Since Angular 9, AOT Compilation is the default mode of compilation.

When do conditional types become distributive in JavaScript?

When conditional types act on a generic type, they become distributive when given a union type. For example, take the following: type ToArray < Type > = Type extends any ? Type [] : never; If we plug a union type into ToArray, then the conditional type will be applied to each member of that union. type ToArray < Type > = Type extends any ?

How do I use the and condition in AngularJS?

The element will be added to the DOM if all conditions are fulfilled. The following example demos how AngularJS evaluates an AND condition: If only one of the conditions is true, you can use *ngIf to display the element with the help of the OR (||) operator. The following code snippet demonstrates the use of the OR condition in ngIf.


2 Answers

I've just tried on a fresh angular 9 project build with ng build --prod

With the following code, in a component's class

import { Features } from 'generated/features.ts';

doSomething() {
  if (Features.ENABLE_SECRET_FEATURE) {
    console.log('AAAA');
  } else {
    console.log('BBBB')();
  }
}

the compiled code is what you expect (the else part is not emitted)

doSomething() {console.log('AAAA');}

If you have other methods calls in you if/else, this is a bit different

For instance, with the code below

import { Features } from 'generated/features.ts';

   doSomething() {
    if (Features.ENABLE_SECRET_FEATURE) {
      this.doAIBlockChainARThing();
    } else {
      this.doSomeBoringOldCRUDThing();
    }
  }

  private doAIBlockChainARThing()
  {
    console.log('AAAAAAAAA');
  }

  private doSomeBoringOldCRUDThing()
  {
    console.log('BBBBB');
  }

the compiled code is

doSomething(){this.doAIBlockChainARThing()}
doAIBlockChainARThing(){console.log("AAAAAAAAA")}
doSomeBoringOldCRUDThing(){console.log("BBBBB")}}

So the else part is not generated, but unused private methods are not dropped by terser either.

You could use your if test again in the specific method to have no secret code generated at all, but it's not very convenient

  private doAIBlockChainARThing()
  {
    if (Features.ENABLE_SECRET_FEATURE)
    console.log('AAAAAAAAA');
  }
like image 142
David Avatar answered Oct 26 '22 01:10

David


For build specific changes you should use Angular.json fileReplacements.

See related answer @ngrx/store-devtools for production mode

like image 31
MTJ Avatar answered Oct 26 '22 02:10

MTJ