Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angular npm 包 ng-packagr打包遇到的坑 #121

Open
deepthan opened this issue Feb 22, 2021 · 0 comments
Open

Angular npm 包 ng-packagr打包遇到的坑 #121

deepthan opened this issue Feb 22, 2021 · 0 comments

Comments

@deepthan
Copy link
Owner

1. es6语法不支持mapstartsWith等报错

这是因为在配置文件中默认配置的是es5,所以需要更为es6+,在最外层tsconfig.json中将target更改为es6,自己模块内的tsconfig.lib.json中的target也需要更改为es6

tsconfig.json

{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "module": "es2015",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",  // <-- 这里改为es6 
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2018",
      "dom"
    ]
  }
}

参考地址

2. includes报错

Property 'includes' does not exist on type 'string[]'

报这个错的原因是includes在ES6中只能是string的方法,在ES7中可以对数组进行使用。

所以更新你的下面配置至es7

{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "outDir": "../../out-tsc/lib",
    "target": "es6",
    "module": "es6",
    ...
    "lib": [
      "dom",
      "es7"  <-- 这里
    ]
  },
 
}

3. 报错关于 Lambda not supported

/core/src/lib/core.module.ts:44:1: Error encountered in metadata genera                         ted for exported symbol 'CoreModule':
 F:/v3-npm-package/iThinkDT-front/projects/core/src/lib/core.module.ts:20:10: Metadata collected contains an err                         or that will be reported at runtime: Lambda not supported.
  {"__symbolic":"error","message":"Lambda not supported","line":19,"character":9}
Error: F:/v3-npm-package/iThinkDT-front/projects/core/src/lib/core.module.ts:44:1: Error encountered in metadata                          generated for exported symbol 'CoreModule':
 F:/v3-npm-package/iThinkDT-front/projects/core/src/lib/core.module.ts:20:10: Metadata collected contains an err                         or that will be reported at runtime: Lambda not supported.
  {"__symbolic":"error","message":"Lambda not supported","line":19,"character":9}
    at F:\v3-npm-package\iThinkDT-front\node_modules\@angular\compiler-cli\src\metadata\collector.js:708:31
    at Array.forEach (<anonymous>)
    at validateMetadata (F:\v3-npm-package\iThinkDT-front\node_modules\@angular\compiler-cli\src\metadata\collec                         tor.js:696:46)
    at MetadataCollector.getMetadata (F:\v3-npm-package\iThinkDT-front\node_modules\@angular\compiler-cli\src\me                         tadata\collector.js:551:21)

在你写

public static generateNonce(): Observable<string> {
    ...
 }
 @ngModule({
    ...
 })

这样一个方法注入到元数据的时候,会报此错误,在函数前面加上一个注释// @dynamic可以让其不报错误。


public static generateNonce(): Observable<string> {
    ...
 }
 
 // @dynami
 
  @ngModule({
    ...
 })

具体原因参见:

https://github.com/angular/angular/issues/19698#issuecomment-338340211

4. 包名字不符合规范

package.json中配置包的名字中带/提示不符合要求,在前面加上@即可。

报错

{
  "name": "ithinkdt/core",
  "version": "0.0.4",
  "peerDependencies": {
    "@angular/common": "^7.0.0",
    "@angular/core": "^7.0.0"
  }
}

这样改即可

{
  "name": "@ithinkdt/core",
  "version": "0.0.4",
  "peerDependencies": {
    "@angular/common": "^7.0.0",
    "@angular/core": "^7.0.0"
  }
}

这样配置的话会成为私有包,所以得加上--access=public 改成公用包发布

npm publish dist/core --access=public 

参考

https://www.w3cvip.org/topics/393

5. 注释不需要注明参数类型

因为我们用的是ts,已经对参数和返回的值做了类型限定,所以不需要再注明类型。

错误写法

/**
 *@param {string} b
 */
a(b:string){
  ... 
}

规范写法: 去除类型注释

/**
 *@param b
 */
a(b:string){
  ... 
}

6. 打包之后新抛出的服务或者组件提示未找到

这是因为编辑器缓存的原因,需要重启下编辑器即可。

7. rxjs打包出错

打包之后成了$urlChange: import("rxjs/internal/Observable").Observable<{}>;
具体代码如下

打包前:

public urlChange = new Subject();
urlChange$ = this.urlChange.asObservable();

打包后:

urlChange: Subject<{}>;
urlChange$: import("rxjs/internal/Observable").Observable<{}>;
constructor();

}

需要将urlChange$ = this.urlChange.asObservable();写到构造器里面初始化

public urlChange = new Subject();
urlChange$: any;

constructor() {
  this.urlChange$ = this.urlChange.asObservable();
}

即可成功打包。

subject方法写法如下:

错误写法:

public urlChange = new Subject();
urlChange$ = this.urlChange.asObservable();

// 有个推送的语句
this.urlChange.next(data);

正确写法

urlChange$ = new Subject<>();
// 有个推送的语句
this.$urlChange.next(data);

8. 在module.ts中报错symbols are not supported in decorators but....

具体信息

core\src\lib\core.module.ts(25,7): Error during template compile of 'CoreModule'
  Reference to a local (non-exported) symbols are not supported in decorators but 'PROVIDERS' was referenced
    Consider exporting 'PROVIDERS'.

如果你的module中有函数的话需要把这个函数抛出即可。

错误写法

function a(){
    ...
}
@ngModule({
 ...
})

正确写法

export function a(){
    ...
}
@ngModule({
 ...
})

9. 打包报引用的npm抛出来的未定义

错误1

: Unexpected value 'undefined' exported by the module 'IThinkDTSharedModule in F:/v3-npm-package/iThinkDT-front/node_modules/@ithinkdt/shared/ithinkdt-shared.d.ts'
: Unexpected value 'undefined' declared by the module 'IThinkDTSharedModule in F:/v3-npm-package/iThinkDT-front/node_modules/@ithinkdt/shared/ithinkdt-shared.d.ts'
: Cannot determine the module for class TheadFixedDirective in F:/v3-npm-package/iThinkDT-front/node_modules/@ithinkdt/shared/ithinkdt-shared.d.ts! Add TheadFixedDire                        ctive to the NgModule to fix it.
Cannot determine the module for class PermissionDirective in F:/v3-npm-package/iThinkDT-front/node_modules/@ithinkdt/shared/ithinkdt-shared.d.ts! Add PermissionDirect                        ive to the NgModule to fix it.

Error: : Unexpected value 'undefined' exported by the module 'IThinkDTSharedModule in F:/v3-npm-package/iThinkDT-front/node_modules/@ithinkdt/shared/ithinkdt-shared.d                        .ts'
: Unexpected value 'undefined' declared by the module 'IThinkDTSharedModule in F:/v3-npm-package/iThinkDT-front/node_modules/@ithinkdt/shared/ithinkdt-shared.d.ts'
: Cannot determine the module for class TheadFixedDirective in F:/v3-npm-package/iThinkDT-front/node_modules/@ithinkdt/shared/ithinkdt-shared.d.ts! Add TheadFixedDire                        ctive to the NgModule to fix it.
Cannot determine the module for class PermissionDirective in F:/v3-npm-package/iThinkDT-front/node_modules/@ithinkdt/shared/ithinkdt-shared.d.ts! Add PermissionDirect                        ive to the NgModule to fix it.

错误2

Cannot read property 'module' of undefined
TypeError: Cannot read property 'module' of undefined

解决办法

9.1. 问题
之前写法是在auth模块的文件夹中建立了一个index.ts把组件抛出来了,然后在module中直接引用的,这样会报这个错误。

组件文件夹里的index.ts

export * from './login/login.component';
export * from './register/register.component';

module中的写法

import { LoginComponent, RegisterComponent } from './auth';

9.2. 错误1解决办法: 加上index

module中的写法

import { LoginComponent, RegisterComponent } from './auth/index';

但是这样的话之前错误不会报了,会报错误2

Cannot read property 'module' of undefined
TypeError: Cannot read property 'module' of undefined

9.3. 错误2解决办法: 一个一个引用
把你的组件等从它定义的地方一个一个引用过来即可解决问题。

module中的写法

import { LoginComponent } from './login/login.component.ts';
import { RegisterComponent } from './register/register.component.ts';

10. 报错关于 Cannot call a namespace ('moment')

错误信息如下

  Cannot call a namespace ('moment')

