自定义库组件不是已知元素,但应用程序编译并运行

Posted

技术标签:

【中文标题】自定义库组件不是已知元素,但应用程序编译并运行【英文标题】:Custom Library component is not a known element, but app compiles and runs 【发布时间】:2020-05-22 22:09:12 【问题描述】:

问题

我的 html 文件警告我的自定义组件/管道“不是已知元素”。但是,构建和运行应用程序按预期工作,并且自定义组件/管道可以正常工作。组件工作但显示为错误的二分法令人讨厌,并且可能难以使用。我知道这是一件小事,但我真的不想在没有错误的情况下在我的 html 文件中看到错误。

总结

我有两个不同的角度项目;我使用我的 Angular 应用程序使用的 Angular 库。该库导出应用程序使用的几个自定义组件、管道和服务。我没有通过 npm 发布这个库,而是使用 npm-link 让应用程序访问该库。这似乎可以像我的应用程序组件中定义的任何服务/组件一样工作并且不会抱怨。虽然当我从库中将任何内容放入模板文件时,该选择器带有下划线并出现警告。

文件

/*Library Module*/
@NgModule(
  declarations: [
    ThemeToggleComponent,
    // Other custom components/pipes
  ],
  exports: [
    ThemeToggleComponent,
    // Other components needed in templates files
  ]
)
export class MyCommonModule 
  
/*
 * Public API Surface of my-common library
 */

export * from './lib/my-common.module';
/*
 * Many other components, services, pipes, etc etc
 */
export * from './lib/theme-toggle/theme-toggle.component';

/* Consuming Application module */
import  MyCommonModule  from 'my-common';

@NgModule(
  imports: [
    MyCommonModule,
  ],
  declarations: [
    MyComponent,
  ],
)
export class MyModule 
/* Template of MyComponent, my.component.html */
<div>
  <my-theme-toggle (darkThemeSelected)="toggleTheme($event)"></my-theme-toggle>
</div>

上面的文件将所有引用我的自定义组件的行都用红色下划线并带有错误消息 'my-theme-toggle' is not a known element: ...如果是,请验证它是否属于模块

尝试修复

我尝试了一些东西,但没有成功

不使用 NPM 链接,只是将 ng-packagr 创建的库复制到我的应用程序的节点模块中 重建和重新链接/重新启动一切 搜索其他 S.O 问题:大多数问题与构建失败有关,因为导入/导出实际上不正确。

我的预感

我认为这是使用应用程序中 tsconfig.json 中的 paths 编译器选项的问题。在我所有的研究中,这是最重要的一件事。我目前没有设置路径,因为一切正常。除了这个问题之外,我的公共库看起来和行为都与任何其他 node_module 库一样。

我的另一个想法是,因为一切正常并运行,所以问题可能是 vs-code 不理解导入,或者类似的东西。虽然我认为这不太可能。

背景

这两个 Angular 项目都在版本 9,rc7 上。我使用 ng-packagr 来构建我的库。我使用 Visual Studio 代码,在撰写本文时,我使用的是最新版本。

编辑 这个问题在升级到 Angular 11 后就消失了,我认为其他几个问题可能会解决它,但这感觉是最好的选择。

【问题讨论】:

可能vs代码不理解符号链接,如果你改为npm install &lt;path-to-library&gt;呢? @JasonWhite 我的想法也是如此,但是执行您的建议导致将我的库直接复制到 node_modules 中的结果相同。一切正常,但仍然在我的 .html 文件中出现错误。 也许在他们的 Github 页面上打开一个问题? 看起来像语言服务器does not support ivy。他们说要解决此问题,请在库上运行带有 --prod 标志的构建,然后运行 ​​Restart Angular Language Service @GetOffMyLawn 我认为这正是我遇到的问题,感谢您为我指明正确的方向。 【参考方案1】:

我将我的项目从 Angular 8 切换到 9,并且在 VS Code 中遇到了同样的问题。我的解决方案对我有用:

使用配置生成构建库:ng build my-lib --prod => 这将强制编译器使用旧版 View Engine 而不是 Ivy (Angular docs libraries) 转到文件夹“./dist/my-lib/”并使用 npm pack 而不是 npm link => 这将创建一个 tgz 文件,您可以将其安装在您的消费应用中。 在您的消费应用程序中安装库:npm install "D:/mypath/dist/my-lib/my-lib-2.1.0.tgz"

这在我的环境中解决了 Angular 9 的 VS Code 问题。

【讨论】:

这是一个有趣的想法,但不幸的是对我不起作用。我按照这些步骤验证了软链接指示器没有出现,这表明我正在使用 tarball 本身。我希望这会奏效。 如果您在两个新应用中尝试这些步骤会发生什么?具有测试库和消费应用的应用。在我的设置中,我有时会遇到您描述的问题,但是当我重新启动 VS Code 时,指向 html 模板中库的链接又可以工作了。魔术...听起来像是 VS Code 中的缓存问题。 我还没有尝试过,但我会尝试用最小的可行产品重现我的问题并更新帖子以反映这一点。【参考方案2】:

直到最近我才遇到过描述的错误。

卸载 Angular 语言服务扩展(我最近安装的)后,错误消失了。

【讨论】:

已验证这确实有效,但我对接受这个作为答案感到不安。 Angular 语言服务对于捕获常见错误、自动完成变量名和许多其他事情非常有用。不过,这可能暗示了问题的潜在根源。 为什么不更新这个答案来解释如何“重启”Angular 语言服务:)【参考方案3】:

我也有同样的问题。这是一个修复,

添加

import  NgModule, CUSTOM_ELEMENTS_SCHEMA  from '@angular/core';

schemas: [
  CUSTOM_ELEMENTS_SCHEMA
],

到你的模块


