Angular: Angular2 AOT compilation - "Cannot determine the module for class (... many components which are unused)"

Created on 20 Dec 2016  ·  183Comments  ·  Source: angular/angular

[ x ] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior
Unused components/pipes/directives in my workspace are detected by the compiler, which throws the error Cannot determine the module for class (...) for each file. It stops compilation, and does not seem be configurable. This is a problem, since I need to have those files in my workspace, but do not need them in the resultant app (partner implementations requiring different combos of shared components). This is especially frustrating with regards to compiling in a webpack loader, which should be able to provide a list of files which are included, regardless of workspace.

Expected behavior
I would expect these errors to be warnings, and/or able to be silenced by a compiler option. Alternatively, with regards to webpack, you could allow a list of files to be inserted, so that a webpack could provide all files in the require chain, instead of all files in the workspace.

Minimal reproduction of the problem with instructions
Cannot demo in plunkr, since it uses JIT.

  1. Create a basic angular app which bootstraps an ngModule with one component, AppComponent
  2. Get this app into a state which can be AOT compiled (should be pretty easy with a hello world)
  3. Add a component to the directory structure, but do not reference it anywhere in your code.
  4. Try to AOT compile again. You will get the warning Cannot determine the module for class

What is the motivation / use case for changing the behavior?
My company has a base app for ourselves, and our partners use modified versions of that app as their own. Rather than maintain all partners separately, we use a shared library of common generic components, imported as needed. For our base app, everything is fine, since we use every component. For partners, we cannot use AOT, since some of the components in the shared npm package do not have a declared module.

Please tell us about your environment:
Happens across all devices, but the current testing setup is:
WIndows 10
VS Code
Cmder (bash terminal)

  • Angular version:
    v2.1.0 (though we have also tested in 2.3.1

  • Browser: All - this is a compiler issue, not browser specific

  • Language: Typescript

  • Node (for AoT issues): node v6.3.0
P5 compiler NgModule ve low error messages triage #1 confusing

Most helpful comment

@DzmitryShylovich It makes sense for components you are USING to need to be part of a module. But as far as the compiler is concerned, these files should not matter. They are unused, un-referenced .ts files that happen to contain components.

All 183 comments

Cannot determine the module for class

Component must be a part of a module. It's intended.
I would say it's a feature request.

@DzmitryShylovich It makes sense for components you are USING to need to be part of a module. But as far as the compiler is concerned, these files should not matter. They are unused, un-referenced .ts files that happen to contain components.

@swimmadude66 u can exclude unused files in tsconfig

@DzmitryShylovich you can, but barrel files complicate that. If a class is re-exported in a barrel file, I have to ignore the barrel file as well, which can cause problems with the classes I DO need from that barrel.

It seems weird that the compiler should try to compile any more than it absolutely has to. Tree-shaking aside, I'd expect the compiler to want to only deal with files given to it or explicitly linked to given files.

It seems weird that the compiler should try to compile any more than it absolutely has to.

this is how compilers work...

The fact that JIT compilation works should be pretty good evidence that the compiler does not NEED these files. It is throwing an error instead of a warning on files which could be excluded with no harm done.

you can talk down to me about how compilers work all day, but this is a real issue in a somewhat basic use case. I am only asking for some way to at least suppress the error and continue at my own risk.

My co-worker is attempting to remove any barrel files which could be blocking us from using blanket excludes, but I'd ask you take a look at the issue I originally opened against @ngtools/webpack, where another user had the same error from a component only referenced in their tests. https://github.com/angular/angular-cli/issues/3636

The compiler is aware of files which I am not asking it to compile, and it is throwing unrecoverable errors for recoverable situations. plain as that.

I don't understand why you have components in the same directory that aren't included in the project.
I do think this could be a feature request but currently this is how the compiler works, also saying "it works in JIT" is not reason enough to think it should work in AOT.
What I think you need to do is separate out these files from your base app into modules then import them through some sort of package manager, this way it solves your problems, tidies up your directory and makes it easier to maintain from every aspect

@Toxicable the unused files are in a library-style npm module. Generally the ideal usecase is something like this:

in @project/angular (our shared code npm module) we have all the components, pipes, directives, and services needed to make our base app and communicate with our backend platform. Our partners want an app that looks similar, but uses a different home page, or has some new component added. However, most of the other pages will be the same, and all the services needed to connect to our platform might be the same.

Our approach to maximize reusable code was make each partner create modules, and import a combination of new pieces, and shared pieces from the npm module. My new HomeModule might have an import like:

import {
    OverviewComponent,
    ProfileComponent
} from './components/home';

import {
    AuthComponent
} from '@project/angular';

this then blows up in AOT saying: Cannot determine the module for class OverviewComponent since we are not using the OverviewComponent from @project/angular.

Since literally no files point at @project/angular/components/home/overview/component.ts I wouldn't expect the compiler to care at all that it is unused. but since the file exists inside the node_modules dir of our project, the compiler finds it, complains, and dies.

As for the JIT works !== AOT works, the base app works with AOT, and the changes in the Proof of Concept partner are incredibly small. I do not mean to imply that everything that works in JIT should work in AOT, but I have very good reason to believe that this should.

I have another example where this current behaviour doesn't make sense - tests.
Say, I have a feature directory some-feature, with some-feature.component.ts and some-feature.component.spec.ts.
This component uses content projection, so I would like to test that functionality by creating a test component inside my some-feature.component.spec.ts file which uses some-feature component in the view, like so:

@Component({
  selector: 'test-app',
  template: `<some-feature><p>projected content</p></some-feature>`
})
export class TestAppComponent {}

I then use this component in my testing module:

  ...
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [TestAppComponent, SomeFeatureComponent]
    })
  })
  ...

Everything's valid and great, until when i run ng build --prod --aot using angular-cli, which throws:
Cannot determine the module for class TestAppComponent.

I don't think AOT should be concerned with .spec files..

The general rule is: ngc will compile everything that tsc compiles. And it will try to compile every component that it finds. However, Angular can't compile components without a related module.

We could change this error into a warning though.

I also have test wrapper components that are used for testing only and that causes AOT to blow up as described here. Would be nice if AOT could ignore all components that satisfies a wildcard expression like TestComponent* etc.

