Moment: Add usage instructions with webpack

Created on 22 Jan 2014  ·  31Comments  ·  Source: moment/moment

Add to the section Where to use it instructions for properly integrating Moment.js with webpack.

require('momentjs/moment.js') causes several errors like this:

ERROR in ./app/bower_components/momentjs/lang/ar-ma.js
Module not found: Error: Cannot resolve module moment in /home/fernando/work/myproject/myproject-manage-app/app/bower_components/momentjs/lang
 @ ./app/bower_components/momentjs/lang/ar-ma.js 8:8-35

ERROR in ./app/bower_components/momentjs/lang/ar.js
Module not found: Error: Cannot resolve module moment in /home/fernando/work/myproject/myproject-manage-app/app/bower_components/momentjs/lang
 @ ./app/bower_components/momentjs/lang/ar.js 8:8-35

require ('momentjs/min/moment-with-langs.js') causes this warning:

WARNING in ./app/bower_components/momentjs/min/moment-with-langs.js
Module not found: Error: Cannot resolve file or directory ./lang in /home/fernando/work/myproject/myproject-manage-app/app/bower_components/momentjs/min
 @ ./app/bower_components/momentjs/min/moment-with-langs.js 808:24-46
Documentation

Most helpful comment

As @sokra suggested, I have added the following plugin in order to require only the necessary locale. Also notice that lang directory in moment has been changed to locale.

plugins: [
    new webpack.ContextReplacementPlugin(/moment[\\\/]locale$/, /^\.\/(en|ko|ja|zh-cn)$/)
]

All 31 comments

I've never used Webpack, so I'm unsure what those instructions would be. Were you able to figure it out? If so, we could add your instructions.

Thanks for the reply.

Not yet, but I'll keep you posted.

The language files are looking for a module moment. See header:

    if (typeof define === 'function' && define.amd) {
        define(['moment'], factory); // AMD

moment is actually the correct name for this module (see package.json) and everything just works if you install it from npm.

@fernandoacorreia Your folder is named momentjs.

@icambron Why not define(['../moment'], factory); as with CommonJs?

It would be better when the order of CommonJs and AMD is consistent in the lang files and the moment.js file.


By default webpack includes all languages because of this statement require('./lang/' + k);. You can override this with the ContextReplacementPlugin:

new webpack.ContextReplacementPlugin(/moment[\\\/]lang$/, /^\.\/(en-gb|de|pl)$/)

@sokra Thanks for explaining about the inconsistency in the module definitions. @icambron can you take a look at these suggestions?

By the way, the directory is named momentjs because I installed it following the instructions here:

bower install --save momentjs

I'm declaring the pathname when requiring, like require ('momentjs/min/moment-with-langs.js').

hmm ok... it works if you use the node.js instructions.

@sokra That helps. Thanks a lot for debugging this. Although I don't want to install it via npm; I'm installing all my frontend dependencies via bower and I only search for modules in bower_components.

@icambron To update the instructions to make it compatible with webpack (and, presumably, other module loaders), in the docs change this line:

bower install --save momentjs

to:

bower install --save moment=momentjs

The npm instructions worked for me, but not bower install --save moment=momentjs

@Sigfried What does your bower.json file look like? Mine has this line:

"moment": "momentjs#~2.5.1"

My webpack.config.js has:

module.exports = {
  resolve: {
    alias: {
      moment: 'moment/moment.js',
    },
    modulesDirectories: ['app/bower_components']
  }
};

I'm requiring moment as:

var moment = require('moment');

I'm using a standard Yeoman directory structure.

That did it for me. Thanks!
(Except I wasn't using Yeoman and now I'm wondering if I need to start doing that... The Javascript ecosystem is amazing, I've spend the last three months doing nothing but saving time! :)

Now you can use bower install --save moment

@ichernev That sounds good. In this case, I believe that updating the Where to use it documentation would resolve this issue.

Bit late on this, but now one can use the provide plugin

    plugins: [
        new webpack.ProvidePlugin({
           "window.moment": "moment"
        }),
        new BowerWebpackPlugin()
    ]

As @sokra suggested, I have added the following plugin in order to require only the necessary locale. Also notice that lang directory in moment has been changed to locale.

plugins: [
    new webpack.ContextReplacementPlugin(/moment[\\\/]locale$/, /^\.\/(en|ko|ja|zh-cn)$/)
]

Added doc item as moment/momentjs.com#269. Will track there.

I'm using es6, typescript, and very tight tslint rules. This is what I ended up doing to get moment into the project:

import "expose?moment!imports?this=>window&exports=>false&define=>false!exports?window.moment!moment";

I just created an empty 'locale' folder in the same folder as 'moment.min.js', so that it includes all of the js files in that folder.

It's a hack but it works.

To load languages in Webpack lazy / dynamically you can use with bundle-loader:

Step 1 - in webpack configuration:

new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), // to not to load all locales

Step 2 - in the client code:

require('bundle!moment/locale/' + locale + '.js')(function () {
  moment().locale(locale).format('lll');
  // note that now you can use the locale even outside of this callback
});

In my case (webpack + npm install moment) the issue was with webpack looking for locales inside the src/lib/locale folder, because that's where moment.js was being picked up.

I removed the node_modules/moment/src folder altogether, and import moment setting its locale using e.g.:

import moment from 'moment';
import 'moment/locale/en-gb';
moment.locale('en-gb');

Everything works perfectly, no warnings, and only the locales I import explicitly are included in the build (even without using the webpack.ContextReplacementPlugin as explained in this comment, which I added at first)

@micheleb the actual cause for looking in that subfolder is the incorrect setting of jsnext:main in momentjs's package.json, which is respected by webpack 2.

jsnext:main should _not_ point to the raw source code, but to a build of the module that does use ES6 module syntax.

This can be worked around by aliasing 'moment' to 'moment/moment.js' (the commonjs "main") in your webpack config (resolve: { alias: { moment: 'moment/moment.js' } }).

EDIT: Alternatively, a use of the ContextReplacementPlugin that uses the locale data from the src dir (i.e. that requests the same moment module as jsnext:main) is similar to:

new webpack.ContextReplacementPlugin(/^\.\/locale$/, context => {
  if (!/\/moment\//.test(context.context)) { return }
  // context needs to be modified in place
  Object.assign(context, {
    // include only CJK
    regExp: /^\.\/(ja|ko|zh)/,
    // point to the locale data folder relative to moment's src/lib/locale
    request: '../../locale'
  })
}),

This probably could be written without using the callback, but I wanted to be "more sure" that this would only apply to a ./locale request inside the moment module.

Make sure the request doesn't point to ../../../locale; while that will compile, it will result in 2 whole copies of moment being bundled.

@sokra what happens if async: true gets set in the context? I can see that the modules are generated as separate chunks if I do that, but what is the expected runtime behavior; a crash? I assume it is true "by default" if it's called for handling a require.ensure / System.import's context?

was this fixed? if not, should it be re-opened?

Why was this closed? This is still an occurring issue.

@ajohnsonRH

"I believe that updating the documentation would resolve this issue."

"Added doc item as moment/momentjs.com#269. Will track there."

So, the issue was closed here because it's been superseded by an issue in Moment's documentation website. We'd love for someone to write a PR there to resolve moment/momentjs.com#269.

@butterflyhug

This fix worked for me:

  1. do the npm install
  2. open vendor.ts and add the line import 'moment'

For reference:
Using Angular2 v2.0.0, Webpack ^1.13.0

Is it possible to not includes all the locale without adding configurations to webpack? I'm using create-react-app and I don't have the ability to edit the webpack config file.

I search everywhere and it always seems to come back to adding a config line in webpack.
https://github.com/moment/moment/issues/2373
https://github.com/moment/moment/issues/2416

Agreed, I think requiring the locales should be explicit only, never implicit.

It's so obvious according to the number of issues raised here in moment, in webpack, in bower, npm, and the time spent by everyone to circumvent it since several _years_.

@ajohnsonRH

I installed npm packs, but when I do

import moment from 'moment-timezone';

moment is always undefined. How that?

I am having this same problem using Angular 2 CLI project. Has anyone found a working solution yet?

Looking for clues for an Angular CLI project too

Any clues for Angular CLI ?

As you can see I asked 4 months ago about the CLI and no answers, our solution was to simply replace moment with date-fns, and since we are also using chartjs in our project and it has a moment dependency we are in the process of replacing that too.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

RobinvanderVliet picture RobinvanderVliet  ·  3Comments

vbullinger picture vbullinger  ·  3Comments

tanepiper picture tanepiper  ·  3Comments

ninigix picture ninigix  ·  3Comments

4rg0n picture 4rg0n  ·  3Comments