New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webpack moment.js integration #3128

Closed
ichernev opened this Issue Oct 12, 2016 · 42 comments

Comments

Projects
None yet
@ichernev

ichernev commented Oct 12, 2016

I'm from the moment.js (http://github.com/moment) team, and some of our users that are also your users voice concerns that because of the way webpack is implemented all moment locale files (currently 104) are bundled together, and that increases the size of what is downloaded to the browser.

Recently there was a suggested "fix" in the moment code (moment/moment#3344), but then we figured it broke the require mechanism for other environments.

Also we happen to have no instructions on how to use moment and webpack (like here: http://momentjs.com/docs/#/use-it/).

Can you please give us a hand by saying what is the right way to use moment with webpack, so it won't include all locale files if the user wants so. I hope this will decrease number of issues sent to both projects :)

Note: A webpack user suggested the following: moment/moment#1435 (comment) but nobody has documented it yet: moment/momentjs.com#269

@TheLarkInn

This comment has been minimized.

Show comment
Hide comment
@TheLarkInn

TheLarkInn Oct 13, 2016

Member

@ichernev thank you so much for reaching out. ❤️❤️❤️❤️

We would be more than happy to help!!!

A cool idea 💡 that might be worth investigating is helping you guys create a 'example' or 'test' fixture of a small use case of webpack and moment together with one or many locales.

Pros:

  • the fixture can serve as a point of reference for users in regards to implementation
  • you can then run functional/integration smoke tests against this example for your test suite?

Thoughts?

Member

TheLarkInn commented Oct 13, 2016

@ichernev thank you so much for reaching out. ❤️❤️❤️❤️

We would be more than happy to help!!!

A cool idea 💡 that might be worth investigating is helping you guys create a 'example' or 'test' fixture of a small use case of webpack and moment together with one or many locales.

Pros:

  • the fixture can serve as a point of reference for users in regards to implementation
  • you can then run functional/integration smoke tests against this example for your test suite?

Thoughts?

@ichernev

This comment has been minimized.

Show comment
Hide comment
@ichernev

ichernev Oct 13, 2016

@TheLarkInn hello, thank you for the prompt response.

I like the fixture idea, we can take example from require.js documentation on our website, which mentions all the different (widely used) use-cases:

http://momentjs.com/docs/#/use-it/require-js/

Basically we'll need examples for:

  • core only (no locales)
  • core with a single locale (known in advance)
  • core with all locales
  • care + dynamically loading locales (if that is applicable to webpack at all)

ichernev commented Oct 13, 2016

@TheLarkInn hello, thank you for the prompt response.

I like the fixture idea, we can take example from require.js documentation on our website, which mentions all the different (widely used) use-cases:

http://momentjs.com/docs/#/use-it/require-js/

Basically we'll need examples for:

  • core only (no locales)
  • core with a single locale (known in advance)
  • core with all locales
  • care + dynamically loading locales (if that is applicable to webpack at all)
@rafde

This comment has been minimized.

Show comment
Hide comment
@rafde

rafde Oct 13, 2016

Contributor

@ichernev
new webpack.IgnorePlugin(/(locale)/, /node_modules.+(momentjs)/),

Contributor

rafde commented Oct 13, 2016

@ichernev
new webpack.IgnorePlugin(/(locale)/, /node_modules.+(momentjs)/),

@Kovensky

This comment has been minimized.

Show comment
Hide comment
@Kovensky

Kovensky Oct 13, 2016

Collaborator

@ichernev one problem is that your package.json points the jsnext:main entry point to your raw source code, instead of to a build of the source code that was emitted with ES6 modules. Your coding convention mostly keeps that from being a problem, but the actual issue is triggered by the relative require call.

In your main entry point, the mostly pre-bundled version, the relative require points to a locale folder that has actual locale data, so webpack happens to work there, but the require in the jsnext:main entry point points to a non-existing folder.

Now, because it is a dynamic require that webpack can parse, it actually creates a require context that can be modified by the ContextReplacementPlugin. The plugin can then be used to make it point to the correct folder, and restrict which imports are bundled.

This is how I dealt with it in my own codebase:

// restrict the extra locales that moment.js can load; en is always builtin
new webpack.ContextReplacementPlugin(/^\.\/locale$/, context => {
  // check if the context was created inside the moment package
  if (!/\/moment\//.test(context.context)) { return }
  // context needs to be modified in place
  Object.assign(context, {
    // include only japanese, korean and chinese variants
    // all tests are prefixed with './' so this must be part of the regExp
    // the default regExp includes everything; /^$/ could be used to include nothing
    regExp: /^\.\/(ja|ko|zh)/,
    // point to the locale data folder relative to moment/src/lib/locale
    request: '../../locale'
  })
})

This technically could be done with new webpack.ContextReplacementPlugin(/^\.\/locale$/, '../../locale', /^\.\/(ja|ko|zh)/), but there was no other way to make sure this would apply only to ./locale-relative requests made inside the moment module.

For dynamic loading of locales, moment would have to load locales with require.ensure instead of plain require. Webpack's parser supports conditional compilation for it with if (typeof require.ensure === 'function').

Collaborator

Kovensky commented Oct 13, 2016

@ichernev one problem is that your package.json points the jsnext:main entry point to your raw source code, instead of to a build of the source code that was emitted with ES6 modules. Your coding convention mostly keeps that from being a problem, but the actual issue is triggered by the relative require call.

In your main entry point, the mostly pre-bundled version, the relative require points to a locale folder that has actual locale data, so webpack happens to work there, but the require in the jsnext:main entry point points to a non-existing folder.

Now, because it is a dynamic require that webpack can parse, it actually creates a require context that can be modified by the ContextReplacementPlugin. The plugin can then be used to make it point to the correct folder, and restrict which imports are bundled.

This is how I dealt with it in my own codebase:

// restrict the extra locales that moment.js can load; en is always builtin
new webpack.ContextReplacementPlugin(/^\.\/locale$/, context => {
  // check if the context was created inside the moment package
  if (!/\/moment\//.test(context.context)) { return }
  // context needs to be modified in place
  Object.assign(context, {
    // include only japanese, korean and chinese variants
    // all tests are prefixed with './' so this must be part of the regExp
    // the default regExp includes everything; /^$/ could be used to include nothing
    regExp: /^\.\/(ja|ko|zh)/,
    // point to the locale data folder relative to moment/src/lib/locale
    request: '../../locale'
  })
})

This technically could be done with new webpack.ContextReplacementPlugin(/^\.\/locale$/, '../../locale', /^\.\/(ja|ko|zh)/), but there was no other way to make sure this would apply only to ./locale-relative requests made inside the moment module.

For dynamic loading of locales, moment would have to load locales with require.ensure instead of plain require. Webpack's parser supports conditional compilation for it with if (typeof require.ensure === 'function').

@ichernev

This comment has been minimized.

Show comment
Hide comment
@ichernev

ichernev Oct 13, 2016

@Kovensky thank you for this explanation.

The dynamic require use case is purely a user thing. I mean -- moment itself doesn't have interface to say "dynamically require a locale". It only has this hack to auto require locale on npm environment with require, and I believe it is the one causing trouble with webpack.

About you example with ContextReplacementPlugin -- where should this code be placed?

About the entry point being the ES6 code vs the bundled (es5) code -- I didn't understand if your solution works with both or just the ES6 code entry point. Also can you tell webpack which entry point to use? I mean do we need to change anything on moment end to make this work?

ichernev commented Oct 13, 2016

@Kovensky thank you for this explanation.

The dynamic require use case is purely a user thing. I mean -- moment itself doesn't have interface to say "dynamically require a locale". It only has this hack to auto require locale on npm environment with require, and I believe it is the one causing trouble with webpack.

About you example with ContextReplacementPlugin -- where should this code be placed?

About the entry point being the ES6 code vs the bundled (es5) code -- I didn't understand if your solution works with both or just the ES6 code entry point. Also can you tell webpack which entry point to use? I mean do we need to change anything on moment end to make this work?

@schmod

This comment has been minimized.

Show comment
Hide comment
@schmod

schmod Oct 18, 2016

Here's a dumb question.

Is there any way Moment could export a separate entry point that doesn't include references to locales, so we could write import moment from 'moment/no-locales'; or require('moment/no-locales'), and subsequently/manually load the locales that we need?

This isn't going to be a great long-term solution, but it seems like it might make folks "happy enough" in the short-term, and should work seamlessly in just about any environment that understands CJS.

schmod commented Oct 18, 2016

Here's a dumb question.

Is there any way Moment could export a separate entry point that doesn't include references to locales, so we could write import moment from 'moment/no-locales'; or require('moment/no-locales'), and subsequently/manually load the locales that we need?

This isn't going to be a great long-term solution, but it seems like it might make folks "happy enough" in the short-term, and should work seamlessly in just about any environment that understands CJS.

@TheLarkInn

This comment has been minimized.

Show comment
Hide comment
@TheLarkInn

TheLarkInn Oct 20, 2016

Member

@ichernev just following up to ensure all your questions are answered. When you have a PR up we would be more than happy to look it over. Or if you are at a stopping point @Kovensky could assist you further.

Member

TheLarkInn commented Oct 20, 2016

@ichernev just following up to ensure all your questions are answered. When you have a PR up we would be more than happy to look it over. Or if you are at a stopping point @Kovensky could assist you further.

@TheLarkInn

This comment has been minimized.

Show comment
Hide comment
@TheLarkInn

TheLarkInn Oct 20, 2016

Member

@ichernev also:

About you example with ContextReplacementPlugin -- where should this code be placed?

This would an item inside of the plugins property in the webpack config: which is an array of plugin instances

webpack.config.js

const webpack = require('webpack');

const config = {
  /* ... */
  plugins: [ 
  new webpack.ContextReplacementPlugin(/^\.\/locale$/, context => {
    // check if the context was created inside the moment package
    if (!/\/moment\//.test(context.context)) { return }
    // context needs to be modified in place
    Object.assign(context, {
      // include only japanese, korean and chinese variants
      // all tests are prefixed with './' so this must be part of the regExp
      // the default regExp includes everything; /^$/ could be used to include nothing
      regExp: /^\.\/(ja|ko|zh)/,
        // point to the locale data folder relative to moment/src/lib/locale
      request: '../../locale'
    })
  })

  ]
  /* ... */
}

module.exports = config;
Member

TheLarkInn commented Oct 20, 2016

@ichernev also:

About you example with ContextReplacementPlugin -- where should this code be placed?

This would an item inside of the plugins property in the webpack config: which is an array of plugin instances

webpack.config.js

const webpack = require('webpack');

const config = {
  /* ... */
  plugins: [ 
  new webpack.ContextReplacementPlugin(/^\.\/locale$/, context => {
    // check if the context was created inside the moment package
    if (!/\/moment\//.test(context.context)) { return }
    // context needs to be modified in place
    Object.assign(context, {
      // include only japanese, korean and chinese variants
      // all tests are prefixed with './' so this must be part of the regExp
      // the default regExp includes everything; /^$/ could be used to include nothing
      regExp: /^\.\/(ja|ko|zh)/,
        // point to the locale data folder relative to moment/src/lib/locale
      request: '../../locale'
    })
  })

  ]
  /* ... */
}

module.exports = config;
@ichernev

This comment has been minimized.

Show comment
Hide comment
@ichernev

ichernev Oct 20, 2016

@Kovensky @TheLarkInn so if I understand correctly, if the user specifies this blob in his config, the listed locales will be loaded in the "pack" and then using require a-la npm it will load them, but in case it requires something that is not "packed" it will fail?

If the user doesn't specify anything then all locales will be loadable with require (but this will increase the "pack").

I'm asking because we're discussing how to implement child locale loading: moment/moment#3336

Also is there away to go with @schmod suggestion. Basically define a separate npm/bower/git repo for webpack, that will have moment without locales and one with all locales and all locales separately and users can pack in a simpler way. I still don't understand how the packing will work in this case. Maybe the patch we reverted: https://github.com/moment/moment/pull/3344/files or the user has to somewhere specify all files he wants (so he either lists moment + a few locales, or moment-with-locales which contains all?).

ichernev commented Oct 20, 2016

@Kovensky @TheLarkInn so if I understand correctly, if the user specifies this blob in his config, the listed locales will be loaded in the "pack" and then using require a-la npm it will load them, but in case it requires something that is not "packed" it will fail?

If the user doesn't specify anything then all locales will be loadable with require (but this will increase the "pack").

I'm asking because we're discussing how to implement child locale loading: moment/moment#3336

Also is there away to go with @schmod suggestion. Basically define a separate npm/bower/git repo for webpack, that will have moment without locales and one with all locales and all locales separately and users can pack in a simpler way. I still don't understand how the packing will work in this case. Maybe the patch we reverted: https://github.com/moment/moment/pull/3344/files or the user has to somewhere specify all files he wants (so he either lists moment + a few locales, or moment-with-locales which contains all?).

@donaldpipowitch

This comment has been minimized.

Show comment
Hide comment
@donaldpipowitch

donaldpipowitch Nov 1, 2016

FYI: This problem isn't specific to moment.js. It would be nice to have a general recommendation how libs, which support multiple locales, should be used together with webpack. Other libs which I think of are https://github.com/andyearnshaw/Intl.js or https://github.com/angular/bower-angular-i18n. They don't have a require which includes all locales, but all of them need to be handled with some custom logic in some way. It would be nice to generalize the way how locale specific files are loaded.

donaldpipowitch commented Nov 1, 2016

FYI: This problem isn't specific to moment.js. It would be nice to have a general recommendation how libs, which support multiple locales, should be used together with webpack. Other libs which I think of are https://github.com/andyearnshaw/Intl.js or https://github.com/angular/bower-angular-i18n. They don't have a require which includes all locales, but all of them need to be handled with some custom logic in some way. It would be nice to generalize the way how locale specific files are loaded.

@orditeck

This comment has been minimized.

Show comment
Hide comment
@orditeck

orditeck Nov 18, 2016

Using create-react-app, we don't have access to webpack config. And according to the main contributor there, "It's really not right that a library requires changes in the config"

Wouldn't moment/moment#2373 be more appropriate? Or maybe that's the same thing you're aiming to do?

I just don't feel like playing with webpack config is the way to go to reduce moment's size in our builds...

orditeck commented Nov 18, 2016

Using create-react-app, we don't have access to webpack config. And according to the main contributor there, "It's really not right that a library requires changes in the config"

Wouldn't moment/moment#2373 be more appropriate? Or maybe that's the same thing you're aiming to do?

I just don't feel like playing with webpack config is the way to go to reduce moment's size in our builds...

@kossnocorp

This comment has been minimized.

Show comment
Hide comment
@kossnocorp

kossnocorp Dec 5, 2016

@donaldpipowitch date-fns solves it by passing locale as an argument https://date-fns.org/docs/I18n#usage.

API looks bulky, but it's easy to write own wrappers and include all necessary locales. It's even possible to load locales on demand when the user changes the language.

// app/_lib/format.js

var format = require('date-fns/format')

var locales = {
  en: require('date-fns/locale/en'),
  eo: require('date-fns/locale/eo'),
  ru: require('date-fns/locale/ru')
}

module.exports = function (date, formatStr) {
  return format(date, formatStr, {
    locale: locales[window.__localeId__] // or global.__localeId__
  })
}

// Later:

var format = require('app/_lib/format')

window.__localeId__ = 'en'
format(friday13, 'dddd D')
//=> 'Friday 13'

window.__localeId__ = 'eo'
format(friday13, 'dddd D')
//=> 'vendredo 13'

Not sure if it's applicable to Moment.js' current state as it has a monolithic core, but still should be possible to implement in the future.

kossnocorp commented Dec 5, 2016

@donaldpipowitch date-fns solves it by passing locale as an argument https://date-fns.org/docs/I18n#usage.

API looks bulky, but it's easy to write own wrappers and include all necessary locales. It's even possible to load locales on demand when the user changes the language.

// app/_lib/format.js

var format = require('date-fns/format')

var locales = {
  en: require('date-fns/locale/en'),
  eo: require('date-fns/locale/eo'),
  ru: require('date-fns/locale/ru')
}

module.exports = function (date, formatStr) {
  return format(date, formatStr, {
    locale: locales[window.__localeId__] // or global.__localeId__
  })
}

// Later:

var format = require('app/_lib/format')

window.__localeId__ = 'en'
format(friday13, 'dddd D')
//=> 'Friday 13'

window.__localeId__ = 'eo'
format(friday13, 'dddd D')
//=> 'vendredo 13'

Not sure if it's applicable to Moment.js' current state as it has a monolithic core, but still should be possible to implement in the future.

@tangoabcdelta

This comment has been minimized.

Show comment
Hide comment
@tangoabcdelta

tangoabcdelta Dec 25, 2016

Hi @ichernev & @TheLarkInn @yiminghe.

I was trying to build an app with react boilerplate using antd. Importing any component from antd results in errors.

May I recommend the aforementioned boilerplate to be the starting point for this?

tangoabcdelta commented Dec 25, 2016

Hi @ichernev & @TheLarkInn @yiminghe.

I was trying to build an app with react boilerplate using antd. Importing any component from antd results in errors.

May I recommend the aforementioned boilerplate to be the starting point for this?

@yiminghe

This comment has been minimized.

Show comment
Hide comment
@yiminghe

yiminghe Dec 26, 2016

@tangoabcdelta
use

 module: {
      noParse: [/moment.js/],
}

yiminghe commented Dec 26, 2016

@tangoabcdelta
use

 module: {
      noParse: [/moment.js/],
}
@andrewvmail

This comment has been minimized.

Show comment
Hide comment
@andrewvmail

andrewvmail Jan 5, 2017

ERROR in ./~/antd/lib/date-picker/locale/zh_CN.js
Module not found: Error: Can't resolve 'moment/locale/zh-cn' in '/Users/andrew/Desktop/lift-app/frontend/node_modules/antd/lib/date-picker/locale'
 @ ./~/antd/lib/date-picker/locale/zh_CN.js 23:0-30
 @ ./~/antd/lib/date-picker/wrapPicker.js
 @ ./~/antd/lib/date-picker/index.js
 @ ./~/antd/lib/index.js
 @ dll reactBoilerplateDeps

Getting this problem with webpack during the dll process i have, although after that using above methods i can get webpack to watch. whats the official integration method for moment with the require locale support?

andrewvmail commented Jan 5, 2017

ERROR in ./~/antd/lib/date-picker/locale/zh_CN.js
Module not found: Error: Can't resolve 'moment/locale/zh-cn' in '/Users/andrew/Desktop/lift-app/frontend/node_modules/antd/lib/date-picker/locale'
 @ ./~/antd/lib/date-picker/locale/zh_CN.js 23:0-30
 @ ./~/antd/lib/date-picker/wrapPicker.js
 @ ./~/antd/lib/date-picker/index.js
 @ ./~/antd/lib/index.js
 @ dll reactBoilerplateDeps

Getting this problem with webpack during the dll process i have, although after that using above methods i can get webpack to watch. whats the official integration method for moment with the require locale support?

@deveedutta

This comment has been minimized.

Show comment
Hide comment
@deveedutta

deveedutta Jan 5, 2017

@andrewvmail @18601673727 - suggest you to read + understand + remove the lines of code that trigger this error from antd/node_modules/moment . I tried the alias approach & removed 2-3 lines of code, it has been working normally ever since.

PS: It won't work with build environments. Therefore, you may have to freeze the antd library by including in your git repo.

OTHER: ant-design/ant-design#3947

deveedutta commented Jan 5, 2017

@andrewvmail @18601673727 - suggest you to read + understand + remove the lines of code that trigger this error from antd/node_modules/moment . I tried the alias approach & removed 2-3 lines of code, it has been working normally ever since.

PS: It won't work with build environments. Therefore, you may have to freeze the antd library by including in your git repo.

OTHER: ant-design/ant-design#3947

@andrewvmail

This comment has been minimized.

Show comment
Hide comment
@andrewvmail

andrewvmail Jan 5, 2017

@deveedutta

Thanks, yeah I was able to continue development by mucking around in the antd package in around datepicker module date-picker/locale/zh_CN.js:23

The guys at antd got me to create a new ticket at
ant-design/ant-design#4491

Nothing major just throwing it out there.

Cheers

andrewvmail commented Jan 5, 2017

@deveedutta

Thanks, yeah I was able to continue development by mucking around in the antd package in around datepicker module date-picker/locale/zh_CN.js:23

The guys at antd got me to create a new ticket at
ant-design/ant-design#4491

Nothing major just throwing it out there.

Cheers

@AaronHarris

This comment has been minimized.

Show comment
Hide comment
@AaronHarris

AaronHarris Feb 14, 2017

It seems this issue got sidetracked regarding the proper use of moment with webpack to reduce bundle sizes, specifically within the constraints of create-react-app. Is there a final word on this? I kind of favor the typescript style when it comes to importing locales.

AaronHarris commented Feb 14, 2017

It seems this issue got sidetracked regarding the proper use of moment with webpack to reduce bundle sizes, specifically within the constraints of create-react-app. Is there a final word on this? I kind of favor the typescript style when it comes to importing locales.

@75lb

This comment has been minimized.

Show comment
Hide comment
@75lb

75lb Feb 24, 2017

Until this is fixed, my solution is to simply avoid including moment in the webpack bundle. Load it as a regular browser script:

<script defer src="node_modules/moment/min/moment.min.js"></script>
<script defer src="node_modules/moment/locale/en-gb.js"></script>

Now you have moment in your web app at the cost of two requests and ~60Kb (as oppose to 0 additional requests but ~0.5Mb added to your bundle when using webpack).

75lb commented Feb 24, 2017

Until this is fixed, my solution is to simply avoid including moment in the webpack bundle. Load it as a regular browser script:

<script defer src="node_modules/moment/min/moment.min.js"></script>
<script defer src="node_modules/moment/locale/en-gb.js"></script>

Now you have moment in your web app at the cost of two requests and ~60Kb (as oppose to 0 additional requests but ~0.5Mb added to your bundle when using webpack).

@hakunin

This comment has been minimized.

Show comment
Hide comment
@hakunin

hakunin Mar 10, 2017

Guys this has been going on for a while and seems really easy to fix. Currently everyone who uses moment (awesome library btw) is including ALL the languages, which is insane, can we do something about it?

For now lets say current behavior doesn't change and those who want to reduce their footprint can do something like this?

import moment form 'moment/core';
import 'moment/locales/...';

hakunin commented Mar 10, 2017

Guys this has been going on for a while and seems really easy to fix. Currently everyone who uses moment (awesome library btw) is including ALL the languages, which is insane, can we do something about it?

For now lets say current behavior doesn't change and those who want to reduce their footprint can do something like this?

import moment form 'moment/core';
import 'moment/locales/...';
@deveedutta

This comment has been minimized.

Show comment
Hide comment
@deveedutta

deveedutta Mar 10, 2017

Agreed.

But have to admit that people who import this are unaware of this 'language package' thing. It'd, hence, remain the responsibility of the library owner to take care of that.

deveedutta commented Mar 10, 2017

Agreed.

But have to admit that people who import this are unaware of this 'language package' thing. It'd, hence, remain the responsibility of the library owner to take care of that.

@AoDev

This comment has been minimized.

Show comment
Hide comment
@AoDev

AoDev Mar 28, 2017

Not really helping but I wanted to show a better illustration of the problem.

screen shot 2017-03-28 at 16 08 47

When you run the webpack-bundle-analyzer it's pretty clear it takes a huge part of the app weight while we only use English.

AoDev commented Mar 28, 2017

Not really helping but I wanted to show a better illustration of the problem.

screen shot 2017-03-28 at 16 08 47

When you run the webpack-bundle-analyzer it's pretty clear it takes a huge part of the app weight while we only use English.

@AoDev

This comment has been minimized.

Show comment
Hide comment
@AoDev

AoDev Mar 28, 2017

@hakunin I haven't tried your solution but it looks good. But, I think it would be hard to "scale" this. We have moment required in tens (maybe a hundred) places. Just forget it once and we are done. I wonder if we could use something like aliases:

alias: {
  moment: path.resolve(__dirname, 'node_modules/moment/core')
}

So this would prevent accidents but maybe it would break other stuff?

AoDev commented Mar 28, 2017

@hakunin I haven't tried your solution but it looks good. But, I think it would be hard to "scale" this. We have moment required in tens (maybe a hundred) places. Just forget it once and we are done. I wonder if we could use something like aliases:

alias: {
  moment: path.resolve(__dirname, 'node_modules/moment/core')
}

So this would prevent accidents but maybe it would break other stuff?

@hakunin

This comment has been minimized.

Show comment
Hide comment
@hakunin

hakunin Mar 28, 2017

Its not a solution, just a proposed way to fix it :) the current workaroudn is webpack config above.

hakunin commented Mar 28, 2017

Its not a solution, just a proposed way to fix it :) the current workaroudn is webpack config above.

@laurenskling

This comment has been minimized.

Show comment
Hide comment
@laurenskling

laurenskling Mar 29, 2017

Hey guys, i came here because (probably) webpack2 treeshaking was removing my locale from production builds. my fix to include it again was to import 'moment/locale/nl'

So isn't webpack2 treeshaking already fixing what you guys are discussing?

laurenskling commented Mar 29, 2017

Hey guys, i came here because (probably) webpack2 treeshaking was removing my locale from production builds. my fix to include it again was to import 'moment/locale/nl'

So isn't webpack2 treeshaking already fixing what you guys are discussing?

@Kovensky

This comment has been minimized.

Show comment
Hide comment
@Kovensky

Kovensky Mar 30, 2017

Collaborator

One fun thing I learned yesterday -- the require call in the module version of moment is unreachable code, at least as of the webpack 2.2.0 release.

It is guarded inside an module && module.exports check, and module.exports is undefined in module code.

Collaborator

Kovensky commented Mar 30, 2017

One fun thing I learned yesterday -- the require call in the module version of moment is unreachable code, at least as of the webpack 2.2.0 release.

It is guarded inside an module && module.exports check, and module.exports is undefined in module code.

@michelgotta

This comment has been minimized.

Show comment
Hide comment
@michelgotta

michelgotta Mar 31, 2017

Contributor

@laurenskling This sounds interesting. Can you provide an example and more code with your webpack configuration.

What's the size of your bundled JavaScript file?

Contributor

michelgotta commented Mar 31, 2017

@laurenskling This sounds interesting. Can you provide an example and more code with your webpack configuration.

What's the size of your bundled JavaScript file?

@laurenskling

This comment has been minimized.

Show comment
Hide comment
@laurenskling

laurenskling Mar 31, 2017

I've created an example package which will prove my theory: https://github.com/laurenskling/moment-treeshaking

running production mode will drop the language support.

laurenskling commented Mar 31, 2017

I've created an example package which will prove my theory: https://github.com/laurenskling/moment-treeshaking

running production mode will drop the language support.

@michelgotta

This comment has been minimized.

Show comment
Hide comment
@michelgotta

michelgotta Mar 31, 2017

Contributor

@laurenskling Thanks for providing the example for us.

Running your code results in a bundle.js file with ~350kB with or without commenting the import 'moment/locale/nl'; line. When checking the bundle.js file, I still find all the other languages inside. That is still a very large file for "just printing out" a date in dutch.

Can you give us more infos about your results?

Contributor

michelgotta commented Mar 31, 2017

@laurenskling Thanks for providing the example for us.

Running your code results in a bundle.js file with ~350kB with or without commenting the import 'moment/locale/nl'; line. When checking the bundle.js file, I still find all the other languages inside. That is still a very large file for "just printing out" a date in dutch.

Can you give us more infos about your results?

@laurenskling

This comment has been minimized.

Show comment
Hide comment
@laurenskling

laurenskling Mar 31, 2017

hm, you're right. It still lives in the bundle. And it doesn't work. Awesome :P

laurenskling commented Mar 31, 2017

hm, you're right. It still lives in the bundle. And it doesn't work. Awesome :P

@Kovensky

This comment has been minimized.

Show comment
Hide comment
@Kovensky

Kovensky Mar 31, 2017

Collaborator

The require call inside moment seems to have become unreachable code after webpack 2's release, as module.exports is now undefined inside ES modules, and the require is inside an if (module.exports).

Collaborator

Kovensky commented Mar 31, 2017

The require call inside moment seems to have become unreachable code after webpack 2's release, as module.exports is now undefined inside ES modules, and the require is inside an if (module.exports).

@michelgotta

This comment has been minimized.

Show comment
Hide comment
@oanogin

This comment has been minimized.

Show comment
Hide comment
@oanogin

oanogin Apr 5, 2017

Hey guys, maybe you are looking something like this one

new webpack.ContextReplacementPlugin(/moment[\\/]locale$/, /^\.\/(ru)$/)

and BundleAnalyzerPlugin result is

2017-04-05 11 24 54

oanogin commented Apr 5, 2017

Hey guys, maybe you are looking something like this one

new webpack.ContextReplacementPlugin(/moment[\\/]locale$/, /^\.\/(ru)$/)

and BundleAnalyzerPlugin result is

2017-04-05 11 24 54

@ichernev

This comment has been minimized.

Show comment
Hide comment
@ichernev

ichernev May 1, 2017

So is this still a problem with webpack2 and should we merge some code in moment to fix this :)

ichernev commented May 1, 2017

So is this still a problem with webpack2 and should we merge some code in moment to fix this :)

@kishorevarma

This comment has been minimized.

Show comment
Hide comment
@kishorevarma

kishorevarma Jun 7, 2017

I resolved this issue in my project in a different way, I have used copy-webpack-plugin to copy all locale files to web root directory where my bundle files are exist.

following is my webpack config

 
      new CopyWebpackPlugin([
        {
          context: 'node_modules/moment/locale',
          from: '**/*',
          to: './moment-locale/'
        },
        {
          context: 'node_modules/react-intl/locale-data',
          from: '**/*',
          to: './react-intl-locale/',
          ignore: ['index.js']
        }
      ]),

In our application user can select any locale, so we need to load them dynamically. using above solution I can achieve that

Cheers
Kishore

kishorevarma commented Jun 7, 2017

I resolved this issue in my project in a different way, I have used copy-webpack-plugin to copy all locale files to web root directory where my bundle files are exist.

following is my webpack config

 
      new CopyWebpackPlugin([
        {
          context: 'node_modules/moment/locale',
          from: '**/*',
          to: './moment-locale/'
        },
        {
          context: 'node_modules/react-intl/locale-data',
          from: '**/*',
          to: './react-intl-locale/',
          ignore: ['index.js']
        }
      ]),

In our application user can select any locale, so we need to load them dynamically. using above solution I can achieve that

Cheers
Kishore

@hoeni

This comment has been minimized.

Show comment
Hide comment
@hoeni

hoeni Jun 27, 2017

To the next person trying to get one of the above configurations to work (which they did not for me):

While trying to fix things, I accidentally stumbled upon the documentation page for the ContextReplacementPlugin showing exact this case (momentjs) as an example and it worked fine for me :-)

plugins: [
    new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /de|en/)
]