Alright, so more info here. We do seem to have found a workaround for our case (doesn't fix the testWrapper case). It seems the real issue in our case was our barrel files. When importing ANYTHING from a barrel file, it follows the chain of all things re-emitted by the barrels. Since we were pulling in our components from a top level PROJECT/components, it was analyzing ALL components instead of just the one we wanted. This would still probably be better as a warning, but I can understand a little better why the compiler cared about those components.

seeing same error:

$ ./node_modules/.bin/ng-xi18n
Error: Cannot determine the module for class DividerPanel in C:/msweb/studiotouch/src/comps/dividerpanel/DividerPanel.ts!
Cannot determine the module for class EntryPanel in C:/msweb/studiotouch/src/comps/entry/EntryPanel.ts!
Cannot determine the module for class ForgotPass in C:/msweb/studiotouch/src/comps/entry/ForgotPass.ts!
Cannot determine the module for class Footer in C:/msweb/studiotouch/src/comps/footer/Footer.ts!
Cannot determine the module for class Infobox in C:/msweb/studiotouch/src/comps/infobox/Infobox.ts!
Cannot determine the module for class InputNumeric in C:/msweb/studiotouch/src/comps/inputnumeric/InputNumeric.ts!
Cannot determine the module for class InputString in C:/msweb/studiotouch/src/comps/inputstring/InputString.ts!
Cannot determine the module for class Loading in C:/msweb/studiotouch/src/comps/loading/Loading.ts!
Cannot determine the module for class MapAddress in C:/msweb/studiotouch/src/comps/mapaddress/MapAddress.ts!
Cannot determine the module for class Minitab in C:/msweb/studiotouch/src/comps/minitabs/MiniTab.ts!
Cannot determine the module for class Minitabs in C:/msweb/studiotouch/src/comps/minitabs/MiniTabs.ts!
Cannot determine the module for class ModalDialog in C:/msweb/studiotouch/src/comps/modaldialog/ModalDialog.ts!
Cannot determine the module for class Ng2Highcharts in C:/msweb/studiotouch/src/comps/ng2-highcharts/src/directives/ng2-highcharts.ts!

Cannot determine the module for class Ng2Highstocks in C:/msweb/studiotouch/src/comps/ng2-highcharts/src/directives/ng2-highstocks.ts!

Cannot determine the module for class Ng2Highmaps in C:/msweb/studiotouch/src/comps/ng2-highcharts/src/directives/ng2-highmaps.ts!
Cannot determine the module for class simplelistEditable in C:/msweb/studiotouch/src/comps/simplelist/simplelistEditable.ts!
Cannot determine the module for class simplelist in C:/msweb/studiotouch/src/comps/simplelist/simplelist.ts!
Cannot determine the module for class FilterPipe in C:/msweb/studiotouch/src/pipes/FilterPipe.ts!
Cannot determine the module for class FilterPipeEqual in C:/msweb/studiotouch/src/pipes/FilterPipeNot.ts!
Cannot determine the module for class OrderBy in C:/msweb/studiotouch/src/pipes/OrderBy.ts!
Cannot determine the module for class ReplacePipe in C:/msweb/studiotouch/src/pipes/ReplacePipe.ts!
Cannot determine the module for class SortBy in C:/msweb/studiotouch/src/pipes/SortBy.ts!
    at analyzeAndValidateNgModules (C:\msweb\studiotouch\node_modules\@angular\compiler\bundles\compiler.umd.js:24878:17)
    at Extractor.extract (C:\msweb\studiotouch\node_modules\@angular\compiler\bundles\compiler.umd.js:27727:20)
    at Extractor.extractBundle (C:\msweb\studiotouch\node_modules\@angular\compiler-cli\src\extractor.js:40:33)
    at Extractor.extract (C:\msweb\studiotouch\node_modules\@angular\compiler-cli\src\extractor.js:30:34)
    at extract (C:\msweb\studiotouch\node_modules\@angular\compiler-cli\src\extract_i18n.js:7:67)
    at Object.main (C:\msweb\studiotouch\node_modules\@angular\tsc-wrapped\src\main.js:47:16)
    at Object.<anonymous> (C:\msweb\studiotouch\node_modules\@angular\compiler-cli\src\extract_i18n.js:14:9)
    at Module._compile (module.js:556:32)
    at Object.Module._extensions..js (module.js:565:10)
    at Module.load (module.js:473:32)
Extraction failed

root@DESKTOP-VEUHFOL /cygdrive/c/msweb/studiotouch

Angular 2 Kitchen sink: http://ng2.javascriptninja.io
and source@ https://github.com/born2net/Angular-kitchen-sink
Regards,

Sean

i18 should not walk the entire project structure and instead look at the declarations used.

I tried to clean the directives that are not being used, and the rabbit hole just got deeper:

$ ./node_modules/.bin/ng-xi18n
Error: Error at C:/msweb/ng-skeleton/node_modules/typescript/lib/lib.d.ts:18770:11: Duplicate identifier 'ActiveXObject'.
Error at C:/msweb/ng-skeleton/node_modules/typescript/lib/lib.d.ts:18773:13: Duplicate identifier 'ActiveXObject'.
Error at C:/msweb/ng-skeleton/e2e/app.po.ts:1:38: Cannot find module 'protractor'.
Error at C:/msweb/ng-skeleton/node_modules/@angular/core/src/facade/lang.d.ts:12:17: Cannot find name 'Map'.
Error at C:/msweb/ng-skeleton/node_modules/@angular/core/src/facade/lang.d.ts:13:17: Cannot find name 'Set'.
Error at C:/msweb/ng-skeleton/node_modules/@angular/core/src/application_init.d.ts:16:18: Cannot find name 'Promise'.
Error at C:/msweb/ng-skeleton/node_modules/rxjs/Observable.d.ts:68:60: Cannot find name 'Promise'.
Error at C:/msweb/ng-skeleton/node_modules/rxjs/Observable.d.ts:68:70: Cannot find name 'Promise'.
Error at C:/msweb/ng-skeleton/node_modules/@angular/core/src/linker/compiler.d.ts:53:49: Cannot find name 'Promise'.
Error at C:/msweb/ng-skeleton/node_modules/@angular/core/src/linker/compiler.d.ts:61:65: Cannot find name 'Promise'.
Error at C:/msweb/ng-skeleton/node_modules/@angular/core/src/application_ref.d.ts:116:67: Cannot find name 'Promise'.
Error at C:/msweb/ng-skeleton/node_modules/@angular/core/src/application_ref.d.ts:132:101: Cannot find name 'Promise'.
Error at C:/msweb/ng-skeleton/node_modules/@angular/core/src/application_ref.d.ts:158:67: Cannot find name 'Promise'.
Error at C:/msweb/ng-skeleton/node_modules/@angular/core/src/application_ref.d.ts:160:101: Cannot find name 'Promise'.

let me add that all is working fine with angular-cli and angular-compiler, so its just i18 that is not liking my project.

Reference (nice and clean setup): https://github.com/born2net/ng-skeleton

Regards,

Sean

Same error for commented out components .. unused and commented out components for development stage are just useful step to not process

// two comments aot read:

//  {path: 'about', component: AboutComponent 
// import { AboutComponent } from './about';

@kirjai ngc compiles all files inside a source directory. it doesn't matter if you are import it or not.

@DzmitryShylovich which I understand, I'm just saying that I don't think that the AOT should care about this file at all in this case.. in my mind, skipping .spec files during AOT compilation is the way to go. But clearly there's something that's stopping the team from doing that, I understand.

As an alternative, then maybe the putting .spec files in the same directory as the entity the tests are written for should not be suggested by the style guide?

I also run into this error message (and some others) because of our test code and AOT in combination.

I can recommend this article. It explains how certain error messages can be provoked and how to fix/workaround them.

Considering that people will stumble into this exact issue if they follow the official testing guide and build their app with AOT, you may want to update the guide?

(If someone looks for an answer regarding RouterLinkStubDirective)
_You can fix it by adding a "dummy" module:_

/**
 * Needed so that `aot` build is working. But it isn't used throughout our tests and/or app.
 */
@NgModule({
    imports: [
        AppModule
    ],
    declarations: [
        RouterLinkStubDirective,
        RouterOutletStubComponent
    ]
})
export class FakeRouterModule {
}

By the way, it also tries to determine the module for abstract classes:
export abstract class AsyncTransform extends AsyncPipe implements PipeTransform { ... }

"Error: Cannot determine the module for class AsyncTransform"

Adding it to a module also doesn't work 😄.
"Cannot assign an abstract constructor type to a non-abstract constructor type."

this is happening for some classes as well.

Err: Cannot determine the module for class AppGlobalModalComponent

export class CustomGlobalModalComponent extends AppGlobalModalComponent {}

@gestj as @Phmager pointed out, dummy modules are not a fix for all cases. Additionally, they are a pretty janky fix, since you end up compiling code you don't want or need.

For our case, we have patched the issue in a different way. We moved our shared components to an npm lib, and ignored node_modules in our tsConfig. I mentioned up above that that still doesn't work, but only because we were using barrel files. If you point directly at each class you need inside node_modules, it will ignore the others. However, as soon as you point to a barrel, it throws the error for the unused files in the same barrel.

This is not ideal, since it kills all our wonderful barrel files, but at least its predictable.

Still hoping for this error to be demoted to a warning

Great work done in Angular team so far.
We're heavily using Angular in our projects and after one year of trying to get my head around all of these buzzy Angular2+ things, here is my finding :
1- Angular is massive and slow , you wanna make it fast ? use AOT and LazyLoading and gzip your stuff .
2- You wanna lazyLoad a component ? NOPE , you'd be able to one lazy load a route , so if you're app is massive but only one page, enjoy 8mg bundle size.
3- You wanna use AOT ?? AOT is buggy and hard to comply with and not use heaps of javascript/es6 features and probably rewrite lot's of your code.
4- You're using AOT fine ? Alright , now have a look at your final bundle, it's now even bigger than @angular/compiler plus your components not AOTed , well done.

5-As part of Angular2+ benefit , you now are eligible to use gzip , just in case you didn't know how to use it before , now that Angular is massive , you'll learn it better :) So there you go , they're selling gziping as an option for optimising Angular2 code :)

@xe4me Please keep discussion in this thread relevant to the issue at hand, rather than just a general rant against the framework.

build:dev in https://github.com/AngularClass/angular2-webpack-starter auto converts a string to a string array to match a function definition, build:aot shows the error. During development it appears that frequent AOT builds are necessary.

I've got the same problem, and I've found a solution, maybe it works also by you.

My scenario was the following:

I have a MapPipes.ts, containing two Pipes.

One of the Pipes was used in my module, the other wasn't. Thus, I didn't register the second in the "declaration:" part of my @NgModule decorator. The problem happened to this second.

I registered also this (despite it wasn't used), and now it works.

My suggestion is to change the angular compiler on a way that it tries to find modules only for the really used angular entities.

I've been getting this error with an abstract class that extends NgClass. Removing the inheritance seems to fix this issue, but obviously creates other issues.

@DzmitryShylovich @kirjai this is only a problem with TestComponents in a spec file if you export them. And as they should only usually be used within the same file there is no need to export them. Problem solved for me.

Honestly, this is ridiculous, I really have nothing else to say about this other than the fact that I'm many hours in and yet still unable to get something that works under JIT working with AOT (I should be clear this is only one of about a half dozen issues so far).

@cwmrowe that's fine, but what if you have one that is being reused in multiple spec files? This seems broken to be honest.

In my case I was working on 2 different projects in the same core Angular 2 app. I have 2 folders named after our clients, say some-domain.com and some-other-domain.com. The app is the exact same for the 2 projects and only differs in a little of styling and some minor custom components. Today I need to compile the app for client A, and later on I want to compile for client B. In the code it is as easy as changing 1 line of code for me:

import {CustomModules} from './some-domain.com';
// import {CustomModules} from './some-other-domain.com';

I simply uncomment whichever domain I want to compile too and it works.

We have the same problem with inheritance and abstract classes and we didn't find any solution. We have some components that extend an abstract component. In JIT everything works great but in AOT the modules for abstract components can't be found and it's not possible to declare abstract components in a module.

Currently we don't have any solution other than avoid oop design patterns and use redundant code.

@jabaa remove @Component annotation from your abstract class

@DzmitryShylovich When I remove @Component the constructor isn't inherited. I have to inject all injectables into all components instead of the abstract component. That's redundant code. When I change the constructor and the services of the abstract class, I have to adept all child components.

Currently we work around this by implementing all abstract methods with dummy methods and creating a dummy module for all abstract components. But then someone could forget to override the dummy method. That's all just a work around.

@jabaa what version do you use? constructor should be inherited regardless of @Component.

@bigjetplane I'm not sure where the problem is, but when I remove @Component I get an error that the depencies for the component couldn't be found. As far as I know DI only works for classes with Angular decorators. So when I remove the decorators, the depencies aren't injected. We use Angular 4.

@jabaa is it broken with jit or aot, or both?

@bigjetplane Here is plunker with the problem. There is an abstract class with decorator and everything works in jit. When you remove the decorator from the abstract class, the app can't render because not all dependencies could be loaded: Can't resolve all parameters for App: (?).

That's our use case. We have an abstract class with constructor und injects. We only want to override some abstract methods in the child components

The given example does not work in aot. The difference between aot and jit is a big problem for us. We are developing with jit. The production build is with aot. So we are developing a week with jit without errors and warnings and after the week we want a production build and get many errors from nowhere. I prefer a switch for jit, where I can enable aot errors. A jit build needs 10-20 seconds. An aot build needs 25 minutes.

@tbosch Any word on changing this to a warning? It seems since my last visit quite a few others have chimed in with their own anecdotes, and I was wondering if you could give us an update.

Thanks!

I also have the same issue.

In my case I was working on 2 different projects but including the common components through an internal angular library project added as dependency in package.json.

As it is a library project the unused components from component repository are throwing the below error when compiling a AOT prod build.

ERROR in Cannot determine the module for class FullPageErrorComponent in C:/users/amra6003/projects/git/refadmintoolui/n ode_modules/refcommonui/src/app/component-library/error/error.component.ts! Cannot determine the module for class SelectCountryComponent in C:/users/amra6003/projects/git/refadmintoolui/node_modul es/refcommonui/src/app/component-library/select-country/select-country.component.ts! Cannot determine the module for class DateRangeSelectorComponent in C:/users/amra6003/projects/git/refadmintoolui/node_m odules/refcommonui/src/app/component-library/date-range-selector/date-range-selector.component.ts!

Looks like i have to create a module for each component & use :(

Any fix for this issue will help a lot.

I'm also hoping for a fix of this. Apparently using stub-components for testing is intended by the Angular developers - so excluding them from the build in a clean way also needs to be possible. For now I'm using the work-around suggested by gestj (defining a fake module in which the stub-component is declared).

So, when using stub-components for testing you want to name your component with sufix spec.ts like whatever.component.spec.ts. This way tsc will ignore this files (given that it's excluded in your tsconfig) and therefore will be ignored by ngc as well.

EDIT: it turns out this is a different error, resulting from a bug in ngtools/webpack. That ticket has been opened here: https://github.com/angular/angular-cli/issues/6228


New fun on this front for my company. In a recent attempt to upgrade our systems to v2.4.10, I ended up with a couple dozen errors of this variety:

ModuleNotFoundError: Module not found: Error: Can't resolve '../../../../../../../../$_gendir/src/components/spinner/component.ngfactory'

It seems to be logging for all the components in our shared library that are not being used by the current application. This is eerily similar to the error for which I opened the ticket originally.

I'm not sure what else we can do about this though. We have tried addressing each component we need from the shared lib directly (not using any index.ts files, as those seemed to pull in every file referenced in the index) and moving all the shared lib in to node_modules.

Why does the compiler need to know about every angular component in my node_modules folder? Even if it needs to read them to build its map, it should not care about whether or not they have a module!

@swimadude66, yeah we ran into this working with our https://github.com/WealthBar/a2d3 library. Even though it provides no templated components (just directives) the library still must be built with the AoT compiler or it will not work with AoT builds when used.

@chrisnicola You are saying the library must be pre-compiled with AoT before being published? because that would imply that the library has its own modules, which seems really counter-intuitive. As is, the library is uncompiled ts files, which we pull in just like any other file in our project. The whole thing is then compiled with the @ngtools/webpack plugin to webpack.

Its worth noting that even the original error for this ticket was "fixed" on our side up to v2.1.1 by just eliminating all references to index.ts files. That fix no longer seems to work for v2.4.10.

Ah I see, yes I misread your problem. You aren't pulling in a pre-compiled shared library via NPM here, you have a local TS library in your project. Do I understand correctly now?

I do agree that it should "just work" and you are correct it definitely sounds like the same problem where it is finding components that have no module in the application. A possible solution would be to use an AoT build specific tsconfig.json that excludes the files and folders that are not needed for the AoT build.

I have managed to solve all our problems relating to this error.
The problem (and solution) appears when exporting.

We had a component that was only used for testing. It was exported from another file so that it could be reused - this caused issues when running our i18n target.

To solve it we just declared a module (make sure to also export it):

@NgModule({ declarations: [MyUnusedComponent] })
export class IgnoreModule {}

Our other component that caused an error was an unused component that hacked i18n.
It was being exported in order to be picked up by the i18n tool but that caused the same error as the other component.

@Component({
    template: `
        <div i18n="some context@@some key">some text to be translated</div>
    `
})
export class LocalisationComponent {}

Again using the IgnoreModule technique we could easily bypass it.

@NgModule({ declarations: [LocalisationComponent] })
export class IgnoreModule {}

@UtopianStorm that is not a solution. It's been mentioned above that having an "UnusedModule" is not only difficult to scale, but also creates an entire module of source files that should not be included in the distribution bundle.

@Phmager Did you ever find a work around for the abstract component issue? I am pulling my hair out.

@swimmadude66 It's not a solution in the sense that it is definitely a workaround - but it overcomes the error.
I'm not sure how it would be difficult to scale as the technique can be applied every time the problem comes up.

It will clutter your distribution bundle but will that matter? From the state of Angular I sort of assumed that it would already be littered with our spec files.
In any case it's a much more clean approach than reaching directly into the guts of the node_modules folder, don't you agree?

At least from the usecase for which I originally opened the ticket, its not even a viable workaround. It is not feasible for every partner team to maintain a list of unused shared components as we go.

Additionally, shipping essentially 2 full apps simply because the compiler is overly strict is a compromise that I am not willing to make. Angular is already pretty large, and I cannot justify shipping an entire module of unused components just to make their opinionated compiler happy.

@swimmadude66 I see. If you think adding another module makes such a big difference I better take another look at it again myself - because I was not advocating just creating one unused module to share for the entire project, but one module for every single component that I had to free from the overly strict compiler - potentially dusins.

Its worth noting that our shared codebase is quite large, so an unused module would be by far the biggest module in the app. Our situation is not 100% typical, but still within the bounds of reason to be supported i believe.

Honestly after 5 months of watching this ticket go nowhere, we are looking at other options, including just killing our shared code repo

I am facing exactly the same issue as you do, @swimmadude66 . The fact that this is not a suppressable warning is ridiculous.

Dear Angular team, is there anything you can do about this?

@DzmitryShylovich How do I exclude a mock.ts file I'm not using? I tried putting it in tsconfig.app.json, tsconfig.json, and tsconfig.ng-cli.json and none seemed to work.

Facing the same issue with the exact same use case - we use Rollup, so unused components don't even make it to the ultimate bundle.

Please do suppress this! It's a big nuisance, and is stopping work.

I just ran into this also, so damn frustrating.

@mlakmal and others, who are getting error on code like

export class CustomGlobalModalComponent extends AppGlobalModalComponent {}

Remove @Component annotation from AppGlobalModalComponent or declare AppGlobalModalComponent (if it is usable) in NgModule

I have created mock directive to use it in my tests. And get this issue with AOT compilation. I don't want to import this mock directive in plain modules. Please fix this.

I wonder if the "freq1: low" tag on this issue is due to the fact that AoT is such a spectacular pain in the ass to get working, that people aren't even bothering with it? It's a bit unbelievable that such a simple but painful issue has received essentially zero feedback from core Angular contributors.

Anyways, there is a way of excluding files that hasn't specifically been mentioned. If you have a naming pattern (e.g. .spec.ts, .abstract.ts, .stfu-aot.ts), you can create a separate tsconfig.json file for AoT and use that instead: ngc -p tsconfig-aot.json. In this file you can use the "exclude": ["./app/**/*.stfu-aot.ts"] to exclude the files. It's annoying, but it should work.

Edit: The above doesn't seem to work with abstract classes that inherit from a component. Yay :(

I just ran into this also, so damn frustrating.when build aot ,common component can't be shared in other app

some of the common cases for this issue , avoid to add @Component to your services class :

// just remove this 
@Component({
    providers: []
});
@Injectable()
export class serviceClass {}

I have a scenario where I'm injecting a service into a service. At first blush, it seems like an easy thing to implement, just add @Component. So the Angular docs should be updated to show this solution for complex services: To resolve this issue I removed @Component. In the constructor of the Service I added:
constructor(@Inject(ExampleService) private exampleService: ExampleService)

you don't need to add @Component() decorator to any service. Only @Injectable()

FWIW I have a MockXYZComponent that extends XYZComponent an app component but is only used in specs (has the same selector and therefore cannot be imported into AppModule).

Is this not a valid use-case?

@alastair-todd not sure i understand what do you mean. If you use component as component then you add @Component() decorator. If you use component as a base - only to inherit from it, but not as a component then you don't have to use decorator - but just inherit and use decorator on "successor".
About unit-testing - i cannot respond, probably you need to create special TestModule? I do not do unit-testing at the moment.

@tytskyi I understood decorator inheritance was not supported. Did that recently change?

the use-case is to mock a sub-component as below. Both need the @Component directive to pick up the selector.

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [
                AppModule
            ]
        }).overrideModule(AppModule, {
            remove: {
                declarations: [SelectionToolComponent]
            },
            add: {
                declarations: [MockSelectionToolComponent]
            }
        }).compileComponents();

Yet that generates the OP AOT compile error.

My point this is a valid use-case, in which case the AOT compile is over-zealous and/or ignoring specs as part of the project.

Maybe my solution will help somebody: I just created a dummy module which declares all the mock component. This module is not imported by anything - it just keeps the AoT compiler happy. Consequently none of the mock components are part of the compiled code. Not ideal, but problem solved.

I'd love to hear about any better solution.

This is so strange & embarrassing that this issue was opened in Dec. 2016 and still has this issue. I converted the structure of my whole app to use aot compilation. I have 4 modules which are lazy loaded and over 60 components. The compiler only complains for only couple of components (as per what the error suggests) which I'm sure are already part of declarations of one of the lazy loaded modules which is kind of strange to me.

Its even giving errors on components which are already part of some module.

Same issue

Angular's compiler looks the the file set you've handed to tsconfig - so excluding files from there should exclude them from this check.

This is really annoying :(

@alastair-todd sorry, i lost notification from you question in tons of other notifications. You are correct -
Decorator inheritance is not supported.

See answer from @robwormald

Angular's compiler looks the the file set you've handed to tsconfig - so excluding files from there should exclude them from this check.

So you could try to make a conventions for mock file names, like: selection-tool.component.mock.ts. Then exclude via

"exclude": [
    //... other excludes
    "**/*.component.mock.ts"
]

accidentally clicked the wrong button, sorry!

+8 months and it is still an issue. Same problem here ERROR in Cannot determine the module for class PasoFooterComponent

I think it is vital for the Angular developers to ignore these files.

If someone can give me tips on where I can find this code, I will be happy
to fix it myself. This is a nuisance that is very annoying. Ran into it
again yesterday.

If anybody thinks this is a feature and not bug, how about we have a flag
for this?

On Wed, 9 Aug 2017 at 2:40 AM, Leonardo Vidal notifications@github.com
wrote:

+8 months and it is still an issue. Same problem here ERROR in Cannot
determine the module for class PasoFooterComponent


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/angular/angular/issues/13590#issuecomment-321082545,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AEM6r7FOTLcicWJN3Oijw2pwKTLGL6cFks5sWM61gaJpZM4LSAwS
.

@samirotiv Do you have any reproduction?
As @robwormald said

Angular's compiler looks the the file set you've handed to tsconfig - so excluding files from there should exclude them from this check.

I had the same issue but i managed to solve it. I just looked at how ts transpiles my app for example

"tsc": "rimraf out-tsc/app && tsc -p ./src/tsconfig.app.json",

And i noticed that typescript didn't compile my lazy loaded modules because i used "files" tsconfig option

I'm getting this error on abstract class (without decorators)

Started running into this same issue recently myself.

+1 for changing error to warning.

Seems like an easy fix. Why the delay?

This is a basic requirement - leave un-referenced files.
This restriction is a problem for larger projects. Please change this to warning.

There are cases when you publish a package that supports different versions of angular. and the user is expected to choose one of them.

For example, a package that provides files for both HttpClient (Angular >= 4.3 users) and Http (Angular < 4.3 users)

Currently, ngc either compiles all files inside a source directory no matter if you use them or not! or the build fails.

What I did was this:

I have saved all my stub / mock components with an .mock.ts extension and updated the tsconfig.app.json "exclude" array like so:

...
  "exclude": [
    "test.ts",
    "**/*.spec.ts",
    "**/*.mock.ts"
  ]
...

AOT now skips compilation of these files

We're doing npm library with common components which supposed to be used not all at once and pissed by that issue during AoT compilation, damn it... Only solution atm is to create kind of UnusedComponentsModule in host project — just ridiculous! Also need NO_ERRORS_SCHEMA or it will swear about other components which can be used inside your unused components and if you will declare them, then you hit another issue where you can't declare same component in two modules (related to #10646).

My current module:

import {NgModule, NO_ERRORS_SCHEMA} from '@angular/core';
import {CommonModule} from '@angular/common';
import {ReceiverPageComponent} from 'cb-web-platform';

@NgModule({
  imports: [
    CommonModule,
  ],
  declarations: [
    ReceiverPageComponent
  ],
  schemas: [
    NO_ERRORS_SCHEMA // IMPORTANT: need that for AoT compilation
  ]
})
export class UnusedComponentsModule {
}

This really should be a warning. I am trying to share a codebase as well and am running into this issue of components not being a part of an ngmodule.
The problem here is exactly on par with an unused variable which is not an error; at most its a warning.

It's easy when it's your code. When it's a problem of some NPM angular library (some dead code), then it's really a pain in the ass :)

Can anyone explain why it can't be a warning instead of an error?

In my case, I just want to extract langs preferably from components that are connected to ngModule and just ignore those who aren't. I have one main app folder with base components and application specific folders that sometimes override components from the main app when I try to extract such overridden component with xi18n it throws Cannot determine the module for class... error that in my mind could be just ignored and extraction could be continued without using that unused component.

One thing that I can think of that could be a problem is that I still use that class that is defined in that faulty component file as a base for creating the overridden component so it needs to be compiled but I just don't need that component annotation cause as you cant use it in overrode component. At least I think you can't because I have to recreate those annotations in derived components to make them work.

@Xesenix at least it should be an option. Like determineModule = false / true. Now it's bananas.

Ich kehre zurück am 01.11.2017.

Ich werde Ihre Nachricht nach meiner Rückkehr beantworten.
In dringenden Fällen senden Sie bitte eine Kopie Ihrer E-Mail für
technische Angelegenheiten an [email protected], ansonsten an
[email protected]. Ein anderer Mitarbeiter wird sich dann Ihrer E-Mail
annehmen.

Hinweis: Dies ist eine automatische Antwort auf Ihre Nachricht "Re:
[angular/angular] Angular2 AOT compilation - "Cannot determine the module
for class (... many components which are unused)" (#13590)" gesendet am
23.10.2017 08:13:17.

Diese ist die einzige Benachrichtigung, die Sie empfangen werden, während
diese Person abwesend ist.

How is this still not fixed almost 1 year later? Pulling my hair out to get AOT to work, but this issue makes me hit a brick wall.

Thank you @rahul-sivalenka-wtc for the solution!
I was successfully able to solve my problem by excluding "**/*.mock.ts" in my tsconfig.app.json as you describe ❤️

Glad I could help 😊

I've also met the problem. But for me seems I just wrongly put the path of importing dodule

any solutions ? (cannot determine the module for component angular 5)

https://stackoverflow.com/questions/47119135/cannot-determine-the-module-for-component-angular-5

This should probably by severity3: broken. For those of us with multiple build targets and polymorphic dependencies (many use cases of which have been present above) this issue prevents builds from working without a crazy complicated built setup.

any good Solution for this problem yet? The IgnoreModule is just a workaround but not a really good solution for this problem. changing the error to a warning would be great!

Our solution was to add a transform function to @ngtools/webpack that passes files through preprocess, and ifdefing components based on various compile-time settings. Very, very ugly, but functional.

Try importing all the angular dependencies first in app.module.ts and then import the components.

` ---------------- First import dependency modules -----------------------
import { BrowserModule } from '@angular/platform-browser';
import { CommonModule } from "@angular/common";
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HttpModule } from '@angular/http';
import { ReactiveFormsModule } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

-------------Then Import service modules ------------------------

import { ApplyFormPostService } from './Services/apply-form-post.service';
import { NavBarColorService } from './Services/nav-bar-color.service';

----------------------- Finally import component modules ------------------------

import { AppComponent } from './app.component';
import { HeaderComponent } from './components/header/header.component';
import { CareerComponent } from './components/career/career.component';
import { HomeComponent } from './Components/home/home.component';`

Somehow this solved the AOT compilation error throwing Cannot determine the module for class --- in production mode

@KarthikSamyak this issue is not about people who have classes which SHOULD be in a module. This is about those of us with component libraries, which are purposefully excluded from all modules. They are unused code which should be ignored by the compiler. Instead, the compiler throws an unrecoverable error when it discovers them.

It really should be a simple change to make this error in to a warning, but for some reason it has taken OVER A YEAR and has been recently moved from pri_col1 to pri_col2 on the roadmap.

I am growing increasingly frustrated with the Angular team for their complete lack of response to this issue. Our company eventually gave up on using component libraries entirely, opting to instead copy files in manually. This is far from ideal, as we now have issues with nearly-identical, but un-shared, components.

Angular team, if you even read this issue any more, please just add a compiler setting for "ignoreUnusedComponents" and let us get on with using this framework.

Ok, I found the place https://github.com/angular/angular/blob/master/packages/compiler/src/aot/compiler.ts#L605 @tbosch hey, can you help here and say how to make that to be a warning properly? Can't see any warnings thrown in that AoT compiler, only errors. Compiler option can be added, as suggested above.

That issue is a pain on complex projects. My particular case is https://github.com/angular/angular/issues/13590#issuecomment-331820496

Our use-case is the same. We want to have a library of modules/components to create apps really easy and have the ability to replace/extend odd ones when needed.

We're having issues the other way as well: If we want to replace 1x component inside a module, we create a new module and import the components we still want in there:

import { HeaderComponent, SidebarComponent } from '@mylibs/layout';
import { FooterComponent } from './footer.component';

@NgModule({ declarations: [ HeaderComponent, SidebarComponent, FooterComponent ] })
export class MyLayoutModule { }

@NgModule({ imports: [ MyLayoutModule ] })
export class AppModule { }

The error is: `HeaderComponent is declared in 2 modules: lib/module.ts and app/module.ts
Being a warning instead would at least allow us to move forward :(

Just realised - Happy Birthday to this issue :)

One year later, and we STILL cannot get this changed to a warning. Ridiculous.

Literally just ran into this issue as well. Compiler tries to pull in a mock that is only used in tests and fails because it's not part of the main module. If it knows it doesn't need the file then it should be a warning at most.

Please fix this. Make it into a warning!
My general experience with the angular 5 aot build is less than stellar.

After some discussion https://gitter.im/angular/angular?at=5a551f565a9ebe4f756843b2 we got into conclusion that we need to create one Component per module as it seems that module is just compilation context and not a way to collect stuff together...

This is taking the size of a history book.

@Xesenix ... the context and organization are 2 parts of the whole.

Just in case anyone is still being stuck with this , you can have this script to run as postinstall script as a workaround

const replace = require('replace-in-file');
const filesToFix = [
    {
        files: 'node_modules/@angular/compiler/esm2015/compiler.js',
        from: ['throw syntaxError(messages.join(\'\\n\'));'],
                // Actually this does nothing , just leave it blank should do
        to: [`console.warn(\'Angular compiler warning\');\n\t\tconsole.warn(messages.join(\'\\n\'));`]
    }
]

filesToFix.forEach((i) => {
    try {

        const changes = replace.sync(i);
        if (changes.length > 0) {
            console.log('Modified files:', changes.join(', '));
        }
    }
    catch (error) {
        console.error('Error occurred:', error);
    }
});

The angular compiler will use the output from tsconfig, so change _tsconfig.app.json_ to exclude those files that you dont want includes
e.g
"exclude": [ "test.ts", "**/*.spec.ts", "**/*.mock.component.ts", ]

@andela-andrewmakenzi this has been suggested before, further up in this gigantic chat (absolutely no shame in not reading through the whole thing). However, issues emerge if you depend on one component in a library that uses barrel files (index.ts). If you import any component from a barrel file, the compiler tries to load all components referenced in that barrel file, and will complain that they are not in a module. This makes it difficult to package re-usable component libraries, which is basically the whole point of component architecture in the first place.

Your solution works great for people who have mock components and are getting this error when they are not running tests. But if your organization (like mine) tried to create a common component library, and pull in just the ones we need for any given project, TSC's exclude sadly will not help you.

@andela-andrewmakenzi : Your suggestion seems to help for now , the problem previously is that I have a component for unit test as ( .spec) and I would not like it to be included for AOT-build ( and maybe some mock component that I would not even like to have it in my projection ) Maybe this was somehow addressed in later version of Angular I think :)

But my case was that I have a lot of new component that was not even referenced in NgModule so for now we must have a name convention for it and exclude them in tsconfig.json , which is not very pleasant for the time being

This is really ridiculous. We have a shared NPM module exporting couple of pipes/directives and unless you import ALL it fails with this dumb error. It should really be changed to a warning and it should not break compile.

In my opinion, every component should be in its own NgModule. It's not that scary to create another NgModule for every component. (Like what @angular/material did)

I think that it is really a virtual problem. We can't see also any reason why to have anything just halfway around. Not a NgModule, not a package, not outside of the app tree ... something what looks as dead code.

So with new @angular/cli (1.7.0+) even IgnoreModule somehow does not workaround this problem.

In my opinion, every component should be in its own NgModule

Do you even try to write unit-tests? This bug is making creating test helpers kinda problematic.

@sarunint In enterprise-sized applications like the one I originally opened this ticket for, that would be hundreds of modules, with very complicated imports in order to handle dependent directives and components. This has a very simple fix: if the compiler cannot find a module for a component, throw a warning and get rid of it in tree-shaking.

The real reason this is so annoying is the fact that barrel files become more of a hazard than a boon. It's convenient to centralize your imports, but not if you are committing to including every single exported component in every app which uses your library.

@dborisenkowork I'm not sure if you didn't see it (or if it doesn't work for your use case) but the solution @rahul-sivalenka-wtc provided works perfectly.

Has anyone recently moved from angular 4 to angular 5 and noticed that some of their components which are actually being declared in modules are throwing this error?

@novologic-clay what error? The thread is long, are you referring to the original error
Angular2 AOT compilation - "Cannot determine the module for class (... many components which are unused)" ?

@andela-andrewmakenzi Yes and no. It is the same error printed when attempting to compile, but the component that it is complaining about is most certainly included in a module. I am migrating from 4.3.6 to 5.2.4, and I was not getting this error for this particular component because I updated my version of angular, and I did an AOT compile on 4.3.6 right before I started migrating as a smoke test.

@novologic-clay can you share your console errors?

... the final goal should be using tsconfig.json option "noUnusedLocals": true which eliminates everything what is unused.

@andela-andrewmakenzi

ERROR in : Cannot determine the module for class InlineAddComponent in /Users/claygarland/CatalsytConnect/frontend/Talon/src/app/core/component/input/inline-add/inline-add.component.ts! Add InlineAddComponent to the NgModule to fix it.

This is an enterprise application and there are dozens of layers of modules and imports, but this is the code that actually declares the component:

**COMPONENT:**
import {Component, Inject, Input} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material';
import {ActivatedRoute} from '@angular/router';
import {BaseForm} from '../../form/form/BaseForm';
import {FormDataService, FormDataServiceProvider} from '../../form/form/FormDataService';
import {BaseApi} from '../../../api/BaseApi';

@Component({
    selector: 'inline-add',
    templateUrl: './inline-add.component.html',
    styleUrls: ['./inline-add.component.scss'],
    providers: [
        FormDataServiceProvider
    ]
})
export class InlineAddComponent extends BaseForm {

    @Input() title = 'Entity';
    @Input() formName;

    protected service: BaseApi;

    constructor(
        protected route: ActivatedRoute,
        protected formDataService: FormDataService,
        public dialogRef: MatDialogRef<InlineAddComponent>,
        @Inject(MAT_DIALOG_DATA) public data: {
            form: string,
            title: string,
            service: BaseApi,
        },
    ) {
        super();
        this.title = data.title;
        this.formName = data.form;
        this.service = data.service;
    }

    submit() {
        super.onSubmit(res => {
            this.dialogRef.close(res.data[0]);
        });

    }

    onCancel() {
        this.dialogRef.close(false);
    }

}

**MODULE:**
import { NgModule } from '@angular/core';
import {SharedModule} from '../../../shared/shared.module';
import {InlineAddComponent} from './inline-add/inline-add.component';


@NgModule({
    imports: [
        SharedModule,
    ],
    declarations: [
        InlineAddComponent,
    ],
    exports: [
        InlineAddComponent,
    ],
    entryComponents: [
        InlineAddComponent,
    ]
})
export class FormInputsModule { }

Also of note is that when I run this application in ng serve, the component works fine.

Fake components used by tests of many real components should not be in a module; They are just inclued in TestBed of tested components.
This error is stupid. Please solve that as it is during from one year.

remove the "export" so ts will not take it to the build.

@tony-kaplan You can't do that if you have noUnusedLocals in your tsconfig, nor if you want use the code in test cases or similar.

My God.... really that no one from the core team found a suitable solution for this?
I'm using the exclude option for now, but still it's a temporary solution. Cannot think on something that would work for all the situations... but I really need it...

@gabrielalan The easy solution is turn this error in to a warning. The better solution is to add a flag which allows you to treat this as a warning or error. It's not a lack of solutions, its a lack of actually implementing either of them.

Oh boy! So much for an enterprise framework...

@atom-morgan which workaround are you talking about?

@netlander This one

Really, nothing can I do about "Cannot determine the module for class DaterangepickerDirective" error?

Anybody helps me too? After this megazord post!

I don't agree to add in the tsconfig.app.json new excludes to this Directive! How can I compile with --aot param without this issue?

My use case https://github.com/angular/angular/issues/23475
I'm creating validators library and I don't want to create module for each validator directive, all I want is just be able to bundle validator directives to npm package so user can install and import only validators that he needs to they NgModule. Also I don't want to create one module for all validators because they all will be bundled in the final bundle which is a huge waste of size.

I'm happy to create PR to fix issue.

@anjmao that's incredibly similar to the reason I opened this in the first place. As a workaround for a small library, we found that this error doesn't occur if you do not use barrel (index.ts) files. It seems that if you import 1 component/directive from an index, it tries to find a module for all the other exports of the index file.

Obviously I still believe this should be a warning, since barrel files are super convenient. However if your use case can't wait another year for this fix, you may be able to get around it like that.

Workaround that I am using for my shared library of components/directives/pipes: create a simple dummy module that references all the class declarations. You don't need to use this module in your real apps, it just has to exist on disk. Ex:

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

@NgModule({
    imports: [],
    declarations: [
        MyComponent,
        MyPipe,
        MyDirective,
        ...
    ],
})
export class DummyModule {
}

Is there a reason we still haven't fixed this problem?

Is the "Make it a warning" solution not adequate? Can a member of the core team comment on this?

In my case, things where fine with NG 5, CLI and AOT. But after upgrading to NG 6, I get similar error for an unused component. Actually the component is used through a service injected to the other component. I have many similar components constructed and used the same way. But just one has problem one upgrading to the latest NG CLI 6.0 and 6.0.1

And it just turned out, in one of the reference, I have the file reference in wrong case. I have an index.ts to export all components in the same directory. I had
export * from './dateTimePicker.component'
while it should had been:
export * from './datetimePicker.component';

Apparently NG CLI 6 is more restricted for casing even in Windows, while NG CLI 1.x is a bit relaxing.
Obviously, such restriction is good and correct, so the same codebase could be working well in Linux which is case sensitive by default.

Another use case for this:

Typescript allows you to setup multiple resolution paths with the paths variable in tsconfig.json. Ex:

{
    ...
    "paths": {
        "~src/*": ["src/*", "src-gen/*"]
    }
}

Allowing you to import things like this:

import { NgModule } from "@angular/core";
import { ExampleComponent } from "~src/example.component";

@NgModule({
    declarations: [
        ExampleComponent
    ],
})
export class ExampleModule {}

If you are generating a component inside src-gen that the developer can "override" by creating another one inside the src folder, the same error starts happening with the (now unused) component inside src-gen (which shouldn't need to be deleted, as it could be extended by the overrider).

Another potential use case:

Environment specific components. I strip them for production.

const environmentComponents = production ? [] : [
  DevOnlyComponent,
];

@NgModule({
  declarations: [
    ...environmentComponents,
  ],
})
export class ExampleModule {
}

I managed to get everything else working with environment specific components and this is what stops me. 😪

We're facing this issue when implementing a mechanism for build customization (components are exchanged for different Angular CLI projects) which looks pretty much like the scenario described by @tiagodws (including the extension of the original component).

Is there any update / opinion of a core team on this issue?

Over a year after I opened this issue, my new approach is to minimize the use of barrel files. If you use TS paths like ~components/button/component in your imports everywhere, unused imports are ignored. If that unused component is referenced in a barrel file, it will throw.

That's still not awesome for reusable libraries, since you have to access all library components with longer paths, instead of just importing from that library top level. Why, oh why can this not just be a warning?

This also seems like it could be helped by (or at least related to) tree shaking, where any code not specifically included in a module gets excluded from final bundle.

exclude option doesn't for a mock pipe:

@Pipe({ name: 'translate' })
export class MockTranslatePipe implements PipeTransform {
    transform(value: string): string {
        //Do stuff here, if you want
        return value;
    }
}

My tsconfig.app.json has excluded this file:

"exclude": [
        "test.ts",
        "**/*.mock.ts",
        "**/*.spec.ts"
    ]

However, when I run ng-xi18n --i18nFormat=xlf2 --outFile=./assets/i18n/messages.xlf, it still complains:

Cannot determine the module for class MockTranslatePipe in src/test/translate.service.mock.ts! Add MockTranslatePipe to the NgModule to fix it.

Mi problema fue que tenia el nombre de una clase en 2 componentes diferente por copiar y pegar jajaja! Después mismo error por no importar ¡Las buenas prácticas hacen al maestro muchachos! éxitos ...
Firma: Satoshi Nakamoto :v

Similar to @yuezhizizhang, I still have this problem, even after adding a glob for mocks to the tsconfig.app.json exclude path.

It's verging on infuriating that this hasn't been resolved almost two years after the initial ticket; this is a common use-case which is BREAKING builds. When writing tests, the developer should ideally create mocks for pipes, services and so on unless. If you choose to do this, your build breaks. If not, then your spec files reference the real components/pipes/etc which leads to very tightly coupled tests.

Could someone from the Angular team please suggest how to get around this? Is creating a catch-all dummy module for mocks really the only option? That's a poor hack, rather than something we should accept as best practice.

the problem persists. I also added the file I wish to skip the build (abstract class) to the exclude section of tsconfig.app.json and I still get:

Cannot determine the module for class MapElementBaseComponent in .../map-elements/map-element-base.component.ts! Add MapElementBaseComponent to the NgModule to fix it.

I've got rid of this problem after double checking imports

ср, 14 нояб. 2018 г., 15:13 Daniel Groh [email protected]:

the problem persists. I also added the file I wish to skip the build
(abstract class) to the exclude section of tsconfig.app.json and I
still get:

Cannot determine the module for class MapElementBaseComponent in
.../map-elements/map-element-base.component.ts! Add MapElementBaseComponent
to the NgModule to fix it.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/angular/angular/issues/13590#issuecomment-438641324,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AQb6kpWdkakUF8JVvea8Hy42tAnTKTuzks5uvAjvgaJpZM4LSAwS
.

When TypeScript strict, Angular importing, in AOT compilation, not used components from a library and lanching this error... Check non used components / modules has non sense...

image

By deleting the library folder where is the non used module and components, the application launch in strict-aot nicely - but surely don't make sense to delete this folder manually

This error is absolutely ridiculous. I had a module which was specifying components in an object, like so:

const landingComponents = {
    'landing-root': LandingComponent,
    'get-notified': GetNotifiedComponent,
    'typed-component': TypedComponent,
    'sticky-bar': StickyBarComponent,
};

then I tried to feed the module with declarations: Object.values(landingComponents), entryComponents: Object.values(landingComponents).

Guess what ... the AOT compiler needs to see the components listed in an array ... otherwise if I pass it any other way I get this horrible "Cannot determine the module for class".

As much as I love Angular, the AOT compiler seems like a chaotic soup of magical incantations.

It's been said a coupla times but the solution is 1 component per Module for this and am not sure if you noticed from the PRs to Angular but this was merged recently and might be of interest to this topic: https://github.com/angular/angular/pull/27481

This issue turns 2 years old today 🎉

Still, not even a word from the core team on why this couldn't be just a warning.

@tiagodws lol how long have you been waiting to post this? Did you set a reminder?

Just an FYI
My issue was same as https://github.com/angular/angular/issues/13590#issuecomment-389113560
Imports are apparently case-sensitive in AOT mode

@peterdeme ... JavaScript is case-sensitive (and paths as strings the same ... = Linux based, not Windows).

Hey guys, just popping back in for a belated 2-year issue age celebration. There is a lot of cross-talk about possible causes for people, including the include and exclude sections of tsconfig.json, so I just want to clear up what the root issue is for this thread.

If you create a library of reusable components, and add barrel files (index.ts) for easier imports, then then Angular compiler will break when you use any of them. This is because as soon as you import anything from that barrelfile (say, @shared/components), it will attempt to find the module for EVERY SINGLE COMPONENT. Even if you specify the specific components you want (e.g. import { SharedToastComponent } from '@shared/components';), the compiler will still look for the module for each and every exported component, and throw an error (not a warning) about the missing components.

Obviously, there are workarounds.

  1. Stop using barrel files. This gets messy fast, since every component has to be fully specified
  2. Use an ExtrasModule and don't use the module anywhere. This works well for people who have components only needed for testing, but not so well for people looking to pull from a component library

However, since using either of these workarounds results in the exact same output code after tree-shaking, its obvious that the other components don't NEED to be included in a used module. All I'm asking for with this 2-year old issue is to turn that error in to a more appropriate warning. Makes sense, since the compilation would still succeed if allowed to continue.

Here's hoping that in 2019 the Angular team will do something about this very old, very annoying issue. 🤞

@swimmadude66 ... you didn't mention the way of creating a real lib module and adding it to an Angular app via tsconfig.json ... like: "paths": {"ng-demo": ["./packages/ng-demo/src/index.ts"]} and using it via import like import { DemoModule } from 'ng-demo';. This way eliminates the necessity to publish the lib in a public / private npm repository but still respect the native role of that lib module. So it works transparently in your app and you don't have any problems.

Having an error on every component stub is the most annoying thing. Everyone is testing/writing specs right? So the component stub errors should be effecting everyone. I'm not saying the barrel issue is less annoying. I'm just saying not everyone is doing the barrels. But everyone should be doing specs. So the specs issue should be the greatest motivation for the core team to fix this. It is currently labeled "Frequency Low" but should be "Frequency High" because anyone doing unit testing will hit this issue.

This isn't even consistent in AOT. Angular CLI does not give errors when running with serve (which by default uses AOT) but does give errors run running with build.

I understand this isn't the Angular CLI repo, but certainly the behavior surround this is odd.

Even with the workaround of creating a mock module, now the "ng build" will fail if a UI unit test writer forgets to add a single mock component to a mock module.

Above means that UI unit testing is currently a risk element for the CI/CD deployment pipeline!

Do we really want to have to explain to people higher in the food chain that Angular unit testers can break entire deployment builds with a single trivial omission? Nope. People that manage Angular developers and who make decisions on which framework to use for the next project should not be wondering about this sort of thing.

As a stopgap: why not just make the error that appears in "ng build" more informative for test writers: i.e. add additional text to the effect of "if this is a mock component used in testing: add it to a mock module in that file as per (this url)"

How your average friendly Angular dev writing unit tests got here:

a) IMHO it is a DRY-code practice to create a "helper" file to place mock components, services, etc. that all .spec files use. However this practice runs the tester smack into this bug scenario.

b) All the .spec files can import this "helper" file without any need of a "mock module" that has no relevance to actual test code. Mock components are useful as-is, without membership in a mock module that has no role in a spec's test environment at all.

Sure the workaround is trivial...but just finding this bug via google search, reading and digesting the thread and helpful workarounds was not.

I just add this to the end of helper file which contains the mock components (among other things):

/*
  mock components
  !! Each mock component added to this file *must* be added to the "MockTestModule", see below !!
*/
@Component({
  selector: 'app-mock-component',
  template: '<span>mock widget</span>'
})
export class MockComponent {}

/*
  This is an unused module to resolve the ng build error:
    'ERROR in : Cannot determine the module for class MockComponent
    in C:/code/myRepo/src/assets/test/test-resources.ts!
    Add MockComponent to the NgModule to fix it.'

  Reference: https://github.com/angular/issues/13590

  Each mock component added to this file *must* be added to the "MockTestModule"
*/
@NgModule({
  declarations: [ MockComponent ],
})
export class MockTestModule {}

Note that the above file in reality is quite large...the "MockTestModule" is buried way down at the end of the helper file...

...I hope we don't have to write a package.json entry for "ng build" that intercepts the call, and inserts a console message "hey UI unit testers, did you add your mock component to the mock module?" nudge.

Here's what solved the problem for me. My structure is as follows:

├── icons.module.ts
├── index.ts
├── icon
│   ├── icon.component.html
│   ├── icon.component.ts
│   └── icon.module.ts
└── icon-indicator
    ├── icon-indicator.component.html
    ├── icon-indicator.component.ts
    └── icon-indicator.module.ts

In icons.module.ts I had:

import { IconComponent } from './icon/icon.component';
import { IconIndicatorComponent } from './icon-indicator/icon-indicator.component';

export { IconIndicatorComponent, IconComponent };

@NgModule({
  /* this was all fine */ 
})
export class IconsModule {}

The index.ts had:

export * from './icons.module';

I am assuming the problem was that the compiler hadn't parsed the icon and icon-indicator modules before encountering the corresponding components and thus threw the Cannot determine the module for class error. This project is ng 5. I only got the error when consuming it in an ng 7 project.

The solution is to move the exports one level down. So I removed the export statement in icons.module.ts and moved them to:

icon.module.ts:
export { IconComponent };
...

icon-indicator.module.ts:
export { IconIndicatorComponent };
...

and adjusted index.ts:

export * from './icons.module';
export * from './icon/icon.module';
export * from './icon-indicator/icon-indicator.module';

Hope this helps someone.

I think new ivy renderer will solve quite few issues with AOT. As you can see from pull requests and issues angular team is focusing on ivy so there is no point of doing something about this issue on angular 6.

I think new ivy renderer will solve quite few issues with AOT.

I love hearing this on every issue.

I'm also having this issue with angular 7.2.0 and angular-cli 7.3.0

ERROR in : Cannot determine the module for class ModalMockComponent in /Users/user/repos/angular-skeleton/src/app/shared/modal/modal.component.mock.ts! Add ModalMockComponent to the NgModule to fix it.
Cannot determine the module for class TranslatePipeMock in /Users/user/repos/angular-skeleton/src/app/shared/pipes/translate.pipe.mock.ts! Add TranslatePipeMock to the NgModule to fix it.

E.g. I have a TranslatePipe and a TranslatePipeMock inside my Shared Module. TranslatePipe is included in the module, the mock pipe is not.
translate.pipe.mock.ts is for unit testing purpose, so I can just import this file to each unit test.

But now my build fails
ng build --prod

How do we fix this?

Atm i have a workaround which solves it

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/app",
    "types": []
  },
  "exclude": [
    "test.ts",
    "**/*.spec.ts",
    "**/*.mock.ts"
  ]
}

It is hard to determine the current status of this issue from a brief walk-through the comments. I agree this is a problem (poor design). What is the plan to fix it? Is it easy or difficult?

@rrmayer the status of this issue is most likely just "wait for ivy", as with almost all "current" issues.

We just want this to be changed from "error" to "warning", so our projects will actually compile... Is that so hard?

@Terrafire123 ... there could be many relations with testing or build tooling for example, which are based actually on the fact that this case leads to the error, so the change to the warning could be a serious problem.

I have no hope that it's gonna be fixed for current compiler :D

Maybe we should at least have the option to show either an error or a warning. Builds breaking because of components not being a part of a module on purpose is pretty annoying.

Unused imports can cause this error..

import { UnusedImportComponent } from "./used-somewhere-else-or-not.component";

Seems like the 'export' keyword next to the class determines in some way that the class which has the @Component decorator applied to, has to be included in some module. Whether you import the component's class and declare directly in tests or declare in e.g. CoreMocksModule and then import the module, it all doesn't matter.

