angular/angular-cli

Provide options to enable/disable the removal of decorators and replacement of resources in a prod build with AOT

Paladinium opened this issue ยท 61 comments

This is a feature request referring to the prod build with AOT using the CLI. A more general title would be "Provide options to make the applied transformations configurable". For my use case, it is sufficient to just consider the two specific options described below - but other developers might have other use-cases.

Requirements

It would be very helpful to me and many other developers if the compiler options would provide means to control the removal of decorators in a prod build with AOT. There are two ways that could make it happen. Either in tsconfig.json as a parameter to angularCompilerOptions, e.g.:

  "angularCompilerOptions": {
    "aotRemoveDecorators": false
  }

Or as a switch to the ng-command, e.g.

ng build --prod --aotRemoveDecorators=false

The wording of such an option is yet to be discussed. I personally would favor to distinguish options that are only valid for either AOT or JIT by having a prefix/suffix in the option's name as indicated.

Additional Requirement

For the use-case described below, it is also important to replace style and template URLs by their content. This is what is done in JIT mode just a few lines above the referenced code (see link below). Now either the proposed option implies this behavior (which I don't like since it is not obvious) or another option gives the developer control for that behavior, too, e.g.

ng build --prod --aotRemoveDecorators=false --aotReplaceResources=true

Use-Case

There are Angular apps that use standard Angular means. To make those applications run fast, it makes sense to use AOT. However, many of those applications also have a need to build Angular components dynamically and invoke the JIT compiler. I am aware that it seems unusual to use JIT and AOT in one app, but it is also a reality that many applications have this need (just do a search for AOT and JIT in the angular github issues). It has also been shown that it is indeed possible to make AOT and JIT work together (e.g. see angular/angular#15510). However, since the CLI removes the decorators in a prod build, the JIT compiler cannot compile the components and is emitting errors like "Please add a @NgModule annotation".

To make it work nowadays, it requires to hand-craft the build yourself using webpack or another bundler, but it is much more complex. Instead, it would be much more convenient to rely on the Angular CLI and use the powerful ecosystem that the CLI provides. The cost of adding such an option seems to me negligible compared to the pain many developers have. And I would highly appreciate if the CLI team would consider it.

The code responsible for the removal

The code responsible for the removal is located here:

this._transformers.push(removeDecorators(isAppPath, getTypeChecker));

Workarounds

I don't know any workaround and I would be very happy to hear some. For example, I was wondering if it is possible to override the function "removeDecorators" to just do nothing? Any other ideas?

For the sake of completeness, I reference some of the issues I found that are related to this feature request (either because the decorators are removed or because developers have issues with AOT and JIT):

angular/angular#15510
angular/angular#20875
angular/angular#20864
#6866
#5359
#2799
#6992
#8525

Yeah, I think we need both options, because we use pure webpack and don't use ng build --prod --removeDecorators=false at all, it would be just have a dual config the removeDecorators. I suppose.

@hansl would you accept a pull request for that? If so, in what form: config parameter, cli parameter, something else?

Thanks a lot, @ocombe , for providing help for this issue!

Yes, it flag very need

I see that some people did nasty hack to remove all decorators that come from @angular/core

function shouldRemove(decorator: ts.Decorator, typeChecker: ts.TypeChecker): boolean {
const origin = getDecoratorOrigin(decorator, typeChecker);
return origin && origin.module === '@angular/core';
}

There should be a better way to decide which decorators should be preserved than preserving all of them. For example, I only need decorated modules from a specific directory.

I did some research and it turns out that if you reexport NgModule, @ngtools will treat it as external decorator and preserve it :)

// ngmodule.decorator
import { NgModule } from '@angular/core';
export { NgModule };
import { NgModule } from './ngmodule.decorator';

@pawelkondraciuk where do you put this?

image

import { NgModule } from '@angular/core';
export { NgModule };
import { NgModule } from './ngmodule.decorator';

Error

Running "webpack:cory-build-aot" (webpack) task
Hash: ea4a0b4e45dd70086af4                                                         
Version: webpack 3.10.0
Time: 2091ms
 2 assets
   [0] ./test/angular-webpack/angular/polyfills.ts 0 bytes {1} [built]
   [1] ./test/angular-webpack/angular/bundle.aot.ts 0 bytes {0} [built]

ERROR in test/angular-webpack/angular/ngmodule.decorator.ts(1,10): error TS2300: Duplicate identifier 'NgModule'.
test/angular-webpack/angular/ngmodule.decorator.ts(3,10): error TS2300: Duplicate identifier 'NgModule'.

Put import { NgModule } from './ngmodule.decorator'; in desired file where you want to preserve decorator

Same error. :( I even added like this:

ngmodule.decorator.ts

import { NgModule, ModuleWithProviders } from '@angular/core';
export { NgModule, ModuleWithProviders };

module.ts

import {
    NgModule,
    ModuleWithProviders
} from './ngmodule.decorator';

@NgModule({
    imports: [
        etc,
    ],
    // export
    declarations: [
        etc,
    ],
    providers: [
        etc,
        forwardRef(() => Boot),
    ],
    exports: [
        etc,
    ],
    entryComponents: [],
})
export class CorifeusModule {

    constructor(private boot: Boot) {
        this.boot.boot();
    }

    public static forRoot(): ModuleWithProviders {
        return {
            ngModule: CorifeusModule,
//            providers: providers,
        };
    }
}

test module.ts

import { NgModule } from '../../../src/ngmodule.decorator';

@NgModule({
    imports: [
        HttpClientModule,
        BrowserModule,
        CorifeusModule,
        RouterModule.forRoot(routes),
    ],
    declarations: [
        Application,
        Http,
        Layout,
        Color,
        AuthHome,
        AuthLogin,
    ],
    providers: [
        SettingsService
    ],
    bootstrap: [ Application ]
})
export class Module {

    constructor(
        private settings: SettingsService,
    ) {
        const json = require('../json/settings.core.json');
        settings.extend('core', json);
    }
};

Same error

Running "webpack:cory-build-aot" (webpack) task
Hash: ea4a0b4e45dd70086af4                                                         
Version: webpack 3.10.0
Time: 3584ms
 2 assets
   [0] ./test/angular-webpack/angular/polyfills.ts 0 bytes {1} [built]
   [1] ./test/angular-webpack/angular/bundle.aot.ts 0 bytes {0} [built]

ERROR in : TypeError: Cannot read property 'getTsProgram' of undefined
  at AngularCompilerPlugin._getTsProgram (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/@ngtools/webpack/src/angular_compiler_plugin.js:188:62)
  at getTypeChecker (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/@ngtools/webpack/src/angular_compiler_plugin.js:521:43)
  at ast_helpers_1.collectDeepNodes.filter (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/@ngtools/webpack/src/transformers/remove_decorators.js:14:60)
  at Array.filter (<anonymous>:null:null)
  at standardTransform (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/@ngtools/webpack/src/transformers/remove_decorators.js:14:14)
  at transformer (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/@ngtools/webpack/src/transformers/make_transform.js:14:25)
  at /home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/typescript/lib/typescript.js:2888:86
  at reduceLeft (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/typescript/lib/typescript.js:2581:30)
  at /home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/typescript/lib/typescript.js:2888:42
  at transformRoot (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/typescript/lib/typescript.js:67711:82)
  at Object.map (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/typescript/lib/typescript.js:1879:29)
  at Object.transformNodes (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/typescript/lib/typescript.js:67699:30)
  at Object.emitFiles (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/typescript/lib/typescript.js:70529:28)
  at emitWorker (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/typescript/lib/typescript.js:74374:33)
  at /home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/typescript/lib/typescript.js:74334:66
  at runWithCancellationToken (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/typescript/lib/typescript.js:74425:24)
  at Object.emit (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/typescript/lib/typescript.js:74334:20)
  at defaultEmitCallback (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/@angular/compiler-cli/src/transformers/program.js:33:20)
  at AngularCompilerProgram.emit (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/@angular/compiler-cli/src/transformers/program.js:241:30)
  at AngularCompilerPlugin._emit (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/@ngtools/webpack/src/angular_compiler_plugin.js:754:49)
  at Promise.resolve.then.then.then (/home/patrikx3/Projects/patrikx3/corifeus/corifeus-web/node_modules/@ngtools/webpack/src/angular_compiler_plugin.js:587:54)
  at <anonymous>:null:null
  at process._tickCallback (internal/process/next_tick.js:160:7)


Child html-webpack-plugin for "index.html":
     1 asset
       [0] ./node_modules/html-webpack-plugin/lib/loader.js!./test/angular-webpack/index.html 261 bytes {0} [built]
Warning:  Use --force to continue.

Aborted due to warnings.


Execution Time (2018-02-03 13:40:18 UTC+1)
cory-ensure-protractor   1.8s  โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡ 31%
loading grunt-webpack   312ms  โ–‡โ–‡โ–‡โ–‡โ–‡ 5%
webpack:cory-build-aot   3.7s  โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡โ–‡ 63%
Total 5.8s

It just removes some other decorators, but which??? It's cool for you it works :/

Angular 2019.12.31-2359

I looked at it on the latest @ngtools/webpack, but no change on the remove decorators function in 4 months.
With Angular 6, I cannot use AOT at all. So sad.
With Angular 4, I used AOT+JIT at once, by now, AOT is not even usable anymore.

@Paladinium I think you help me a lot before with AOT and JIT at once, so here is a help for you:
https://gist.github.com/p3x-robot/e12ed76acb7033638b4179149546bb73

@Paladinium besides, the aot on my pages.corifeus.com is double speed instead of jit so it works! ๐Ÿ”ข

i just upgraded everything, just removed the decorators and that's it, it works, like magic.

Thanks, @p3x-robot . It's funny, we do the same workaround as you but with Gradle (which is our main build invoking the CLI - not going into details why) just after npm install. It is renaming removeDecorators by replaceResources in angular_compiler_plugin.js. One could also think of applying such a hack as part of the postinstall hook in packages.json if not using gradle. However, this is very unstable meaning that it can break anytime the CLI changes.

This is why I hope that @ocombe , besides being busy with many other tasks, can eventually help to solve this issue. In my view, he understands the pain and the use-cases described in this feature request.

@p3x-robot : with our help, others should now be able to figure out what to do. I highly appreciate that you shared it here! If you ask me, we should let the Angular guys do their job and avoid adding further comments.

Could the commit of marcelamsler be merged on angular-cli? I need also to skip removal of decorators in aot mode :(

In my view, the commit is only 50% correct. For JIT to work, the resources must also be replaced which is the IF condition just above where @marcelamsler made his change where function 'replaceResources' is called. Therefore, instead of having a narrow argument like 'skipRemoveDecorators', maybe a more general like 'enableJitInAot' might provide a higher level of abstraction.

Yep

I also noticed the build-optimizer option of angular-cli AOT compilation (default: true since Angular 5), is stripping the decorators as well :( so workaround for me, is to apply the hack above, and also to set build-optimizer to false. Definitively too much.....

but they are not allowing this merge...

@Paladinium but enableJitInAot is not about remove decorators.
You have info I have the project open, you know where I should put it?
I can add a new option add in the IF you are talking about and I can create a pull merge...

@Paladinium i guess, we could use both options, it's not bad, given for now I just use AOT purely.

@Paladinium still, i have to remove the decorators and don't use JIT.

image

If you have this hack, I can add it in.

I am sorry my pull-request for this commit was a mistake. I just tried if it could work but it did not. I am planning to do it, but I don't have time at the moment.

My current work-around is to disable build-optimizer ng-build --aot --build-optimizer=false and to re-export the needed decorators. This works for me and allows me to use dynamic templates until the new option is available.

import { Component, NgModule } from '@angular/core';

export { NgModule, Component };

And this is the component I wrote to make dynamic templates possible

import { Compiler, Input, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
import { Component, NgModule } from '@app/aot.decorators';

/*
 This Component allows you to compile a template at runtime. Just pass in the template, the needed modules and a context. Make sure that
 context is not a complete component, but an object with attributes. Because you would overwrite internal attributes.
 e.g. <cu-dynamic [template]="myObject.template" [context]="{data: myObject.data}" [modules]="FormsModule"></cu-dynamic>
 With the example above you could use a template like this <div>{{task.id}}</div>
 */
@Component({
    selector: 'cu-dynamic',
    template: '<ng-container #vc></ng-container>'
})
export class DynamicComponent implements OnInit {
    @ViewChild('vc', {read: ViewContainerRef}) viewContainer: ViewContainerRef;

    @Input() public template: string;
    @Input() public modules: any[];
    @Input() public context: any;

    constructor(private compiler: Compiler) {
    }

    public static createComponent(compiler: Compiler, template: string, modules?: any[]): any {
        @Component({template})
        class TemplateComponent {
        }

        @NgModule({
            declarations: [TemplateComponent],
            imports: modules
        })
        class TemplateModule {
        }

        const mod = compiler.compileModuleAndAllComponentsSync(TemplateModule);
        const factory = mod.componentFactories.find((comp: any) =>
            comp.componentType === TemplateComponent
        );

        return factory;
    }

    ngOnInit() {
        const component = DynamicComponent.createComponent(this.compiler, this.template, this.modules);

        const container = this.viewContainer.createComponent(component);
        Object.assign(container.instance, this.context);
        container.changeDetectorRef.detectChanges();
    }
}

This is awesome hack, another guy told me to do it, but only export the NgModule, so it looks like, I have to export and use the Component. That must be the missing hack.
I will try to check it out over the weekend. Thanks so much!

So with this, you don't even have to remove the decorators in AOT?

That is really all you have to do. It worked for us and we also use forms and ngModel and even the two way binding works. But I hope that we can fix it soon with a compiler-option, so this hack won't be necessary anymore and we can use build-optimizer again. Btw it is also awesome because we don't have to eject the webpack config like in your hack you proposed to paladium.

With your last question you meant not removing the removal of decorators? :-) Just to be sure, because as far as I understand the problem, we want to keep the decorators because otherwise aot and build optimizer will remove them and we can't use modules in jit compiler because we need these decorators on the modules.

Some additional info, I also tried to use ngsummary files and pass them to the compiler, like the testcompiler does, it but I was not able to get them.

@marcelamsler from the factories you can get VievDef and renderType. After giving them to the JitCompiler

@Alekcei sorry I don't get the context/intention of your comment. Why would I do/need that?

For Some additional info, I also tried to use ngsummary files and pass them to the compiler, like the testcompiler does, it but I was not able to get them.

I have re-architectured the whole system, only AOT, no JIT at all.

@p3x-robot how should it be possible to use aot if you don't know the template at compile-time?

variables, parameters

@marcelamsler I rather construct patterns/builders/factories with variables and parameters for the speed with JIT vs JIT+AOT vs AOT. It is so much faster, I deprecated JIT or the mix totally.

It is fact, that AOT is sometimes bigger (given code), instead of pure HTML, but I only use NGINX gzip on .js and the bundles are so small with gzip, that's cannot be measured by the difference.

I understand my point for you, I might be 2 old for this, but that's just code styling, an opinion.

We are not going to make any changes to how this works in the short term. The new Ivy view engine (slated to land in 7.0) will allow you to dynamically compose views (note that this is not the same thing as JIT/ $compile does - allowing full compilation is a security risk, and requires a HUGE amount of slow code to be shipped to browsers).

In short, the output of the compiler will be a public API, so that you could handwrite (or generate at runtime based on whatever) the same thing the compiler spits out. How you arrive at that point will be up to you. See https://github.com/angular/angular/blob/master/packages/core/test/render3/component_spec.ts#L28-L33 for an example of what that looks like. We will not provide you an API to take a string template and compile it at runtime.

See also https://github.com/angular/angular/blob/master/packages/core/src/reflection/reflection_capabilities.ts#L135 - rather than using a decorator, you could use the longhand syntax (this is what the decorator actually does):

import { Component } from '@angular/core';

export class AppComponent  {
  name = 'Angular 5';
}

AppComponent['decorators'] = [{
  type: Component, 
  args: [{
    selector: 'my-app',
    template: 'hello'
  }]
}]

This is a private API, is likely to blow up in your face if you rely on it, and is subject to change without warning or mercy, and we will immediately close any issues complaining about it with "I told you so" - again, shipping the JIT compiler to your users is a Bad Idea, and its an especially bad idea to take arbitrary, non-trusted input (eg, "I have random people write templates and drop them into a database, and then fetch them at runtime") and run it through the compiler. You have been warned. JIT is for development ONLY. Please do not rely on this behavior for production applications.

Thanks, @robwormald for taking your time to explain the thoughts of the Angular team on that subject. I do acknowledge many of your points (security, bundle size, performance, ...).

On the other side, I would be very happy if the Angular team could start to honor the need for more dynamic applications. The changes you mentioned for Angular 7 seem to go into that direction. But I am convinced that for web apps with an adaptive UI (e.g. allowing its customers for configuration), a very dynamic solution is required. This could also be a significant differentiator to other web frameworks.

@robwormald

Thank you for your explanation. I think it is a mistake to remove template compilation at runtime. I am with you that everybody should be very careful when they decide to use it, because it has some disadvantages (security, performance). But sometimes you just need it. And to assume that everyone who uses it, is just a noob who knows nothing about security, performance or a proper application architecture, is just wrong. ("I have random people write templates and drop them into a database, and then fetch them at runtime")

In our case we are wrapping an other application, which provides forms, we have to display. So it is just not possible to know the html at compile time. Also we have html content that can be defined and shown whenever the customer wants it. And there we need a lot of html features, which we can not avoid by using structured data from server. But these templates are designed by our own staff and we are also running a security check(whitelist) and optimizations on it, on the server side.

So please consider valid used cases for runtime compilation before removing it from Angular completely.

@Paladinium how about just compile the bundle and that's it? you got the databases, variables, just build it and put it on the server and it's AOT and secure.

@p3x-robot you have an example of how we could use a module compiled with angular cli, in another application created with angular cli, taking into account that they are not known at compile time ?

... just to notice ... using JitCompiler together with AOT mode is available right now -> and it means using any HTML code in run-time in fact. The only problem is CLI and its decorators removal when an app is built.

If any other way of compiling and building is used (Rollup, SystemJS, CC, ...) then it works just fine because decorators are contained in compiled code via ngc by default and it is necessary to remove them (regexp is the simplest way how to do it) if the minimum bundle sizing is required.

Is there any update of this feature request?
I really wish this feature can be implemented.

i can only this:

https://gist.github.com/p3x-robot/e12ed76acb7033638b4179149546bb73

plus i depreciated jit, i only use aot.
more thinking but you can use aot.
the worst is to rebuild on the server and thats it. so wicky to hack with jit , rebuild the app is the best i think, secure, fast, you will do the same thing hacking wih jit...

for the size i use gzip... wicked quick pure aot...

I found a viable solution to this problem. can create an angular element
Here is an example:
https://github.com/nrwl/playbook-angular-v6-elements-example

Then insert the script main.js and inline.js at run time and go!

you can create and compile components that can be loaded at run time, this technique does not need the application to know the components at compile time and get the benefits of the compiler

@marcelamsler From your example above, do I need to know about the @app/aot.decorators?

At the moment during my runtime I'm getting a StaticInjectError:
Uncaught (in promise): Error: StaticInjectorError[n -> n]: StaticInjectorError(Platform: core)[n -> n]: NullInjectorError: No provider for n!

Could this be my DI for the Compiler from @angular/core?

No, I also use the compiler from core directly. Make sure that all Modules for all components, pipes are passed in in "modules"-input. Also make sure, that your custom components you want to use (and their dependencies are using the re-exported decorators. Here is my current code with some minor improvements (supports replacing/changing template)

reexports

import { Component, Directive, HostListener, Input, NgModule, Pipe } from '@angular/core';

export { Component, Directive, HostListener, Input, NgModule, Pipe };

Here the dynamic component:

import { Compiler, EventEmitter, Input, Output, ViewChild, ViewContainerRef } from '@angular/core';
import { Component, NgModule } from '@app/aot.decorators';

/*
 This Component allows you to compile a template at runtime. Just pass in the template, the needed modules and a context. Make sure that
 context is not a complete component, but an object with attributes. Because you would overwrite internal attributes.
 e.g. <cu-dynamic [template]="details.html" [context]="{task: task}"></cu-dynamic>
 With the example above you could use a template like this <div>{{task.id}}</div>
 */
@Component({
    selector: 'cu-dynamic',
    template: '<ng-container #vc></ng-container>'
})
export class DynamicComponent {
    @ViewChild('vc', {read: ViewContainerRef}) viewContainer: ViewContainerRef;
    @Input() public modules: any[];
    @Output() public onTemplateError: EventEmitter<string> = new EventEmitter();
    private _context: any;
    private container;
    private _template: string;

    constructor(private compiler: Compiler) {
    }

    get context(): any {
        return this._context;
    }

    @Input()
    set context(value: any) {
        this._context = value;
        this.replaceComponentInDOM(this._template, this._context);
    }

    get template(): string {
        return this._template;
    }

    @Input()
    set template(value: string) {
        this._template = value;
        try {
            this.replaceComponentInDOM(this._template, this._context);
        } catch (e) {
            this.onTemplateError.emit(e.message);
        }
    }

    public static createComponent(compiler: Compiler, template: string, modules?: any[]): any {
        @Component({template})
        class TemplateComponent {
        }

        @NgModule({
            declarations: [TemplateComponent],
            imports: modules
        })
        class TemplateModule {
        }

        const mod = compiler.compileModuleAndAllComponentsSync(TemplateModule);
        const factory = mod.componentFactories.find((comp: any) =>
            comp.componentType === TemplateComponent
        );

        return factory;
    }


    private replaceComponentInDOM(template: string, context: any) {
        if (template && context) {
            const component = DynamicComponent.createComponent(this.compiler,
                template,
                this.modules
            );

            this.viewContainer.remove(0);
            this.container = this.viewContainer.createComponent(component);
            Object.assign(this.container.instance, context);
            this.container.changeDetectorRef.detectChanges();
        }
    }
}

@robwormald As others have expressed, there are companies (like mine) that want to use Angular but have use cases which would be very well served by being able to dynamically compile an html template into a component at runtime, knowing the risks and performance implications. You may want to reconsider this as a valid use case.

@marcelamsler I'm able to make this work without re-exporting the decorators. I only have to set build-optimizer=false. Of course this increases my output main.js file size by 40%.

@lefoulkrod why not use angular element?

Can I dynamically compile an html template into a component at runtime without build-optimizer=false ? Any update of this issue?

this is not something they want to care about ...
before i used this hack:
https://gist.github.com/p3x-robot/e12ed76acb7033638b4179149546bb73

where is my angular 1.x ...

Is there an update or work around for this issue yet?

Here are some of my observations relative to this problem (all 3 ways implies aot compilation enabled and combination of lib with custom decorators and project importing it)

  1. the problem is not observed when project imports the lib (with custom decorators) directly non-compiled (not from node_modules, but from inner folder as sources)
  2. the problem is not observed when project imports the lib from node_modules, as external but disables optimization
  3. the problem is not observed when importing project compiles to 'es5' target with aot

The problem is raised only when these factors meet together: optimization enabled (by default), es2015 target (by default) and library with it's own decorators is external to the project (comes from node_modules)

Still very waiting this flag (preserving custom annotations from external node_modules lib)! Probably it may be done by providing some ability to export custom decorators with lib module same way as it is done for pipes and services?

Angular team, please pay attention to this, your users are unhappy without it! It's actually a kind of trap: you writing custom decorators and all works well until you develop all the stuff. Next you go live of your project and everything wraps into a singularity because angular decides you don't need them as well as they don't and "optimizing" it without any care or choose.

Just take a look at this instruction how to achive this functionality here: https://blog.angularindepth.com/converting-typescript-decorators-into-static-code-using-tsquery-tstemplate-and-transforms-8c65d606a517 It's a kind of Fifty Shades of Grey. Do you think it's normal to rewrite AST tree in 2019 to bring this to project?

I have similar use-case: I need an Angular module which is compiled and stored on a remote server, and loaded into the main app in the runtime. Having in-browser compiler in the AOT build of the main app would solve the issue.

But since there is no solution for this yet (at least none of the solutions described above helped me, I was still getting other errors), I ended up with a different approach: compiling my remote module as an AOT bundle, using a custom builder script for that. And that is where this great article came handy: https://blog.angularindepth.com/building-extensible-dynamic-pluggable-enterprise-application-with-angular-aed8979faba5
This solution is more straightforward and requires fewer hooks and workarounds (basically, all hooks and workarounds end up in one place: custom builder). Although it requires time to set it up and run (took me ~5 hours).

This came up in a CLI meeting recently. @robwormald's previous comment is still a pretty accurate description of our feelings on the matter. Using JIT in a prod application causes a lot of performance and security issues. JIT is intended for development use only, and we don't expect that to change anytime soon.

Here's a link to a relevant discussion, if anybody still needs AOT-compilation of a separate module which is then included to the main application in the runtime via HTTP request: angular/angular#20875 (comment)

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.