`

hoeni commented Jun 27, 2017

To the next person trying to get one of the above configurations to work (which they did not for me):

While trying to fix things, I accidentally stumbled upon the documentation page for the ContextReplacementPlugin showing exact this case (momentjs) as an example and it worked fine for me :-)

plugins: [
    new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /de|en/)
]

`

@FedC

This comment has been minimized.

Show comment
Hide comment
@FedC

FedC Oct 11, 2017

I ran into this issue trying to use moment.js in my Angular Universal project. Since I am only interested in using it on the client for now, my workaround has been simply to inject the <script> tag with the CDN url (or from your local bower/node_modules) on the my index.html as so:

<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.7.0/moment.min.js" type="text/javascript"></script>

Then using it in my client-side js by declaring it first:

declare const moment: any;

It's not pretty, but it meets my needs for now.

FedC commented Oct 11, 2017

I ran into this issue trying to use moment.js in my Angular Universal project. Since I am only interested in using it on the client for now, my workaround has been simply to inject the <script> tag with the CDN url (or from your local bower/node_modules) on the my index.html as so:

<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.7.0/moment.min.js" type="text/javascript"></script>

Then using it in my client-side js by declaring it first:

declare const moment: any;

It's not pretty, but it meets my needs for now.

@ShavidzeT