There is a workaround though! Let's say that we have our stub component declared like this:

@Component({
  selector: 'app-user-stub-component',
  template: ''
})
export class UserStubComponent {}

We have to remove the 'export' keyword but in some way we still have to export the component to use it in test/test module. Do it like this:

@Component({
  selector: 'app-user-stub-component',
  template: ''
})
class UserStubComponent {}

export default UserStubComponent;

Now, everywhere when you import the stub, we have to avoid brackets like follows:
import UserStubComponent from 'path'

Hope it works. For me it solves AOT compilation problems.

In my case , I fixed it . Problem was with casing. I used uppercase for folders but the auto import of VS code imported the path with lower case.

@renilbabu03 JS is case sensitive.

In my case, I fixed it for my unit tests, where I mocked the translate pipe.

I changed the export class to default export:

import { PipeTransform, Pipe } from '@angular/core';

@Pipe({
  name: 'translate'
})
class TranslatePipeMock implements PipeTransform { // <-- NOT: "export class TranslatePipeMock implements PipeTransform"
  public name = 'translate';

  public transform(query: string): any {
    return query;
  }
}

export default TranslatePipeMock;

Any fixes for this ?
I tried export default <class> but when I run ng serve --aot, it throws an error: Unexpected value 'null' exported by the module .

It's very frustrating.

@redplane Why do you want to do that? I mean the default export.

Unless I import an exported asset, why does Angular care if the file exists?

More often than not I'm refactoring a component or removing components and just want to comment out the stale component references like I did back in the CommonJS days. This would be plenty safe enough since I never use barrel files cuz I've been burned too many times on that front, and having Angular force me to commit to physically removing the assets from my project is just unacceptable when I'm neck deep in a prototyping phase...

I'm stuck in Angular 6 because I'm the only developer working on this project and it would be hell to refactor things to get up to the latest stable tools in the midst of having to ship new features... so at the very least it would be great if Angular 6+ could be patched with a compiler flag for disabling this behavior...

In my case, I am having an angular library project setup. In one of my components inside the library, I have declared few enums, in order to use these enums in my application project I was importing with a relative path to the projects directory in my application root.

This is the reason why angular compiler wanted to have my library component to be declared in any of the ngModules of the application project.

To solve this error I have to declare my enums into public-api.ts file as well as use them in application project with a direct import from the library and not with a relative import path.

For example:
Library Project Name: components-lib
Application Project Name: demo-app

To use any interfaces, classes, enums, etc declared inside the library project import them with a direct path:

import { SearchEnum } from 'components-lib';

and don't do
import { SearchEnum } from '../../../projects/components-lib/path-to-your-component';

I hope this helps someone in the future, as I have spent hours finding this myself.

Having an issue to maintain compatibility for a library built with ng 9 that I wanted people running ng 8 to be able to use.

I offer through the library some utility classes that your components can extend upon. In that chain of parent classes some of these are abstract and with ng 9 need to have a @Directive({ selector: 'random' }) to be compatible with ng 8.

So I nearly got away with it... BUT:

Cannot determine the module for class NgxSubFormComponent in /........./node_modules/ngx-sub-form/ngx-sub-form.d.ts! Add NgxSubFormComponent to the NgModule to fix it.`

I do not expose any module within the library, people are just supposed to extends on the classes we offer. But I don't want them to have to imports the parent classes in their modules (wouldn't make any sense).

So I'm stuck and I'll just cut a breaking change release requiring people to upgrade to ng 9 instead of having backward compat

Hey all, sorry for the silence on this issue.

ngc in View Engine, by design, generates ngfactory files for every component in the "compilation" - that is, the full set of TS files defined by your tsconfig. This is how TypeScript
itself works - it compiles all the files defined by a tsconfig. ngc is just doing extra processing on top of that.

So if an @Component is present in that compilation and ngc can see it (meaning it's top-level and exported), ngc will try to compile it. There is no way around this other than to ensure ngc doesn't compile the file which declares the component in the first place.

The correct way to do that is to scope your tsconfig. For example, you might have a top-level tsconfig for your editor, which includes all files, and then a tsconfig.app.json for your application compilation specifically, which inherits from the editor config and excludes spec files. Only the app config would be compiled with ngc.

Projects (each tsconfig is a "project") should be structured such that a component and its module are always compiled together.

In Ivy the same rules still largely apply, with several small differences:

  • By default Ivy will try to compile _any_ @Component, regardless of whether it's exported.
  • It's no longer an error, in Ivy, to have a component without a module. However, you will still get template type-checking errors if that component tries to use other components/directives in its template, since without a module nothing else will be visible to that component.
  • It's possible to tell the Ivy compiler to ignore a particular component or module and leave it until runtime, by adding a jit: true flag to the decorator.

@alxhub I'm glad to hear it is no longer an error!

I understand that ngc will try and compile anything that tsc would, and that tsc will compile anything within its scope. That being said, the requirement that a component be added to a module is 100% an angular concern, so removing it from your typescript project scope feels like kicking the can down the road. Additionally, with patterns like barrel files being common, it can be difficult to truly remove a single file from compilation, without ALSO removing it from any re-exports along the way. This is why the calls to simply "exclude those components" above were often met with dissatisfaction.

Regarding the remaining limitation with ivy (the template errors on components without modules), is it too much to ask for those to be warnings as well? I understand that may be more difficult (or impossible) if type-checking occurs before the component is identified as module-less, but it seems to me like a warning along the lines of Warning: ExampleUnusedComponent does not belong to an NgModule, and will be excluded from the output accurately captures the idea that the component (and any others referenced by it) will not be included unless they are added to an ngModule.

Overall, I am very excited to see movement on this issue, and look forward to trying out my original use case with the new changes in the ivy compiler!

Was this page helpful?
0 / 5 - 0 ratings