完整的app.module.ts 供您参考

import  BrowserModule  from '@angular/platform-browser';
import  NgModule, CUSTOM_ELEMENTS_SCHEMA  from '@angular/core';

import  AppRoutingModule  from './app-routing.module';
import  AppComponent  from './app.component';
import  NgNiceSelectModule  from 'ng-nice-select';

@NgModule(
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    NgNiceSelectModule
  ],
  providers: [],
  bootstrap: [AppComponent],
  schemas: [
    CUSTOM_ELEMENTS_SCHEMA
  ]
)
export class AppModule  

【讨论】:

这将消除显示中的错误,但它也允许其他错误溜走。例如, 不会显示为错误。这在技术上是可行的,但可能会破坏太多其他功能而无法被接受。【参考方案4】:

要解决此问题,您当前必须使用生产标志 --prod 构建,因为在当前状态下,Angular Language Server doesn't work with Ivy 构建。默认情况下,没有 Ivy 的 angular prod 构建构建。因此,当它被构建时,它会创建一个lib.metadata.json 文件。这是语言服务器用来使插件工作的文件。

    在您的库中,创建一个构建 ng build &lt;lib&gt; --prod 添加 --watch 标志以观察变化 在您的图书馆中,创建一个链接 cd dist 然后 npm link 我在dist 文件夹中创建了一个package.json 并在那里创建了链接,因为我的库中有多个模块。这将允许你做 import ModuleAComponent from '&lt;lib&gt;/moduleA' import ModuleADirective from '&lt;lib&gt;/moduleA' 注意:您链接的文件夹必须有一个package.json,否则它将使用项目的根目录,因为那是最接近的package.json 如果您执行相同操作,则以下路径格式正确,否则可能不正确,您可以尝试:"lib": ["./node_modules/lib", "./node_modules/lib/*"] 在您的应用程序中,链接到包npm link &lt;lib&gt; 在您的应用程序中,在您的tsconfig.base.json 中创建一个path(路径可能会有所不同,具体取决于您创建链接的方式) 在您的应用程序中,重新启动 Angular 语言服务器

  "compilerOptions": 
    "paths": 
      "lib/*": [
        "./node_modules/lib/*"
      ]
    
  

【讨论】:

【参考方案5】:

您可以尝试以下方法。 https://github.com/angular/vscode-ng-language-service/issues/645#issuecomment-648283157 简而言之:

使用 --prod 标志构建您的库。 然后转到dist/YourLibName 并运行npm link 转到将使用该 lib 的项目并从 lib package.json 中运行 npm link YourLibName name 在项目 tsconfig.json 中将 paths 属性添加到 compilerOptions。
      
      "compilerOptions": 
       .
       .
       .
        "paths": 
          "YourLibName from lib package.json": ["node_modules/YourLibPath"]
        ,

然后您将能够像使用任何库一样使用它,例如材料。

【讨论】:

谢谢——它只需要使用 --prod 标志构建它就可以在我这边使用最新的 angualr 版本 (11.1.0)【参考方案6】:

这是一个导入问题,99.99% 的时间!

我在 Stack Overflow 内外的不同网站上看到了这个问题以略有不同的方式发布。我可以告诉你这可能不是 Angular 语言服务的问题。

发生这种情况的三个原因

    您如何从库中导出缺少的组件,例如检查你是否:

    已将 export * from &lt;your-component&gt; 添加到您的 public-api.ts 文件中 将您的组件添加到导出它的库模块的exports

    您如何导入库组件,例如检查你是否:

    链接图书馆? cd /path/to/&lt;your-library&gt; &amp;&amp; npm link 链接应用程序?:cd /path/to/app &amp;&amp; npm link &lt;your-library&gt; 将库 NgModule(s) YourLibraryModule 添加到您的应用程序主 NgModule 的 imports:[]

    你可能忘记在你的 App NgModule 中声明父组件了!!

    这个很大,不常被提及。在 Angular 10、11 中,您可能忘记将引用缺少库组件的应用程序组件添加到 declarations,语言服务/编译器会抱怨缺少库组件,但不会提及应用程序组件被错误导出!

为什么要重启 Angular 语言服务?

有时,一旦您重新启动语言服务(例如重新启动 VSCode),错误可能会改变。对于我上面提到的场景3,错误变为:

Error: Cannot determine the module for class YourAppComponent in YourApp/src/app/components/your-app-component/your-app-component.component.ts! Add YourAppComponent to the NgModule to fix it

瞧!您看到了真正的问题并且很容易解决它!

【讨论】:

这应该是公认的答案。 “将您的组件添加到导出它的库模块的导出中”是让我感到沮丧的原因。 3 是适合我的。【参考方案7】:

您好,我在开发自定义库时遇到了同样的问题。我正在使用应用程序和库之间的链接。

我修复了在 tsconfig.json 中的 compilerOptions 下添加 preserveSymlinks。


  "compileOnSave": false,
  "compilerOptions": 
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "forceConsistentCasingInFileNames": true,
    "preserveSymlinks": true,
    ...

查看here了解更多详情。

【讨论】:

这在 monorepo 中对我有用。简单的解决方案,只需根据您的 nx 版本将其添加到父 tsconfig 或 tsconfig.base 中

以上是关于自定义库组件不是已知元素,但应用程序编译并运行的主要内容,如果未能解决你的问题,请参考以下文章

Ionic 4 无法导入自定义组件不是已知元素

错误:“组件选择器”不是已知元素:在 Angular 5 应用程序上运行 ng-build

ngModel、自定义管道和模式的单元测试错误[重复]

SLX 云是不是允许自定义库?

如何正确使用 vue js Web 组件内部的插槽并应用样式

我可以通过自定义元素使用 Preact 组件吗?