moment引进来赋值给一个常量即可

import * as moment_ from 'moment';

const moment = moment_;

参考

https://github.com/jvandemo/generator-angular2-library/issues/221#issuecomment-355945207

11. http拦截器不起作用

httpClientModule是http服务的模块,在项目中的某个懒加载模块再次引入的话会覆盖之前的http设置,这样注册在根模块的拦截器就会失效。
如果在npm包中配置了拦截器,用户项目中引入了http模块拦截器也会失效。

即最好保证httpClientModule在一个项目中只会被注入到module中一次。官方文档参考:

https://angular.io/guide/http#setup-installing-the-module

问题讨论:
HTTP_INTERCEPTORS are reset when a lazy loaded module imports another module importing HttpClientModule

12. 在npm包的ngModule中使用xxx()导致报错Function calls are not supported

具体报错信息如下

Function calls are not supported in decorators but 'DndModule' was called.

解决方案

RouterModule是angular的路由模块, routes是自己配置的路由。
进行如下改写即可解决错误。

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

export const routerModuleForChild: ModuleWithProviders = RouterModule.forChild(routes)

@NgModule({
  imports: [
    routerModuleForChild
  ],
  ...
})

参考https://github.com/ng-packagr/ng-packagr/issues/778#issuecomment-385122626

13. 路由中懒加载引入npm包抛出模块报错

ERROR in Could not resolve module AuthModule relative to pages/pages.module.ts

之前的写法:

import {
  AuthModule
} from '@my/pages';

export const PagesRouting: Routes = [
  {
    path: 'auth',
    loadChildren: 'AuthModule'
  },
]

正确写法

import {
  AuthModule
} from '@my/pages';

export const PagesRouting: Routes = [
  {
    path: 'auth',
    loadChildren: () => AuthModule
  },
]

npm包中做路由懒加载也需要这样写。

参考https://github.com/aspnet/JavaScriptServices/issues/1258#issuecomment-327818748

14. 路由打包时构建错误,ModuleWithProviders未被成功引入

npm包会构建成这样:

打包前

export const routerModuleForChild = RouterModule.forChild(routers)

打包后

export declare const routerModuleForChild: import("@angular/core/src/metadata/ng_module").ModuleWithProviders<RouterModule>;;

正确写法:

import { ModuleWithProviders } from "@angular/core";

export const routing: ModuleWithProviders = RouterModule.forRoot(routers);

参考https://stackoverflow.com/questions/41134288/angular-2-routing-error-with-modulewithproviders

路由配置时报路由配置错误

unhandled Promise rejection: Invalid configuration of route 'pages/'. One of the following must be provided: component, redirectTo, children or loadChildren ; Zone: <root> ; Task: Promise.then ; Value: Error: Invalid configuration of route 'pages/'. One of the following must be provided: component, redirectTo, children or loadChildren

这是因为路由里面有个空的{}什么都没填,将其删除即可。

{ path: '401', component: Exception401Component, },
{
    // path: 'demo',
    // loadChildren: './demo/demo.module#DemoModule'
},
{ path: '403', component: Exception403Component},

删除后

{ path: '401', component: Exception401Component, },
{ path: '403', component: Exception403Component},

15. 路由模块报关于Consider changing the function expression into an exported function错误

引入npm包中的模块在路由中配置之后,报错如下

ERROR in src\app\pages\pages.module.ts(23,7): Error during template compile of 'PagesModule'
  Function expressions are not supported in decorators in 'PagesRouting'
    'PagesRouting' contains the error at src\app\pages\pages.routing.ts(24,19)
      Consider changing the function expression into an exported function.

之前写法

import {AModule,BModule,CModule} from 'ANpmPackage'

export const PagesRouting: Routes = [
  { path: 'a', loadChildren: ()=> AModule },
  { path: 'b', loadChildren: ()=> BModule },
  { path: 'c', loadChildren: ()=> CModule },
]

解决方法:

建立一个function抛出模块再引用这个方法。

正确写法

import {AModule,BModule,CModule} from 'ANpmPackage'

export function getAModule(){
    return AModule;
}

export function getBModule(){
    return BModule;
}

export function getCModule(){
    return CModule;
}

export const PagesRouting: Routes = [
  { path: 'a', loadChildren: getAModule },
  { path: 'b', loadChildren: getBModule },
  { path: 'c', loadChildren: getCModule },
]

16. 测试项目中一直报错Can't resolve all parameters for AppComponent

这是因为你项目的polyfills.ts文件中未引入'core-js/es7/reflect'包,引入即可。

import 'core-js/es7/reflect';

更多信息请参考:

https://github.com/angular/angular/issues/19417#issuecomment-359722822

17. Runtime compiler is not loaded

在本地开发可以运行并且能打包,但是打包之后放在服务器会报错,具体错误信息

main.e81fa16196eccd7cdc8b.js:1 ERROR Error: Uncaught (in promise): Error: Runtime compiler is not loaded
Error: Runtime compiler is not loaded

原因

解决办法:

app.routing.ts中,你之前的写法可能是这样的

import { Routes } from "@angular/router";
import { AModule } from '@my/lib';

export const AppRouting: Routes = [
  {
    path: "a",
    loadChildren: ()=> AModule
  },
]

或者是这样的

import { Routes } from "@angular/router";
import { AModule } from '@my/lib';

export function loadAModule(){
    return AModule;
}

export const AppRouting: Routes = [
  {
    path: "a",
    loadChildren: loadAModule
  },
]

又或者是这样的

import { Routes } from "@angular/router";
import { AModule } from '@my/lib';

export function loadAModule(){
    return System.import("@@my/lib").then(
        mod => mod.AModule
    );
}

export const AppRouting: Routes = [
  {
    path: "a",
    loadChildren: loadAModule
  },
]

都还是会报错,

解决办法

新增一个module,在这个模块里面把要用的包引进来,在路由中懒加载新建的这个模块即可。

新增的 A-module-loader.ts

import { NgModule } from "@angular/core";
import { AModule } from '@my/lib';

@NgModule({
  imports: [
    AModule
  ]
})
export class AModuleLoader {}

原来的app.routing.ts中可以这样写

import { Routes } from "@angular/router";


export const AppRouting: Routes = [
  {
    path: "a",
    loadChildren: './A-module-loader#AModuleLoader'
  },
]

参考

1. https://github.com/angular/angular-cli/issues/6373#issuecomment-319116889
2. https://github.com/angular/angular-cli/issues/6373#issuecomment-424819684
3. https://github.com/angular/angular-cli/issues/6373#issuecomment-303013724
4. https://github.com/angular/angular-cli/issues/6373#issuecomment-304922035
5. https://stackoverflow.com/questions/45503497/how-to-load-dynamic-external-components-into-angular-application/45506470#45506470
6. https://stackoverflow.com/questions/41438198/implementing-a-plugin-architecture-plugin-system-pluggable-framework-in-angu

18. project does not support the 'build' target

Project './projects/core' does not support the 'build' target.
Error: Project './projects/core' does not support the 'build' target.
    at BuildCommand.initialize (F:\AAA---v3-npm-package\iThinkDT-npm-package\node_modules\@angular\cli\models\architect-command.js:53:19)
    at process._tickCallback (internal/process/next_tick.js:68:7)
    at Function.Module.runMain (internal/modules/cjs/loader.js:721:11)
    at startup (internal/bootstrap/node.js:228:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:576:3)

这是因为在你的angular.json中未对打包规则进行配置,用ng g library xxx会自动新增打包规则,但是在项目中的angular.json则不会生成,需自己配置。
projects下面新增你的规则,如:

"projects": {
  "core": {
      "root": "projects/core",
      "sourceRoot": "projects/core/src",
      "projectType": "library",
      "prefix": "lib",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-ng-packagr:build",
          "options": {
            "tsConfig": "projects/core/tsconfig.lib.json",
            "project": "projects/core/ng-package.json"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "projects/core/src/test.ts",
            "tsConfig": "projects/core/tsconfig.spec.json",
            "karmaConfig": "projects/core/karma.conf.js"
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "projects/core/tsconfig.lib.json",
              "projects/core/tsconfig.spec.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    },
}

19. Cannot find module 'tsickle/src/tsickle'

这是ng-packer更新版本之后依赖了tsickle包,因此下载这个包即可。

npm i --save-dev tsickle
yarn add tsickle
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant