【问题标题】:Angular / Typescript class.name does not work in production buildAngular / Typescript class.name 在生产构建中不起作用
【发布时间】:2018-07-23 08:43:15
【问题描述】:

使用 Angular 5。class.name 属性面临一个奇怪的问题。我们在打字稿中有以下功能:

export class ApiService
{
  public list<T>(c: new(values: Object)=> T)
  {
    var cname = c.name;
    ....
  }
}

现在,如果我在 Angular (ng-build) 的开发版本中使用此功能,如下所示:

export class Employee()
{
    public id:string;
    public name: string;

    constructor(values: Object = {}) {          
       Object.assign(this, values);          
    }
}

在某处的代码中:

var list = api.list(Employee);

以上方法有效,在列表函数中我得到 cname = 'Employee'

但是,如果我们使用 ng build --env=prod 构建此解决方案,代码将失败,我们会得到 cname = undefined。

为什么会发生这种情况,如何解决?在开发构建中编译和工作的东西不应该在生产中工作吗?

【问题讨论】:

  • 无论如何我不会依赖函数/类名,因为它可能会在缩小后发生变化。
  • 为什么你在这个泛型中使用“新”关键字?
  • 嗯,这是我们在文档中看到的使泛型工作的语法,否则会出错。

标签: javascript angularjs typescript angular5


【解决方案1】:

您可能会遇到缩小问题,该问题仅在 prod 构建期间发生。缩小将重命名您的类以实现最小的输出文件大小。

有关相关讨论,请参阅此问题和答案:Angular-cli : How to ignore class names from being minified

正如上面的答案提到的,为了配置这个选项,你需要ng eject你的应用程序,这将允许你自定义 UglifyJS 选项(负责缩小的库),但这也会阻止你使用一些Angular CLI 的优秀功能(如 ng buildng serve)。

有关ng eject 的描述,请参阅此 GitHub 评论:https://github.com/angular/angular-cli/issues/6302#issuecomment-301220770

【讨论】:

  • 谢谢你。由于明显的缩小问题,我们确实意识到将 name 属性用于类是错误的。我们改用静态变量,效果很好。
【解决方案2】:

在“constructor.name”返回空字符串的生产代码中遇到了同样的问题。我的解决方案是装饰我需要的类,其中装饰器将在运行时使用任意类名或作为参数传递的类名重新分配“名称”:这是装饰器:

import "reflect-metadata";
var __global__ClassName__id__ = 0;
export function ClassName(useThisName: string = null) {
    return function (target: any) {
       if (target.name.length === 0 || useThisName !== null) {
            Object.defineProperty(target, "name", {
                value: useThisName !== null ? useThisName : `__ClassName__${++__global__ClassName__id__}`,
                enumerable: false,
                writable: false,
                configurable: true
            });
        }
    }
}

代码如下所示:

// generate a dynamic class name
@Decorator.ClassName()
export class PopupMessage{ }

// uses the argument as class name
@Decorator.ClassName("PopupMessage")
export class PopupMessage{ }

// and code will work as usual
var something = new Message.PopupMessage(1);
var samething = (<any>something).constructor.name == Message.PopupMessage.name;

【讨论】:

    猜你喜欢
    • 2020-11-26
    • 2021-12-07
    • 2021-12-18
    • 2019-03-30
    • 2018-01-18
    • 2018-08-27
    • 2020-09-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多