在使用Angular Typescript库中使用MomentJS时出现错误

18
我正在使用jvandemo/generator-angular2-library作为起点来构建一个基于Angular(2+)的组件库,该起点使用Rollup作为模块构建器。我正在创建的库中的组件使用MomentJS
在包含MomentJS时,我遇到了各种构建问题。
我首先使用import moment from 'moment';将moment引入组件,但这会在构建时产生以下错误;
[17:26:28] Starting 'ngc'...
Error at /Users/chris/angular-library/.tmp/components/my-library/my-component.component.ts:6:8: Module '"/Users/chris/my-library/node_modules/moment/moment"' has no default export.

我发现这个stackoverflow问题,上面说要使用import * as moment from 'moment';,然而我用了这个却出现了以下错误:

'moment' is imported by build/components/my-component.component.js, but could not be resolved – treating it as an external dependency

events.js:182
      throw er; // Unhandled 'error' event
      ^
Error: Cannot call a namespace ('moment')
    at error (/Users/chris/angular-library/node_modules/rollup/dist/rollup.js:185:14)

据我所知,这似乎是唯一的两个选项,但我都无法使其正常工作,我错过了什么吗?
编辑
我已将此问题添加到库的Github存储库中,其中包含最简化的复制步骤。

将 "import moment from 'moment'" 更改为 "import * as moment from 'moment'" 可以简化代码。 - Surely
1
@当然,如上所述,这样做会导致“错误:无法调用命名空间('moment')”。 - Chris Brown
1
{btsdaf} - Chris Brown
我需要安装 yogenerator-angular2-library 才能有机会重现您的问题吗? - Sergey
1
@PeterS 最新的v2版本(2.19.1) - Chris Brown
显示剩余13条评论
3个回答

35

错误非常明确而具体

错误:无法调用命名空间('moment') 在error (/Users/chris/angular-library/node_modules/rollup/dist/rollup.js:185:14)

这符合ES模块规范。

这意味着以下方式导入moment或任何你想要调用的内容是无效的,因为模块命名空间对象(例如由* as ns创建的对象)不能被调用。

import * as moment from 'moment';

正确的表单是ngc引发错误的表单。

import moment from 'moment';

首先,为了使这个工作起来,你需要指定--allowSyntheticDefaultImports标志。

tsconfig.json

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true
  }
}

假设ngc将识别该选项,您仍需要解决另一个问题。

上面的标志是为使用SystemJS或Webpack等工具的用户准备的,这些工具执行综合,从而允许此类代码进行类型检查。

从TypeScript 2.7开始,您现在可以指定--esModuleInterop标志,使语言在转译过程中提供综合功能。

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true
  }
}

请注意,如果您使用的是 TypeScript 2.7 之前的版本 而且 您正在编译为 CommonJS、AMD 或 UMD 模块(例如使用 --module commonjs),则正确的导入语法应该是:

import moment = require('moment');

import = require 语法是 TypeScript 特有的构造,目前已经大部分不再需要。它存在的原因是为了获取 AMD、CommonJS 或 UMD 模块的模块导出值和类型。"and" 很重要,因为 constvarlet = require 调用只在值空间中创建名称而不是类型空间。


当设置esModuleInterop=true时,allowSyntheticDefaultImports将默认为true,因此只需设置esModuleInterop=true即可。 - Esben Skov Pedersen
1
@EsbenSkovPedersen 当我写这段代码时,TypeScript存在一个错误,我认为在2.9或3.0版本中已经修复了,其中一个变量的类型并不意味着另一个变量的类型。 - Aluan Haddad
1
好知道。我写这篇文章更多是作为给未来读者的信息。 - Esben Skov Pedersen
我会添加一条注释。 - Aluan Haddad
1
这节省了很多时间。 - Just code

6

面向2018年及以后使用Angular6和当前版本的@angular/cli:

今天我遇到了这个问题,并在这里找到了解决方案。

import * as moment_ from 'moment';
const moment = moment_;

现在这个库对我来说可以编译通过了。


1
在示例指令中,当我使用以下内容时编译没有问题:
import { Directive, ElementRef } from '@angular/core';
import * as moment from '../node_modules/moment/moment';
@Directive({
  selector: '[sampleDirective]'
})
export class SampleDirective {

  constructor(private el: ElementRef) {
    moment.isDate('test');
  }

}

这些文件是从一个构建目录编译而来,该目录是根目录的子目录。你会收到关于“this”的进一步警告,如此处所述:

https://github.com/rollup/rollup/issues/794

我需要在gulfile中说明该库是外部的:
  external: [
    '@angular/core',
    '@angular/common',
    'moment'
  ],

从github链接中,您应该向两个rollup部分添加一个onwarn块:即“rollup:umd”和“rollup:fesm”

onwarn: function(warning) {
    // Skip certain warnings

    // should intercept ... but doesn't in some rollup versions
    if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; }

    // console.warn everything else
    console.warn( warning.message );
},

这是否有所帮助?

谢谢您的关注 - 当使用 moment.isDate() 时,这对我也有效,但是当使用 moment() 时它不起作用,所以遗憾的是我还是停留在同一点。值得一提的是,仅使用 moment.isDate() 时,import * as moment from 'moment'; 也可以正常工作,因此在那里不需要从 node_modules 导入。 - Chris Brown
使用import * as moment from 'moment'; 应该可以正常工作。如果不行,尝试npm uninstall moment ,然后 npm i moment@latest, rm -rf node/modules 并重新安装所有依赖项(npm i)。 - andrea06590

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接