This comment has been minimized.

Show comment
Hide comment
@ShavidzeT

ShavidzeT Feb 18, 2018

To use for global scope (access with window.moment) with webpack loader

Install
yarn add moment expose-loader

Add a loader:

      {
        test: require.resolve('moment'),
        use: [
          {
            loader: 'expose-loader',
            options: 'moment'
          }
        ]
      },

import from entry files

import 'moment'

ShavidzeT commented Feb 18, 2018

To use for global scope (access with window.moment) with webpack loader

Install
yarn add moment expose-loader

Add a loader:

      {
        test: require.resolve('moment'),
        use: [
          {
            loader: 'expose-loader',
            options: 'moment'
          }
        ]
      },

import from entry files

import 'moment'
@mryarbles

This comment has been minimized.

Show comment
Hide comment
@mryarbles

mryarbles Mar 9, 2018

How the !@#$!@#$ is this still a problem?

mryarbles commented Mar 9, 2018

How the !@#$!@#$ is this still a problem?

@ronbnsim

This comment has been minimized.

Show comment
Hide comment
@ronbnsim

ronbnsim Apr 22, 2018

it just doesnt work!!!

ronbnsim commented Apr 22, 2018

it just doesnt work!!!

@TheLarkInn

This comment has been minimized.

Show comment
Hide comment
@TheLarkInn

TheLarkInn Apr 22, 2018

Member

Since this doesn't really have anything to do with webpack at this point I think it's best to close this issue. If anyone would like to create a guide on webpack.js.org they can submit a PR to GitHub.com/webpack/webpack.js.org

Member

TheLarkInn commented Apr 22, 2018

Since this doesn't really have anything to do with webpack at this point I think it's best to close this issue. If anyone would like to create a guide on webpack.js.org they can submit a PR to GitHub.com/webpack/webpack.js.org

@TheLarkInn TheLarkInn closed this Apr 22, 2018

@marcosfede

This comment has been minimized.

Show comment
Hide comment
@marcosfede

marcosfede Apr 23, 2018

Hi, I'm using some libraries and each one is bundling its own version of moment. How would I avoid duplication with webpack so that I bundle only one version of moment?

marcosfede commented Apr 23, 2018

Hi, I'm using some libraries and each one is bundling its own version of moment. How would I avoid duplication with webpack so that I bundle only one version of moment?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment