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

南楼画角 提交于 2019-11-28 20:59:27

问题


I'm trying to follow the official AoT guide for Angular 2, and I'm using Moment.js in my application. Moment.js is on my packages.json file, and I'm using version 2.15.0. I've been importing it like this so far:

import * as moment from 'moment';

But when I get to the part where I have to run rollup, I end up with the following error:

Cannot call a namespace ('moment')

Which appears to be related to the way I import moment according to this. So, how am I supposed to do this? I can't seem to import moment any other way. If I use

import moment from 'moment'

I get the compile error

External module ''moment'' has no default export


回答1:


I have finally managed to get rid of both errors. Indeed to avoid:

Cannot call a namespace ('moment')

You need to use:

import moment from 'moment'

Then to avoid

"moment" has no default export

You have to add into your tsconfig.json (compilerOptions):

"allowSyntheticDefaultImports": true

EDIT 17/11/2016

I also had to add the following to my rollup-config.js file:

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



回答2:


I found a nice solution for the problem at hand:

Npm-install additional package moment-es6 which provides a default export. Then import from 'moment-es6' instead of from 'moment':

import moment from 'moment-es6';

  • For use with systemjs, add the following to the systemjs.config.js map section:
    'moment-es6': 'npm:moment-es6/index.js'

  • add 'node_modules/moment-es6/**' to the include's of your rollup configs commonjs section (rollup-plugin-commonjs)




回答3:


Here is what I did to make work moment with typescript (at 2.1.6) and rollup (0.41.4).

  1. To import moment, keep the standard way:

    import * as moment from 'moment';

import moment from 'moment'; is non-standard for a package without a default export, it will result an error at runtime: moment_1.default is not a function

  1. In typescript use moment with by casting moment as any, and call the default function:

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

moment(value).format(format) will result an error at rollup tree shaking: Cannot call a namespace ('moment')




回答4:


We had a similar issue with ng-packagr which uses rollup to generate a module that can be published in an npm repo. Our project was built-up using @angular-cli (using webpack).

We have 2 dependencies that are imported using the asteriks method:

 import * as dataUrl from 'dataurl';

Worked fine, is used like:

 dataUrl.parse(url)

Another import gave the error (Cannot call a namespace) because the exported object is to be used as a function:

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

We could workaround this by assigning the exported initializer function to another const and use that in the code:

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

 svgPanZoom(element);

We also made the tsconfig.json config change as described above.

Versions: ng-packagr: 1.4.1 rollup: 0.50.0 typescript: 2.3.5 @angular/cli: 1.4.8 webpack: 3.7.1

Hope this help,

Rob




回答5:


I was having the same problems described above.

import * as moment from 'moment'; - worked when developing and loading via systemjs, but not during rollup.

import moment from 'moment'; - worked in a rollup build but not during development.

To avoid having to change code depending on build type, I just added moment as a global and created a helper function that I import everywhere I need to use it instead of importing moment.

This means the same code works for both types of scenarios. It's not particularly pretty though, if there's a better way please let me/us know!

Here's the helper function, added to it's own file 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);
}

To use moment in other classes I just import the function and call it as if I'd imported moment directly:

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

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

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

To get systemjs to load it as a global, I just followed these steps. http://momentjs.com/docs/#/use-it/system-js/

In my case the moment config for systemjs looks like this:

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

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

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

For the rollup build you'll have to make sure moment.js is added to the page somewhere via a script tag, as it won't get included in the rollup build file unfortunately.




回答6:


Going by this thread, import moment from 'moment'; should work.




回答7:


As of version 2.13.0,

import * as moment from 'moment';




回答8:


I tried all the solutions above, but none worked for me. What worked was

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



回答9:


Had same problem with momentJs (2.24) usage in my Angular 5 (5.2.9) project (upgraded from Ng2) with Gulp and Rollup (0.58.0) for prod build.

As guys mentioned earlier here import * as moment from 'moment'; works only for deving (via SystemJS) with referring momentJs in packages list:

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

Other case is Rollup usage (Production build) - momentJs have its code as ES6 module (in moment/src), but it exports in different way (then usual export). That's why import moment from 'moment'; works with Rollup's

include: [
  'node_modules/rxjs/**',
]

and ES6 modules import.

Yes, to use ES6 wrapper (such as moment-es6 or so) is simple solution. But it always requires momentJs. Same time there is one more simple solution for this issue - replace your import row from Dev to Prod. For example, Gulp can use gulp-replace at some step:

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


来源:https://stackoverflow.com/questions/39519823/using-rollup-for-angular-2s-aot-compiler-and-importing-moment-js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!