Angular: Angular2 AOT 编译 - “无法确定类的模块(......许多未使用的组件)”

创建于 2016-12-20  ·  183评论  ·  资料来源: 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

当前行为
编译器检测到我的工作区中未使用的组件/管道/指令,这会为每个文件引发错误Cannot determine the module for class (...) 。 它停止编译,并且似乎不可配置。 这是一个问题,因为我需要在我的工作区中拥有这些文件,但在生成的应用程序中不需要它们(合作伙伴实现需要不同的共享组件组合)。 这对于在 webpack 加载器中进行编译尤其令人沮丧,它应该能够提供包含的文件列表,而不管工作空间如何。

预期行为
我希望这些错误是警告,和/或能够被编译器选项静音。 或者,对于 webpack,您可以允许插入文件列表,以便 webpack 可以提供 require 链中的所有文件,而不是工作区中的所有文件。

使用说明最小化重现问题
无法在 plunkr 中演示,因为它使用 JIT。

  1. 创建一个基本的 Angular 应用程序,它使用一个组件 AppComponent 引导 ngModule
  2. 让这个应用程序进入一个可以被 AOT 编译的状态(用一个 hello world 应该很容易)
  3. 将组件添加到目录结构中,但不要在代码中的任何位置引用它。
  4. 再次尝试 AOT 编译。 您将收到警告Cannot determine the module for class

改变行为的动机/用例是什么?
我的公司有一个自己的基础应用程序,我们的合作伙伴使用该应用程序的修改版本作为他们自己的应用程序。 我们不是单独维护所有合作伙伴,而是使用通用通用组件的共享库,根据需要导入。 对于我们的基础应用程序,一切都很好,因为我们使用了每个组件。 对于合作伙伴,我们不能使用 AOT,因为共享 npm 包中的某些组件没有声明的模块。

