将 Rollup 用于 Angular 2 的 AoT 编译器并导入 Moment.js

Using Rollup for Angular 2's AoT compiler and importing Moment.js

我正在尝试遵循 Angular 2 的 official AoT guide,并且我在我的应用程序中使用了 Moment.js。 Moment.js 在我的 packages.json 文件中,我使用的是 2.15.0 版。到目前为止,我一直是这样导入的:

import * as moment from 'moment';

但是当我到达必须 运行 汇总的部分时,我最终遇到以下错误:

Cannot call a namespace ('moment')

这似乎与我根据 this 导入时刻的方式有关。那么,我该怎么做呢? 我似乎无法以任何其他方式导入时刻。如果我使用

import moment from 'moment'

我收到编译错误

External module ''moment'' has no default export

从版本 2.13.0 开始,

import * as moment from 'moment';

按照 this threadimport moment from 'moment'; 应该可行。

我终于设法摆脱了这两个错误。确实要避免:

Cannot call a namespace ('moment')

您需要使用:

import moment from 'moment'

那就避免

"moment" has no default export

你必须添加到你的 tsconfig.json (compilerOptions):

"allowSyntheticDefaultImports": true

编辑 2016 年 11 月 17 日

我还必须将以下内容添加到我的 rollup-config.js 文件中:

plugins: [
  nodeResolve({jsnext: true, module: true}),
  commonjs({
    include: [
        'node_modules/rxjs/**',
        'node_modules/moment/**'
      ]
    }
  }),
  uglify()
]

我遇到了与上述相同的问题。

import * as moment from 'moment'; - 在通过 systemjs 开发和加载时有效,但在汇总期间无效。

import moment from 'moment'; - 在汇总构建中工作但在开发期间不工作。

为了避免必须根据构建类型更改代码,我只是将 moment 添加为全局变量并创建了一个辅助函数,我在需要使用它的任何地方导入它而不是导入 moment。

这意味着相同的代码适用于两种类型的场景。虽然不是特别漂亮,如果有更好的方法请让me/us知道!

这是辅助函数,已添加到它自己的文件中 momentLoader.ts

import { default as mom } from 'moment';
export default function moment(args?: any): mom.Moment {
    let m = window["moment"];
    if (!m) { 
        console.error("moment does not exist globally.");
        return undefined;
    }
    return m(args);
}

要在其他 类 中使用 moment,我只需导入函数并像直接导入 moment 一样调用它:

import moment from '../../momentLoader';

let d = moment().utc("1995-12-25");

let m = moment("1995-12-25");

为了让 systemjs 将其作为全局加载,我只是按照以下步骤操作。 http://momentjs.com/docs/#/use-it/system-js/

在我的例子中,systemjs 的时刻配置如下所示:

let meta = {
    'lib:moment/moment.js': { format: 'global' }
};

System.config({
    paths: paths,
    map: map,
    packages: packages,
    meta: meta
});

System.import('lib:moment/moment.js');

对于汇总构建,您必须确保通过脚本标记将 moment.js 添加到页面的某处,因为不幸的是它不会包含在汇总构建文件中。

这是我使用打字稿(2.1.6)和汇总(0.41.4)制作工作时刻的方法。

  1. 要导入时刻,保持标准方式:

    import * as moment from 'moment';

import moment from 'moment'; 是 non-standard 对于没有默认导出的包,它会在运行时导致错误:moment_1.default is not a function

  1. 在 typescript 中使用 moment with by cast moment as any,并调用 default 函数:

    var momentFunc = (moment as any).default ? (moment as any).default : moment;
    var newFormat = momentFunc(value).format( format );
    

moment(value).format(format) 会导致 rollup tree shaking 出错:Cannot call a namespace ('moment')

我找到了解决手头问题的好方法:

Npm-install 附加包 moment-es6 提供默认导出。 然后从 'moment-es6' 而不是从 'moment':

导入

import moment from 'moment-es6';

  • 要与 systemjs 一起使用,请将以下内容添加到 systemjs.config.js 映射部分:
    'moment-es6': 'npm:moment-es6/index.js'

  • 'node_modules/moment-es6/**' 添加到汇总配置 commonjs 部分 (rollup-plugin-commonjs) 的 include

我们在 ng-packagr 中遇到了类似的问题,它使用 rollup 生成可以在 npm 存储库中发布的模块。 我们的项目是使用@angular-cli(使用 webpack)构建的。

我们有 2 个使用星号方法导入的依赖项:

 import * as dataUrl from 'dataurl';

工作正常,用法如下:

 dataUrl.parse(url)

另一个导入给出了错误(无法调用命名空间),因为导出的对象将用作函数:

 import * as svgPanZoom from 'svg-pan-zoom';
 svgPanZoom(element); <== error: Cannot call a namespace

我们可以通过将导出的初始化函数分配给另一个 const 并在代码中使用它来解决这个问题:

 import * as svgPanZoomImport from 'svg-pan-zoom';
 const svgPanZoom = svgPanZoomImport;

 svgPanZoom(element);

我们还如上所述进行了 tsconfig.json 配置更改。

版本: ng-packagr:1.4.1 汇总:0.50.0 打字稿:2.3.5 @angular/cli:1.4.8 网络包:3.7.1

希望对您有所帮助,

罗布

我尝试了以上所有解决方案,但 none 对我有用。有效的是

import moment from 'moment-with-locales-es6';

在我的 Angular 5 (5.2.9) 项目(从 Ng2 升级)中使用 momentJs (2.24) 时遇到同样的问题,使用 Gulp 和 Rollup (0.58.0) 用于产品构建。

正如前面提到的那些人import * as moment from 'moment'; 仅适用于在包列表中引用 momentJs 的开发(通过 SystemJS):

{
  name: 'moment',
  path: 'node_modules/moment/min/moment.min.js'
}

其他情况是 Rollup 用法(生产构建)——momentJs 的代码作为 ES6 模块(在 moment/src 中),但它以不同的方式导出(然后是通常的导出)。 这就是 import moment from 'moment'; 使用 Rollup 的

的原因
include: [
  'node_modules/rxjs/**',
]

和 ES6 模块导入。

是的,使用 ES6 包装器(例如 moment-es6 左右)是简单的解决方案。但它总是需要momentJs。 同时对于这个问题还有一个更简单的解决方案——将您的导入行从 Dev 替换为 Prod。 例如,Gulp 可以在某些步骤中使用 gulp-replace

return gulp.src([
     ...
    ])
    .pipe(replace('import * as moment from \'moment\';', 'import moment from \'moment\';'))
     ...;