请告诉我们您的环境:
发生在所有设备上,但当前的测试设置是:
视窗 10
VS 代码
Cmder(bash 终端)

  • 角度版本:
    v2.1.0(虽然我们也在 2.3.1 中测试过

  • 浏览器:全部 - 这是编译器问题,与浏览器无关

  • 语言:打字稿

  • 节点(针对 AoT 问题):节点 v6.3.0
P5 compiler NgModule ve low error messages triage #1 confusing

最有用的评论

@DzmitryShylovich对于您正在使用的组件需要成为模块的一部分是有意义的。 但就编译器而言,这些文件应该无关紧要。 它们是碰巧包含组件的未使用、未引用的 .ts 文件。

所有183条评论

无法确定类的模块

组件必须是模块的一部分。 这是有意的。
我会说这是一个功能请求。

@DzmitryShylovich对于您正在使用的组件需要成为模块的一部分是有意义的。 但就编译器而言,这些文件应该无关紧要。 它们是碰巧包含组件的未使用、未引用的 .ts 文件。

@swimmadude66你可以在 tsconfig 中排除未使用的文件

@DzmitryShylovich你可以,但桶文件使这复杂化。 如果一个类在桶文件中重新导出,我也必须忽略桶文件,这可能会导致我确实需要该桶的类出现问题。

编译器应该尝试编译而不是绝对必须编译,这似乎很奇怪。 除了摇树之外,我希望编译器只想处理给它的文件或明确链接到给定文件的文件。

编译器应该尝试编译而不是绝对必须编译,这似乎很奇怪。

这就是编译器的工作方式......

JIT 编译工作的事实应该很好地证明编译器不需要这些文件。 它会抛出错误而不是警告文件,这些文件可以被排除而不会造成任何伤害。

你可以整天跟我谈论编译器是如何工作的,但这在一些基本的用例中是一个真正的问题。 我只是要求某种方法来至少抑制错误并继续自担风险。

我的同事正在尝试删除任何可能阻止我们使用一揽子排除的桶文件,但我想请您看看我最初针对 @ngtools/webpack 打开的问题,其中另一个用户遇到了同样的错误仅在其测试中引用的组件。 https://github.com/angular/angular-cli/issues/3636

编译器知道我没有要求它编译的文件,并且它会在可恢复的情况下抛出不可恢复的错误。 就这么简单。

我不明白为什么您在同一目录中有未包含在项目中的组件。
我确实认为这可能是一个功能请求,但目前这是编译器的工作方式,还说“它在 JIT 中工作”不足以认为它应该在 AOT 中工作。
我认为您需要做的是将这些文件从您的基本应用程序中分离到模块中,然后通过某种包管理器将它们导入,这样它就可以解决您的问题,整理您的目录并使其更易于从各个方面进行维护

@Toxicable未使用的文件位于库样式的 npm 模块中。 通常理想的用例是这样的:

在@project/angular(我们的共享代码 npm 模块)中,我们拥有制作基础应用程序和与后端平台通信所需的所有组件、管道、指令和服务。 我们的合作伙伴想要一个看起来相似但使用不同主页或添加了一些新组件的应用程序。 但是,大多数其他页面将是相同的,连接到我们平台所需的所有服务可能都是相同的。

我们最大化可重用代码的方法是让每个合作伙伴创建模块,并从 npm 模块中导入新片段和共享片段的组合。 我的新HomeModule可能具有如下导入:

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

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

这然后在 AOT 中爆炸说: Cannot determine the module for class OverviewComponent因为我们没有使用来自 @project/angular 的 OverviewComponent。

由于实际上没有文件指向@project/angular/components/home/overview/component.ts ,我不希望编译器关心它是未使用的。 但是由于该文件存在于我们项目的 node_modules 目录中,因此编译器会找到它,抱怨并死掉。

至于 JIT 工作 !== AOT 工作,基础应用程序与 AOT 一起工作,并且概念验证合作伙伴的变化非常小。 我并不是说在 JIT 中工作的所有东西都应该在 AOT 中工作,但我有充分的理由相信这应该。

我有另一个例子,这个当前的行为没有意义 - 测试。
说,我有一个功能目录some-feature ,其中有some-feature.component.tssome-feature.component.spec.ts
该组件使用内容投影,因此我想通过在我的some-feature.component.spec.ts文件中创建一个测试组件来测试该功能,该文件在视图中使用some-feature组件,如下所示:

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

然后我在我的测试模块中使用这个组件

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

一切都有效且很棒,直到我使用 angular-cli 运行ng build --prod --aot时,它会抛出:
Cannot determine the module for class TestAppComponent

我认为 AOT 不应该关心.spec文件..

一般规则是:ngc 将编译 tsc 编译的所有内容。 它会尝试编译它找到的每个组件。 但是,Angular 无法编译没有相关模块的组件。

不过,我们可以将此错误更改为警告。

我也有测试包装器组件,它们仅用于测试,导致 AOT 爆炸,如此处所述。 如果 AOT 可以忽略所有满足通配符表达式(如 TestComponent* 等)的组件,那就太好了。

好的,这里有更多信息。 我们似乎确实为我们的案例找到了解决方法(不修复 testWrapper 案例)。 在我们的案例中,真正的问题似乎是我们的桶文件。 当从桶文件中导入任何东西时,它会遵循桶重新发出的所有东西的链。 由于我们是从顶层PROJECT/components中提取我们的组件,因此它正在分析所有组件,而不仅仅是我们想要的那个。 作为警告,这仍然可能会更好,但我可以更好地理解编译器为什么关心这些组件。

看到同样的错误:

$ ./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 厨房水槽:http: //ng2.javascriptninja.io
和来源@ https://github.com/born2net/Angular-kitchen-sink
问候,

肖恩

i18 不应该遍历整个项目结构,而是查看使用的声明。

我试图清理没有使用的指令,兔子洞变得更深了:

$ ./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'.

让我补充一点,使用 angular-cli 和 angular-compiler 一切正常,所以它只是 i18 不喜欢我的项目。

参考(漂亮而干净的设置): https ://github.com/born2net/ng-skeleton

问候,

肖恩

注释掉的组件的相同错误..开发阶段未使用和注释掉的组件只是不处理的有用步骤

// two comments aot read:

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

@kirjai ngc 编译源目录中的所有文件。 无论您是否导入它都没有关系。

@DzmitryShylovich我理解,我只是说在这种情况下我认为 AOT 根本不应该关心这个文件。在我看来,在 AOT 编译期间跳过 .spec 文件是要走的路。 但很明显,有什么东西阻止了团队这样做,我理解。

作为替代方案,样式指南可能不建议将 .spec 文件与为其编写测试的实体放在同一目录中?

由于我们的测试代码和 AOT 相结合,我也遇到了这个错误消息(以及其他一些错误消息)。

我可以推荐这篇文章。 它解释了如何引发某些错误消息以及如何修复/解决它们。

考虑到如果人们遵循官方测试指南并使用 AOT 构建他们的应用程序,他们会偶然发现这个确切的问题,您可能想要更新该指南?

(如果有人寻找有关RouterLinkStubDirective的答案)
_您可以通过添加“虚拟”模块来修复它:_

/**
 * 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 {
}

顺便说一句,它还尝试确定抽象类的模块:
export abstract class AsyncTransform extends AsyncPipe implements PipeTransform { ... }

“错误:无法确定 AsyncTransform 类的模块”

将其添加到模块中也不起作用😄。
“无法将抽象构造函数类型分配给非抽象构造函数类型。”

这也发生在某些课程上。

错误:无法确定类 AppGlobalModalComponent 的模块

export class CustomGlobalModalComponent extends AppGlobalModalComponent {}

@gestj正如@Phmager指出的那样,虚拟模块并非适用于所有情况。 此外,它们是一个非常笨拙的修复,因为您最终编译了您不想要或不需要的代码。

对于我们的案例,我们以不同的方式修复了这个问题。 我们将共享组件移至 npm 库,并在 tsConfig 中忽略了 node_modules。 我在上面提到过这仍然不起作用,但这仅仅是因为我们使用了桶文件。 如果您直接指向 node_modules 中需要的每个类,它将忽略其他类。 但是,一旦您指向一个桶,它就会为同一桶中未使用的文件引发错误。

这并不理想,因为它杀死了我们所有美妙的桶文件,但至少它是可以预测的。

仍然希望将此错误降级为警告

到目前为止,Angular 团队完成了出色的工作。
我们在我们的项目中大量使用 Angular,经过一年的努力让我了解所有这些 Angular2+ 的嗡嗡声,这是我的发现:
1- Angular 又大又慢,你想让它快点吗? 使用 AOT 和 LazyLoading 并 gzip 你的东西。
2-你想lazyLoad一个组件? 不,你可以懒加载一个路由,所以如果你的应用程序很大但只有一页,享受 8mg 包大小。
3-你想使用AOT?? AOT 有问题,难以遵守,不使用大量 javascript/es6 功能,可能会重写很多代码。
4-您使用AOT好吗? 好吧,现在看看你的最终包,它现在甚至比 @angular/compiler 加上你的组件还没有 AOTed ,做得好。

5-作为 Angular2+ 优势的一部分,您现在有资格使用 gzip ,以防您以前不知道如何使用它,现在 Angular 很庞大,您会更好地学习它 :) 所以你去吧,他们'正在出售 gziping 作为优化 Angular2 代码的选项 :)

@xe4me请继续在此线程中与手头的问题相关的讨论,而不仅仅是对框架的一般咆哮。

https://github.com/AngularClass/angular2-webpack-starter中的build:dev自动将字符串转换为字符串数组以匹配函数定义, build:aot显示错误。 在开发过程中,似乎需要频繁的 AOT 构建。

我遇到了同样的问题,我已经找到了解决方案,也许它也适用于你。

我的情况如下:

我有一个包含两个管道的 MapPipes.ts。

我的模块中使用了一个管道,另一个没有。 因此,我没有在我的@NgModule装饰器的“声明:”部分中注册第二个。 问题发生在这一秒。

我也注册了这个(尽管它没有被使用),现在它可以工作了。

我的建议是更改角度编译器,使其仅尝试为真正使用的角度实体查找模块。

我在extends NgClass的抽象类中遇到了这个错误。 删除继承似乎可以解决这个问题,但显然会产生其他问题。

@DzmitryShylovich @kirjai如果您导出它们,这只是规范文件中TestComponents的问题。 而且由于它们通常只能在同一个文件中使用,因此无需导出它们。 问题为我解决了。

老实说,这太荒谬了,除了我已经工作了很多小时但仍然无法获得在 JIT 下与 AOT 一起工作的东西(我应该清楚这只是其中之一)到目前为止大约有六个问题)。

@cwmrowe很好,但是如果您有一个在多个规范文件中重复使用怎么办? 老实说,这似乎被打破了。

就我而言,我在同一个核心 Angular 2 应用程序中从事 2 个不同的项目。 我有 2 个以我们的客户命名的文件夹,比如some-domain.comsome-other-domain.com 。 该应用程序与 2 个项目完全相同,仅在样式和一些小的自定义组件上有所不同。 今天我需要为客户端 A 编译应用程序,稍后我想为客户端 B 编译。在代码中,我只需更改 1 行代码即可:

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

我只需取消注释我也想编译的任何域,它就可以工作。

我们在继承和抽象类方面有同样的问题,我们没有找到任何解决方案。 我们有一些扩展抽象组件的组件。 在 JIT 中一切正常,但在 AOT 中找不到抽象组件的模块,并且无法在模块中声明抽象组件。

目前,除了避免使用 oop 设计模式和使用冗余代码外,我们没有任何解决方案。

@jabaa从抽象类中删除@Component注释

@DzmitryShylovich当我删除@Component时,构造函数不会被继承。 我必须将所有可注射剂注入所有组件而不是抽象组件。 那是多余的代码。 当我更改抽象类的构造函数和服务时,我必须熟悉所有子组件。

目前,我们通过使用虚拟方法实现所有抽象方法并为所有抽象组件创建一个虚拟模块来解决此问题。 但是有人可能会忘记覆盖虚拟方法。 这一切都只是一个解决办法。

@jabaa你用的是什么版本? 无论@Component如何,都应该继承构造函数。

@bigjetplane我不确定问题出在哪里,但是当我删除@Component时,我收到一个错误,即找不到组件的依赖项。 据我所知,DI 仅适用于带有 Angular 装饰器的类。 因此,当我删除装饰器时,不会注入依赖项。 我们使用 Angular 4。

@jabaa是否被 jit 或 aot 或两者兼而有之?

@bigjetplane这是问题所在。 有一个带有装饰器的抽象类,一切都在 jit 中工作。 当您从抽象类中删除装饰器时,应用程序无法呈现,因为并非所有依赖项都可以加载: Can't resolve all parameters for App: (?).

这就是我们的用例。 我们有一个带有构造函数和注入的抽象类。 我们只想覆盖子组件中的一些抽象方法

给定的示例在 aot 中不起作用。 aot 和 jit 的区别对我们来说是个大问题。 我们正在使用 jit 进行开发。 生产版本使用 aot。 因此,我们正在使用 jit 开发一周,没有错误和警告,一周后我们想要一个生产构建并从无处获得许多错误。 我更喜欢 jit 的开关,我可以在其中启用 aot 错误。 一个 jit 构建需要 10-20 秒。 一个 aot 构建需要 25 分钟。

@tbosch关于将其更改为警告的任何消息? 自从我上次访问以来,似乎有不少人附和了他们自己的轶事,我想知道你是否可以给我们一个更新。

谢谢!

我也有同样的问题。

在我的情况下,我正在处理 2 个不同的项目,但包括通过一个内部 angular 库项目添加为 package.json 中的依赖项的公共组件。

由于它是一个库项目,因此组件存储库中未使用的组件在编译 AOT 产品构建时会引发以下错误。

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!

看起来我必须为每个组件创建一个模块并使用:(

任何解决此问题的方法都会有很大帮助。

我也希望能解决这个问题。 显然,使用 stub-components 进行测试是 Angular 开发人员打算使用的——因此以干净的方式将它们从构建中排除也是可能的。 现在我正在使用 gestj 建议的解决方法(定义一个声明存根组件的假模块)。

因此,当使用存根组件进行测试时,您希望使用后缀spec.ts来命名组件,例如whatever.component.spec.ts 。 这样 tsc 将忽略这些文件(假设它已被排除在您的 tsconfig 中),因此也会被 ngc 忽略。

编辑:事实证明这是一个不同的错误,由 ngtools/webpack 中的错误引起。 该票已在此处打开: https ://github.com/angular/angular-cli/issues/6228


在这方面为我的公司带来新的乐趣。 在最近尝试将我们的系统升级到 v2.4.10 时,我遇到了几十个此类错误:

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

它似乎正在记录我们共享库中当前应用程序未使用的所有组件。 这与我最初打开票证的错误非常相似。

不过,我不确定我们还能做些什么。 我们已经尝试直接从共享库中处理我们需要的每个组件(不使用任何index.ts文件,因为这些文件似乎会拉入索引中引用的每个文件)并将所有共享库移动到 node_modules。

为什么编译器需要知道我的node_modules文件夹中的每个角度组件? 即使它需要阅读它们来构建它的地图,它也不应该关心它们是否有一个模块!

@swimadude66 ,是的,我们在使用我们的https://github.com/WealthBar/a2d3库时遇到了这个问题。 即使它没有提供模板化组件(只是指令),该库仍然必须使用 AoT 编译器构建,否则在使用时它将无法与 AoT 构建一起使用。

@chrisnicola您是说该库必须在发布之前使用 AoT 进行预编译? 因为这意味着图书馆有自己的模块,这似乎真的违反直觉。 照原样,该库是未编译的 ts 文件,我们像项目中的任何其他文件一样将其拉入。 然后用@ngtools/webpack 插件将整个东西编译到webpack。

值得注意的是,即使是这张票的原始错误,在 v2.1.1 之前,我们也已通过删除对 index.ts 文件的所有引用来“修复”。 该修复似乎不再适用于 v2.4.10。

啊,我明白了,是的,我误读了您的问题。 您不是在这里通过 NPM 拉入预编译的共享库,您的项目中有一个本地 TS 库。 我现在理解正确了吗?

我确实同意它应该“正常工作”,而且你是对的,这听起来绝对是同一个问题,它正在寻找应用程序中没有模块的组件。 一种可能的解决方案是使用 AoT 构建特定的tsconfig.json ,它排除了 AoT 构建不需要的文件和文件夹。

我已经设法解决了与此错误有关的所有问题。
导出时出现问题(和解决方案)。

我们有一个仅用于测试的组件。 它是从另一个文件中导出的,以便可以重复使用——这在运行我们的 i18n 目标时引起了问题。

为了解决这个问题,我们刚刚声明了一个模块(确保也导出它):

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

我们另一个导致错误的组件是一个未使用的组件,它入侵了 i18n。
它被导出以便被 i18n 工具拾取,但这会导致与其他组件相同的错误。

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

再次使用 IgnoreModule 技术,我们可以轻松绕过它。

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

@UtopianStorm这不是解决方案。 上面已经提到,拥有“UnusedModule”不仅难以扩展,而且还会创建不应包含在分发包中的整个源文件模块。

@Phmager你有没有找到解决抽象组件问题的方法? 我正在拔头发。

@ swimmadude66从某种意义上说,它绝对是一种解决方法,这不是解决方案-但它克服了错误。
我不确定每次出现问题时都可以应用该技术,因此很难扩展。

它会使您的分发包混乱,但这有关系吗? 从 Angular 的状态来看,我有点假设它已经被我们的规范文件乱扔了。
无论如何,这比直接进入 node_modules 文件夹的内容要干净得多,您不同意吗?

至少从我最初打开票证的用例来看,它甚至不是一个可行的解决方法。 对于每个合作伙伴团队来说,随时维护未使用的共享组件列表是不可行的。

此外,仅仅因为编译器过于严格而交付基本上 2 个完整的应用程序是我不愿意做出的妥协。 Angular 已经相当大了,我不能证明仅仅为了让他们固执己见的编译器满意而发布一个包含未使用组件的整个模块是合理的。

@swimmadude66我明白了。 如果您认为添加另一个模块会产生如此大的不同,我最好自己再看一遍 - 因为我并不是主张只为整个项目创建一个未使用的模块来共享,而是为我必须释放的每个组件创建一个模块从过于严格的编译器 - 潜在的dusins。

值得注意的是,我们共享的代码库非常大,因此未使用的模块将是迄今为止应用程序中最大的模块。 我们的情况不是 100% 典型的,但我相信仍然在得到支持的理由范围内。

老实说,在看了这张票 5 个月后,我们正在寻找其他选择,包括杀死我们的共享代码仓库

我面临与您完全相同的问题, @swimmadude66 。 这不是一个可抑制的警告这一事实是荒谬的。

亲爱的 Angular 团队,你有什么可以做的吗?

@DzmitryShylovich如何排除我不使用的mock.ts文件? 我尝试将其放入tsconfig.app.jsontsconfig.jsontsconfig.ng-cli.json中,但似乎都没有。

使用完全相同的用例面临同样的问题 - 我们使用 Rollup,因此未使用的组件甚至无法进入最终捆绑包。

请压制这个! 这是一个大麻烦,并且正在停止工作。

我也遇到了这个问题,好郁闷。

@mlakmal和其他人,他们在代码上遇到错误,例如

export class CustomGlobalModalComponent extends AppGlobalModalComponent {}

从 $#$ AppGlobalModalComponent $#$ 中删除@Component注释或在NgModule中声明AppGlobalModalComponent (如果可用)

我创建了模拟指令以在我的测试中使用它。 并通过 AOT 编译来解决这个问题。 我不想在普通模块中导入这个模拟指令。 请解决这个问题。

我想知道这个问题上的“freq1:low”标签是否是因为 AoT 是一个让工作非常痛苦的事实,以至于人们甚至都不在乎它? 令人难以置信的是,这样一个简单但痛苦的问题却从核心 Angular 贡献者那里得到了几乎为零的反馈。

无论如何,有一种方法可以排除没有特别提到的文件。 如果您有一个命名模式(例如.spec.ts.abstract.ts.stfu-aot.ts ),您可以为 AoT 创建一个单独的tsconfig.json文件并使用它来代替: ngc -p tsconfig-aot.json 。 在此文件中,您可以使用"exclude": ["./app/**/*.stfu-aot.ts"]排除文件。 这很烦人,但它应该工作。

编辑:以上似乎不适用于从组件继承的abstract类。 耶 :(

我也遇到了这个,太令人沮丧了。构建aot时,公共组件无法在其他应用程序中共享

此问题的一些常见情况,请避免将@Component添加到您的服务类:

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

我有一个将服务注入服务的场景。 乍一看,这似乎是一件容易实现的事情,只需添加@Component。 因此,应该更新 Angular 文档以显示针对复杂服务的此解决方案:为了解决此问题,我删除了 @Component。 在我添加的服务的构造函数中:
constructor(@Inject(ExampleService) private exampleService: ExampleService)

您不需要将@Component()装饰器添加到任何服务。 只有@Injectable()

FWIW 我有一个MockXYZComponent扩展XYZComponent一个应用程序组件,但仅在规范中使用(具有相同的选择器,因此不能导入AppModule )。

这不是一个有效的用例吗?

@alasair-todd 不确定我明白你的意思。 如果将组件用作组件,则添加@Component()装饰器。 如果您使用组件作为基础 - 只是从它继承,而不是作为组件,那么您不必使用装饰器 - 只需在“继任者”上继承和使用装饰器。
关于单元测试 - 我无法回应,可能您需要创建特殊的 TestModule? 我目前不进行单元测试。

@tytskyi我知道不支持装饰器继承。 最近有变化吗?

用例是模拟一个子组件,如下所示。 两者都需要@Component指令来选择选择器。

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

然而,这会产生 OP AOT 编译错误。

我的观点是这是一个有效的用例,在这种情况下,AOT 编译过于热心和/或忽略了作为项目一部分的规范。

也许我的解决方案会对某人有所帮助:我刚刚创建了一个虚拟模块,它声明了所有模拟组件。 这个模块不是由任何东西导入的——它只是让 AoT 编译器满意。 因此,没有任何模拟组件是编译代码的一部分。 不理想,但问题解决了。

我很想听听任何更好的解决方案。

这太奇怪和尴尬了,这个问题在 2016 年 12 月被打开,仍然存在这个问题。 我将整个应用程序的结构转换为使用 aot 编译。 我有 4 个延迟加载的模块和 60 多个组件。 编译器只抱怨只有几个组件(根据错误提示),我确信它们已经是延迟加载模块之一的声明的一部分,这对我来说有点奇怪。

它甚至在已经是某些模块的一部分的组件上给出错误。

同样的问题

Angular 的编译器会查看您交给 tsconfig 的文件集 - 因此从那里排除文件应该将它们排除在此检查之外。

这真的很烦人:(

@alasair-todd 抱歉,我在大量其他通知中丢失了您的问题通知。 你是对的 -
不支持装饰器继承。

查看@robwormald的回答

Angular 的编译器会查看您交给 tsconfig 的文件集 - 因此从那里排除文件应该将它们排除在此检查之外。

因此,您可以尝试为模拟文件名制定约定,例如: selection-tool.component.mock.ts 。 然后通过排除

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

不小心按错了,对不起!

+8 个月,这仍然是一个问题。 同样的问题ERROR in Cannot determine the module for class PasoFooterComponent

我认为 Angular 开发人员忽略这些文件至关重要。

如果有人能给我关于在哪里可以找到此代码的提示,我会很高兴
自己修复它。 这是一个非常烦人的麻烦事。 跑进去
昨天又一次。

如果有人认为这是一个功能而不是错误,我们有一个标志怎么样
为了这?

2017 年 8 月 9 日星期三凌晨 2:40,Leonardo Vidal [email protected]
写道:

+8 个月,这仍然是一个问题。 同样的问题 ERROR in Cannot
确定类 PasoFooterComponent 的模块


您收到此消息是因为您发表了评论。
直接回复此邮件,在 GitHub 上查看
https://github.com/angular/angular/issues/13590#issuecomment-321082545
或使线程静音
https://github.com/notifications/unsubscribe-auth/AEM6r7FOTLcicWJN3Oijw2pwKTLGL6cFks5sWM61gaJpZM4LSAwS
.

@samirotiv你有复制品吗?
正如@robwormald所说

Angular 的编译器会查看您交给 tsconfig 的文件集 - 因此从那里排除文件应该将它们排除在此检查之外。

我有同样的问题,但我设法解决了。 例如,我只是查看了 ts 如何转换我的应用程序

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

而且我注意到打字稿没有编译我的延迟加载模块,因为我使用了“文件” tsconfig 选项

我在抽象类上遇到这个错误(没有装饰器)

我自己最近开始遇到同样的问题。

+1 用于将错误更改为警告。

似乎很容易解决。 为什么延迟?

这是一项基本要求 - 保留未引用的文件。
这种限制对于大型项目来说是个问题。 请将此更改为警告。

在某些情况下,您发布的包支持不同版本的 angular。 并且用户应该选择其中之一。

例如,为HttpClient (Angular >= 4.3 用户)和Http (Angular < 4.3 用户)提供文件的包

目前,无论您是否使用它们, ngc都会编译源目录中的所有文件! 或构建失败。

我所做的是这样的:

我已经使用.mock.ts扩展名保存了所有存根/模拟组件,并更新了tsconfig.app.json “排除”数组,如下所示:

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

AOT 现在跳过这些文件的编译

我们正在做带有通用组件的 npm 库,这些组件不应该一次全部使用,并且在 AoT 编译期间被这个问题惹恼了,该死的......唯一的解决方案 atm 是在宿主项目中创建一种 UnusedComponentsModule ——太荒谬了! 还需要NO_ERRORS_SCHEMA否则它将发誓可以在未使用的组件中使用的其他组件,如果您要声明它们,那么您会遇到另一个问题,即您不能在两个模块中声明相同的组件(与 # 10646)。

我当前的模块:

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 {
}

这确实应该是一个警告。 我也在尝试共享一个代码库,并且遇到了组件不属于 ngmodule 的问题。
这里的问题与未使用的变量完全一致,这不是错误; 最多是一个警告。

当它是您的代码时,这很容易。 当它是一些 NPM 角度库(一些死代码)的问题时,那真的很痛苦:)

谁能解释为什么它不能是警告而不是错误?

就我而言,我只想从连接到 ngModule 的组件中提取语言,而忽略那些没有的组件。 我有一个主应用程序文件夹,其中包含基本组件和应用程序特定文件夹,当我尝试使用 xi18n 提取此类被覆盖的组件时,有时会覆盖主应用程序中的组件,它会引发Cannot determine the module for class...错误,在我看来可能只是被忽略和提取可以在不使用该未使用组件的情况下继续。

我能想到的可能是一个问题的一件事是,我仍然使用该错误组件文件中定义的类作为创建覆盖组件的基础,因此需要对其进行编译,但我只是不需要该组件注释原因,因为您不能在覆盖组件中使用它。 至少我认为你不能,因为我必须在派生组件中重新创建这些注释才能使它们工作。

@Xesenix至少它应该是一个选项。 像确定模块=假/真。 现在是香蕉。

我将于 2017 年 11 月 1 日返回。

我回来后会回复你的消息。
在紧急情况下,请发送您的电子邮件副本
技术问题发送至[email protected] ,否则发送至
[email protected] 然后另一位员工将查看您的电子邮件
接受。

注意:这是对您的“回复:
[angular/angular] Angular2 AOT 编译-“无法确定模块
对于类(......许多未使用的组件)“(#13590)”发送
2017 年 10 月 23 日 08:13:17。

这是您将收到的唯一通知
那个人不在。

将近一年后,这仍然没有解决? 拉我的头发让 AOT 工作,但这个问题让我碰壁了。

谢谢@rahul-sivalenka-wtc 的解决方案!
正如你所描述的那样,我成功地通过在我的tsconfig.app.json中排除"**/*.mock.ts"来解决我的问题❤️

很高兴我能帮忙😊

我也遇到过这个问题。 但对我来说,我似乎只是错误地输入了 dodule 的路径

任何解决方案? (无法确定组件角度 5 的模块)

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

这可能应该是severity3: broken 。 对于我们这些具有多个构建目标和多态依赖项(上面已经存在许多用例)的人来说,这个问题会阻止构建在没有疯狂复杂的构建设置的情况下工作。

这个问题有什么好的解决方案吗? IgnoreModule 只是一种解决方法,但不是解决此问题的真正好方法。 将错误更改为警告会很棒!

我们的解决方案是在@ngtools/webpack中添加一个transform函数,该函数通过preprocessifdef基于各种编译时设置传递文件的组件。 非常非常难看,但是很实用。

尝试先在 app.module.ts 中导入所有角度依赖项,然后再导入组件。

` ---------------- 首先导入依赖模块 ------------------------
从“@angular/platform-b​​rowser”导入 { BrowserModule };
从“@angular/common”导入 { CommonModule };
从'@angular/core'导入{ NgModule };
从'@angular/router'导入{RouterModule,Routes};
从“@angular/http”导入 { HttpModule };
从“@angular/forms”导入 { ReactiveFormsModule };
从'@angular/platform-b​​rowser/animations'导入{ BrowserAnimationsModule };

-------------然后导入服务模块------------

从'./Services/apply-form-post.service'导入{ApplyFormPostService};
从'./Services/nav-bar-color.service'导入{NavBarColorService};

------------------------ 最后导入组件模块 ------------ -

从'./app.component'导入{AppComponent};
从'./components/header/header.component'导入{ HeaderComponent };
从'./components/career/career.component'导入{CareerComponent};
从'./Components/home/home.component'导入{ HomeComponent};`

不知何故,这解决了 AOT 编译错误抛出无法确定类的模块 --- 在生产模式下

@KarthikSamyak这个问题不是关于那些应该在模块中的类的人。 这是关于我们这些拥有组件库的人,这些组件库被故意排除在所有模块之外。 它们是未使用的代码,编译器应该忽略它们。 相反,编译器在发现它们时会引发不可恢复的错误。

将这个错误变为警告确实应该是一个简单的更改,但由于某种原因,它已经花费了一年多的时间,并且最近在路线图上从 pri_col1 移动到了 pri_col2。

我对 Angular 团队对这个问题完全没有回应越来越感到沮丧。 我们公司最终完全放弃了使用组件库,而是选择手动复制文件。 这远非理想,因为我们现在遇到了几乎相同但未共享的组件的问题。

Angular 团队,如果您再阅读此问题,请为“ignoreUnusedComponents”添加编译器设置,让我们继续使用此框架。

好的,我找到了这个地方https://github.com/angular/angular/blob/master/packages/compiler/src/aot/compiler.ts#L605 @tbosch嘿,你能在这里帮忙并说一下如何做到这一点是正确的警告? 在该 AoT 编译器中看不到任何警告,只有错误。 如上所述,可以添加编译器选项。

这个问题是复杂项目的痛点。 我的特殊情况是https://github.com/angular/angular/issues/13590#issuecomment -331820496

我们的用例是一样的。 我们希望有一个模块/组件库来真正轻松地创建应用程序,并能够在需要时替换/扩展奇数的应用程序。

我们也遇到了其他问题:如果我们想替换模块中的 1x 组件,我们创建一个新模块并在其中导入我们仍然想要的组件:

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 { }

错误是:`HeaderComponent 在 2 个模块中声明: lib/module.tsapp/module.ts
相反,作为一个警告至少可以让我们继续前进:(

刚刚意识到-这个问题生日快乐:)

一年后,我们仍然无法将其更改为警告。 荒谬的。

从字面上看,也遇到了这个问题。 编译器尝试引入仅用于测试的模拟并失败,因为它不是主模块的一部分。 如果它知道它不需要该文件,那么它最多应该是一个警告。

请解决这个问题。 把它变成一个警告!
我对 Angular 5 aot 构建的一般经验并不出色。

经过一些讨论https://gitter.im/angular/angular?at=5a551f565a9ebe4f756843b2我们得出结论,我们需要为每个模块创建一个组件,因为似乎模块只是编译上下文,而不是一种收集东西的方法。 .

这是一本历史书的大小。

@Xesenix ...上下文和组织是整体的两个部分。

万一有人仍然被这个问题困扰,您可以让这个脚本作为安装后脚本运行作为一种解决方法

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);
    }
});

角度编译器将使用 tsconfig 的输出,因此更改_tsconfig.app.json_以排除那些您不希望包含的文件
例如
"exclude": [ "test.ts", "**/*.spec.ts", "**/*.mock.component.ts", ]

@andela-andrewmakenzi 之前有人建议过,在这个巨大的聊天中更进一步(不通读整件事绝对不会感到羞耻)。 但是,如果您依赖于使用桶文件 (index.ts) 的库中的一个组件,则会出现问题。 如果您从桶文件中导入任何组件,编译器会尝试加载该桶文件中引用的所有组件,并会抱怨它们不在模块中。 这使得打包可重用的组件库变得很困难,这首先是组件架构的重点。

您的解决方案非常适合拥有模拟组件并且在不运行测试时遇到此错误的人。 但是,如果您的组织(如我的组织)试图创建一个通用组件库,并且只引入我们在任何给定项目中需要的那些,那么 TSC 的 exclude 很遗憾对您没有帮助。

@andela-andrewmakenzi:你的建议现在似乎有帮助,以前的问题是我有一个用于单元测试的组件(.spec),我不希望它包含在 AOT-build 中(也许还有一些模拟组件我什至不想在我的投影中使用它)也许我认为在更高版本的 Angular 中以某种方式解决了这个问题 :)

但我的情况是,我有很多新组件甚至没有在 NgModule 中引用,所以现在我们必须为其命名约定并将它们排除在 tsconfig.json 中,这暂时不是很愉快

这真的很荒谬。 我们有一个共享的 NPM 模块导出几个管道/指令,除非你全部导入,否则它会因为这个愚蠢的错误而失败。 它确实应该更改为警告,并且不应该破坏编译。

在我看来,每个组件都应该有自己的NgModule 。 为每个组件创建另一个NgModule并不可怕。 (就像@angular/material所做的那样)

我认为这确实是一个虚拟问题。 我们也看不出有什么理由半途而废。 不是NgModule ,不是包,不在应用程序树之外......看起来像是死代码的东西。

因此,使用新的 @angular/cli (1.7.0+) 甚至 IgnoreModule 也无法解决这个问题。

在我看来,每个组件都应该在自己的 NgModule 中

你甚至尝试编写单元测试吗? 这个错误使得创建测试助手有点问题。

@sarunint在企业规模的应用程序中,比如我最初打开这张票的那个,那将是数百个模块,为了处理依赖的指令和组件,导入非常复杂。 这有一个非常简单的解决方法:如果编译器找不到组件的模块,则抛出警告并在 tree-shaking 中删除它。

这如此令人讨厌的真正原因是桶文件变得比恩惠更危险。 集中您的导入很方便,但如果您承诺在使用您的库的每个应用程序中包含每个导出的组件,则不是。

@dborisenkowork我不确定您是否没有看到它(或者它是否不适用于您的用例),但@rahul-sivalenka-wtc 提供的解决方案非常有效。

有没有人最近从 angular 4 移动到 angular 5 并注意到他们的一些实际在模块中声明的组件抛出了这个错误?

@novologic-clay 什么错误? 线程很长,你指的是原始错误吗
Angular2 AOT 编译 - “无法确定类的模块(......许多未使用的组件)”

@andela-andrewmakenzi 是的,也不是。 尝试编译时打印的错误相同,但它抱怨的组件肯定包含在模块中。 我正在从 4.3.6 迁移到 5.2.4,但我没有收到此特定组件的此错误,因为我更新了我的 angular 版本,并且在开始迁移为冒烟测试之前,我在 4.3.6 上进行了 AOT 编译.

@novologic-clay 你能分享你的控制台错误吗?

...最终目标应该是使用tsconfig.json选项"noUnusedLocals": true消除所有未使用的内容。

@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.

这是一个企业应用程序,有几十层模块和导入,但这是实际声明组件的代码:

**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 { }

另外值得注意的是,当我在 ng serve 中运行此应用程序时,该组件工作正常。

许多真实组件的测试使用的假组件不应该在一个模块中; 它们只是包含在测试组件的 TestBed 中。
这个错误很愚蠢。 请从1年起解决那个问题。

删除“导出”,因此 ts 不会将其带到构建中。

@tony-kaplan 如果您的 tsconfig 中有 noUnusedLocals ,或者您想在测试用例或类似情况中使用代码,则不能这样做。

我的上帝……真的没有人从核心团队找到合适的解决方案吗?
我现在使用exclude选项,但它仍然是一个临时解决方案。 想不出适用于所有情况的东西......但我真的需要它......

@gabrielalan简单的解决方案是将此错误转换为警告。 更好的解决方案是添加一个标志,允许您将其视为警告或错误。 这不是缺乏解决方案,而是缺乏实际实施其中任何一个。

好家伙! 企业框架就这么多...

@atom-morgan 您在说哪种解决方法?

@netlander这个

真的,对于“无法确定类 DaterangepickerDirective 的模块”错误,我无能为力吗?

也有人帮助我吗? 在这个 megazord 帖子之后!

我不同意将 tsconfig.app.json 新的排除项添加到该指令中! 如何在没有此问题的情况下使用 --aot param 进行编译?

我的用例https://github.com/angular/angular/issues/23475
我正在创建验证器库,我不想为每个验证器指令创建模块,我想要的只是能够将验证器指令捆绑到 npm 包中,这样用户就可以只安装和导入他需要的验证器到 NgModule。 此外,我不想为所有验证器创建一个模块,因为它们都将被捆绑在最终的捆绑包中,这是对大小的巨大浪费。

我很高兴创建 PR 来解决问题。

@anjmao这与我首先打开它的原因非常相似。 作为小型库的解决方法,我们发现如果您不使用桶(index.ts)文件,则不会发生此错误。 似乎如果您从索引中导入 1 个组件/指令,它会尝试为索引文件的所有其他导出找到一个模块。

显然我仍然认为这应该是一个警告,因为桶文件非常方便。 但是,如果您的用例不能再等一年来进行此修复,您也许可以像这样绕过它。

我用于组件/指令/管道共享库的解决方法:创建一个引用所有类声明的简单虚拟模块。 你不需要在你的真实应用程序中使用这个模块,它只需要存在于磁盘上。 前任:

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

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

我们还没有解决这个问题是有原因的吗?

“使其成为警告”解决方案是否不够? 核心团队的成员可以对此发表评论吗?

就我而言,NG 5、CLI 和 AOT 都很好。 但是在升级到 NG 6 后,对于未使用的组件,我遇到了类似的错误。 实际上,该组件是通过注入到另一个组件的服务来使用的。 我有许多类似的组件以相同的方式构建和使用。 但是只有一个问题是升级到最新的 NG CLI 6.0 和 6.0.1

事实证明,在其中一个参考资料中,我的文件参考资料错误。 我有一个 index.ts 来导出同一目录中的所有组件。 我有
export * from './dateTimePicker.component'
虽然它应该是:
从'./datetimePicker.component'导出*;

显然 NG CLI 6 即使在 Windows 中也更受限制,而 NG CLI 1.x 则有点放松。
显然,这样的限制是好的和正确的,所以相同的代码库可以在默认情况下区分大小写的 Linux 中运行良好。

另一个用例:

Typescript 允许您使用tsconfig.json中的paths变量设置多个解析路径。 前任:

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

允许您导入如下内容:

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

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

如果您在src-gen中生成一个组件,开发人员可以通过在src文件夹中创建另一个组件来“覆盖”该组件,那么src-gen中的(现在未使用的)组件开始发生相同的错误

另一个潜在用例:

环境特定组件。 我剥离它们进行生产。

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

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

我设法让其他所有东西都与环境特定的组件一起工作,这就是让我停下来的原因。 😪

我们在实现构建自定义机制(为不同的 Angular CLI 项目交换组件)时遇到了这个问题,这看起来很像@tiagodws描述的场景(包括原始组件的扩展)。

核心团队对此问题是否有任何更新/意见?

在我打开这个问题一年多之后,我的新方法是尽量减少桶文件的使用。 如果您在任何地方的导入中都使用像~components/button/component这样的 TS 路径,则忽略未使用的导入。 如果在桶文件中引用了该未使用的组件,它将抛出。

对于可重用的库来说,这仍然不是很好,因为您必须访问具有更长路径的所有库组件,而不仅仅是从该库顶层导入。 为什么,哦,为什么这不仅仅是一个警告?

这似乎也可以通过摇树(或至少与摇树相关)得到帮助,其中任何未明确包含在模块中的代码都会从最终捆绑包中排除。

exclude 选项不适用于模拟管道:

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

我的 tsconfig.app.json 已排除此文件:

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

但是,当我运行 ng-xi18n --i18nFormat=xlf2 --outFile=./assets/i18n/messages.xlf 时,它仍然抱怨:

无法确定 src/test/translate.service.mock.ts 中类 MockTranslatePipe 的模块! 将 MockTranslatePipe 添加到 NgModule 以修复它。

我的问题是我通过复制和粘贴在 2 个不同的组件中获得了一个类的名称,哈哈! 后来因为不关心而犯了同样的错误好习惯造就完美的人! 命中...
签名:中本聪:v

@yuezhizizhang类似,我仍然有这个问题,即使在 tsconfig.app.json exclude路径中添加了一个用于模拟的 glob 之后。

令人愤怒的是,在最初的罚单将近两年后,这个问题仍未得到解决; 这是一个常见的用例,它正在破坏构建。 在编写测试时,开发人员应该理想地为管道、服务等创建模拟,除非。 如果您选择这样做,您的构建就会中断。 如果不是,那么您的规范文件会引用真实的组件/管道/等,这会导致非常紧密耦合的测试。

Angular 团队的某个人可以建议如何解决这个问题吗? 为模拟创建一个包罗万象的虚拟模块真的是唯一的选择吗? 这是一个糟糕的 hack,而不是我们应该接受的最佳实践。

问题仍然存在。 我还将我希望跳过构建(抽象类)的文件添加到tsconfig.app.json排除部分,但我仍然得到:

无法确定 .../map-elements/map-element-base.component.ts 中类 MapElementBaseComponent 的模块! 将 MapElementBaseComponent 添加到 NgModule 以修复它。

在仔细检查进口后我已经摆脱了这个问题

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

问题仍然存在。 我还添加了我希望跳过构建的文件
(抽象类)到 tsconfig.app.json 的排除部分和我
仍然得到:

无法确定类 MapElementBaseComponent 的模块
.../map-elements/map-element-base.component.ts! 添加 MapElementBaseComponent
到 NgModule 来修复它。


您收到此消息是因为您发表了评论。
直接回复此邮件,在 GitHub 上查看
https://github.com/angular/angular/issues/13590#issuecomment-438641324
或使线程静音
https://github.com/notifications/unsubscribe-auth/AQb6kpWdkakUF8JVvea8Hy42tAnTKTuzks5uvAjvgaJpZM4LSAwS
.

当 TypeScript 严格时,Angular 导入,在 AOT 编译中,未使用库中的组件并启动此错误...检查未使用的组件/模块没有意义...

image

通过删除未使用的模块和组件所在的库文件夹,应用程序可以在 strict-aot 中很好地启动 - 但手动删除此文件夹肯定没有意义

这个错误绝对是荒谬的。 我有一个模块,它指定对象中的组件,如下所示:

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

然后我尝试用declarations: Object.values(landingComponents)entryComponents: Object.values(landingComponents)为模块提供食物。

你猜怎么着...... AOT编译器需要查看数组中列出的组件......否则,如果我以任何其他方式传递它,我会得到这个可怕的“无法确定类的模块”。

尽管我很喜欢 Angular,但 AOT 编译器似乎是一团混乱的魔法咒语。

有人说 coupla 次,但解决方案是每个模块 1 个组件,并且不确定您是否注意到从 PR 到 Angular,但这最近被合并并且可能对这个主题感兴趣: https ://github.com/

这个问题今天 2 岁了🎉

尽管如此,核心团队甚至没有说明为什么这不能只是一个警告。

@tiagodws大声笑你等了多久才发布这个? 你设置了提醒吗?

仅供参考
我的问题与https://github.com/angular/angular/issues/13590#issuecomment -389113560 相同
导入在 AOT 模式下显然区分大小写

@peterdeme ... JavaScript 区分大小写(作为字符串的路径相同 ... = 基于 Linux,而不是 Windows)。

嘿,伙计们,刚刚回来参加一个迟来的 2 年发行年龄庆祝活动。 关于人们可能的原因有很多交叉讨论,包括 tsconfig.json 的includeexclude tsconfig.json ,所以我只想弄清楚根本问题是什么对于这个线程。

如果您创建一个可重用组件库,并添加桶文件 ( index.ts ) 以便于导入,那么当您使用其中任何一个组件时,Angular 编译器都会中断。 这是因为一旦您从该桶文件中导入任何内容(例如@shared/components ),它就会尝试为每个单个组件查找模块。 即使您指定了您想要的特定组件(例如import { SharedToastComponent } from '@shared/components'; ),编译器仍会为每个导出的组件查找模块,并针对缺少的组件抛出错误(而不是警告)。

显然,有一些解决方法。

  1. 停止使用桶文件。 这会很快变得混乱,因为每个组件都必须完全指定
  2. 使用ExtrasModule并且不要在任何地方使用该模块。 这适用于只需要测试组件的人,但对于希望从组件库中提取的人来说不是很好

但是,由于使用这些变通方法中的任何一种都会在摇树之后产生完全相同的输出代码,因此很明显其他组件不需要包含在使用的模块中。 对于这个已有 2 年历史的问题,我所要求的只是将该错误转化为更合适的警告。 有道理,因为如果允许继续编译,编译仍然会成功。

希望 Angular 团队在 2019 年为这个非常古老、非常烦人的问题做点什么。 🤞

@swimmadude66 ...您没有提到创建真正的 lib 模块并通过tsconfig.json ... 将其添加到 Angular 应用程序的方式: "paths": {"ng-demo": ["./packages/ng-demo/src/index.ts"]}并通过 import like import { DemoModule } from 'ng-demo';使用它

每个组件存根都有错误是最烦人的事情。 每个人都在测试/编写规范吗? 所以组件存根错误应该影响每个人。 我并不是说枪管问题不那么烦人。 我只是说不是每个人都在做桶。 但是每个人都应该做规格。 所以规格问题应该是核心团队解决这个问题的最大动力。 它目前被标记为“频率低”,但应该是“频率高”,因为任何进行单元测试的人都会遇到这个问题。

这在 AOT 中甚至不一致。 Angular CLI 在使用 serve(默认使用 AOT)运行时不会出现错误,但会在使用 build 运行时出现错误。

我知道这不是 Angular CLI 存储库,但围绕它的行为肯定很奇怪。

即使创建模拟模块的解决方法,现在如果 UI 单元测试编写者忘记将单个模拟组件添加到模拟模块,“ng build”也会失败。

以上意味着UI 单元测试目前是 CI/CD 部署管道的风险元素

我们真的需要向食物链中更高层的人解释 Angular 单元测试人员可以通过一个微不足道的遗漏来破坏整个部署构建吗? 没有。 管理 Angular 开发人员并决定下一个项目使用哪个框架的人不应该对这类事情感到疑惑。

作为权宜之计:为什么不让“ng build”中出现的错误为测试编写者提供更多信息:即添加附加文本以达到“如果这是用于测试的模拟组件:将其添加到模拟模块中根据(此网址)的文件“

您平均友好的 Angular 开发人员编写单元测试是如何到达这里的:

a) 恕我直言,创建一个“帮助”文件来放置所有 .spec 文件使用的模拟组件、服务等是一种 DRY 代码实践。 然而,这种做法会使测试人员陷入这种错误场景。

b) 所有 .spec 文件都可以导入这个“帮助”文件,而不需要与实际测试代码无关的“模拟模块”。 模拟组件按原样很有用,没有模拟模块的成员资格,在规范的测试环境中根本没有任何作用。

当然解决方法是微不足道的......但只是通过谷歌搜索找到这个错误,阅读和消化线程和有用的解决方法不是。

我只是将它添加到包含模拟组件(除其他外)的帮助文件的末尾:

/*
  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 {}

请注意,实际上上面的文件非常大......“MockTestModule”被埋在帮助文件的末尾......

...我希望我们不必为拦截调用的“ng build”编写 package.json 条目,并插入控制台消息“嘿 UI 单元测试人员,您是否将模拟组件添加到模拟模块?” 轻推。

这就是为我解决问题的方法。 我的结构如下:

├── 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

icons.module.ts我有:

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 {}

index.ts有:

export * from './icons.module';

我假设问题是编译器在遇到相应的组件之前没有解析 icon 和 icon-indicator 模块,因此抛出了Cannot determine the module for class错误。 这个项目是 ng 5。我只在 ng 7 项目中使用它时遇到错误。

解决方案是将出口下移一级。 所以我删除了icons.module.ts中的导出语句并将它们移动到:

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

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

并调整index.ts

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

希望这可以帮助某人。

我认为新的 ivy 渲染器将解决 AOT 的一些问题。 正如您从拉取请求和问题中看到的那样,Angular 团队专注于 ivy,因此在 Angular 6 上对这个问题做任何事情是没有意义的。

我认为新的 ivy 渲染器将解决 AOT 的一些问题。

我喜欢在每个问题上听到这个。

我也遇到了 angular 7.2.0 和 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.

例如,我的 Shared Module 里面有一个TranslatePipe和一个TranslatePipeMock Shared Module 。 TranslatePipe 包含在模块中,模拟管道不包含。
translate.pipe.mock.ts用于单元测试目的,所以我可以将此文件导入每个单元测试。

但现在我的构建失败了
ng build --prod

我们如何解决这个问题?

Atm 我有一个解决方法

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

从简短的评论中很难确定此问题的当前状态。 我同意这是一个问题(设计不佳)。 修复它的计划是什么? 是容易还是困难?

@rrmayer这个问题的状态很可能只是“等待常春藤”,就像几乎所有“当前”问题一样。

我们只是希望将其从“错误”更改为“警告”,这样我们的项目才会真正编译……这有那么难吗?

@Terrafire123 ... 例如,可能与测试或构建工具有很多关系,这实际上是基于这种情况导致错误的事实,因此对警告的更改可能是一个严重的问题。

我不希望它会为当前的编译器修复:D

也许我们至少应该可以选择显示错误或警告。 由于组件不是故意成为模块的一部分而导致构建中断是非常烦人的。

未使用的导入可能会导致此错误..

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

似乎类旁边的“export”关键字以某种方式确定了应用了@Component装饰器的类必须包含在某个模块中。 无论您是导入组件的类并直接在测试中声明,还是在例如CoreMocksModule 中声明然后导入模块,都无关紧要。

不过有一个解决方法! 假设我们有这样声明的存根组件:

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

我们必须删除'export'关键字,但在某种程度上我们仍然必须导出组件才能在测试/测试模块中使用它。 像这样做:

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

export default UserStubComponent;

现在,当您导入存根时,我们必须避免使用如下括号:
import UserStubComponent from 'path'

希望它有效。 对我来说,它解决了 AOT 编译问题。

在我的情况下,我修复了它。 问题出在外壳上。 我对文件夹使用了大写字母,但 VS 代码的自动导入使用小写字母导入了路径。

@renilbabu03 JS 区分大小写。

就我而言,我为我的单元测试修复了它,在那里我模拟了翻译管道。

我将export class更改为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;

对此有任何修复吗?
我试过export default <class>但是当我运行ng serve --aot时,它会抛出一个错误: Unexpected value 'null'exported by the module

这非常令人沮丧。

@redplane你为什么要这样做? 我的意思是default出口。

除非我import是一个exported资产,否则为什么 Angular 会关心文件是否存在?

我经常重构一个组件或删除组件,只是想注释掉过时的组件引用,就像我在 CommonJS 时代所做的那样。 这足够安全,因为我从不使用桶文件,因为我在这方面被烧了太多次,当我深陷其中时,让 Angular 强迫我承诺从我的项目中物理删除资产是不可接受的原型设计阶段...

我被困在 Angular 6 中,因为我是唯一一个从事这个项目的开发人员,在不得不发布新功能的过程中重构东西以升级到最新的稳定工具将是地狱......所以在非常至少,如果 Angular 6+ 可以使用编译器标志进行修补以禁用此行为,那就太好了……

就我而言,我有一个角度库项目设置。 在库中的一个组件中,我声明了几个枚举,为了在我的应用程序项目中使用这些枚举,我正在使用应用程序根目录中项目目录的相对路径导入这些枚举。

这就是为什么 Angular 编译器想要在应用程序项目的任何 ngModules 中声明我的库组件的原因。

为了解决这个错误,我必须将我的枚举声明到 public-api.ts文件中,并通过从库中直接导入而不是相对导入路径在应用程序项目中使用它们。

例如:
库项目名称: components-lib
应用项目名称: demo-app

要使用在库项目中声明的任何接口、类、枚举等,请使用直接路径导入它们:

从“组件库”导入 { SearchEnum };

不要做
从'../../../projects/components-lib/path-to-your-component'导入{ SearchEnum };

我希望这对将来的某人有所帮助,因为我自己花了几个小时才找到它。

在维护使用 ng 9 构建的库的兼容性方面存在问题,我希望运行 ng 8 的人能够使用该库。

我通过库提供了一些您的组件可以扩展的实用程序类。 在该父类链中,其中一些是抽象的,并且 ng 9 需要有一个@Directive({ selector: 'random' })才能与 ng 8 兼容。

所以我几乎侥幸逃脱了……但是:

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.`

我没有在库中公开任何模块,人们只是应该扩展我们提供的类。 但我不希望他们必须在他们的模块中导入父类(没有任何意义)。

所以我被困住了,我将只删除一个要求人们升级到 ng 9 而不是向后兼容的重大变更版本

大家好,很抱歉在这个问题上保持沉默。

View Engine 中的 ngc 按照设计为“编译”中的每个组件生成ngfactory文件 - 即由您的 tsconfig 定义的全套 TS 文件。 这就是 TypeScript
它本身可以工作 - 它编译由 tsconfig 定义的所有文件。 ngc 只是在此之上进行额外的处理。

因此,如果该编译中存在@Component并且 ngc 可以看到它(意味着它是顶级并导出的),则 ngc 将尝试编译它。 除了确保 ngc 不编译首先声明组件的文件之外,没有其他办法。

正确的方法是确定 tsconfig 的范围。 例如,您的编辑器可能有一个顶级 tsconfig,其中包括所有文件,然后是一个专门用于应用程序编译的tsconfig.app.json ,它继承自编辑器配置并排除规范文件。 只有应用程序配置会用 ngc 编译。

项目(每个 tsconfig 都是一个“项目”)的结构应使得组件及其模块始终一起编译。

在 Ivy 中,同样的规则在很大程度上仍然适用,但有几个小区别:

  • 默认情况下,Ivy 将尝试编译 _any_ @Component ,无论它是否被导出。
  • 在 Ivy 中,没有模块的组件不再是错误。 但是,如果该组件尝试在其模板中使用其他组件/指令,您仍然会收到模板类型检查错误,因为没有模块,该组件将看不到任何其他内容。
  • 通过向装饰器添加jit: true标志,可以告诉 Ivy 编译器忽略特定组件或模块并将其保留到运行时。

@alxhub我很高兴听到它不再是错误!

我知道 ngc 会尝试编译 tsc 会编译的任何东西,并且 tsc 会编译其范围内的任何东西。 话虽这么说,将组件添加到模块的要求是 100% 的角度问题,因此将其从 typescript 项目范围中删除感觉就像在路上踢罐头。 此外,由于桶文件等模式很常见,因此很难从编译中真正删除单个文件,而在此过程中也不将其从任何重新导出中删除。 这就是为什么上面简单地“排除那些组件”的呼吁经常遭到不满。

关于 ivy 的剩余限制(没有模块的组件上的模板错误),要求那些也是警告是否太过分了? 我知道如果在组件被识别为无模块之前进行类型检查可能会更困难(或不可能),但在我看来,这就像Warning: ExampleUnusedComponent does not belong to an NgModule, and will be excluded from the output这样的警告准确地捕捉到了组件(以及它引用的任何其他组件)将不会被包含在内,除非它们被添加到 ngModule。

总的来说,我很高兴看到在这个问题上的进展,并期待通过 ivy 编译器的新变化来尝试我的原始用例!

此页面是否有帮助?
0 / 5 - 0 等级