Skip to content
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

Modularize moment.js, make the core as light as possible #2373

Closed
srcspider opened this issue May 13, 2015 · 129 comments
Closed

Modularize moment.js, make the core as light as possible #2373

srcspider opened this issue May 13, 2015 · 129 comments
Milestone

Comments

@srcspider
Copy link

@srcspider srcspider commented May 13, 2015

I remember when moment was a "lightweight" library, right now at 12kb (gziped no less) for, what it's in most cases, just very very simple date manipulation.

A simple solution to this problem would be to modularize momentjs so at least for environments like browerify, webpack and such a minimal version can be obtained.

eg.

Regular usage can stay the same,

// get everything under the sun
var moment = require('moment');

Modular usage could look like this,

// get core, the core does nothing, no validation, no nothing
// it would only define a internal storage structure and the bare minimum
// methods for getting values out of it: day, month, year, etc (no "format" 
// functions or "fromNow" since you might not even want to use them)
var moment = require('moment/core');

// add plugins for all the stuff you need, if you ever want ALL of them you 
// just include the directory instead (node/browserify/webpack will pick up
// a index.js inside it that would have all the things)
moment.plugin([

    // if you know this is all the parsers you need this is all you add
    require('moment/plugins/parser/yyyy-mm-dd-time'),
    require('moment/plugins/parser/unixtime'),

    require('moment/plugins/validator/yyyy-mm-dd-time'),
    // if we don't use unixtime locally, only on server we dont care for that
    // when it comes to validation

    require('moment/plugins/fromNow'),
    require('moment/plugins/toUnixTime'),

    // with a modular structure we can add 3rd party stuff really easily
    require('moment-phpstyle-format'),
    require('moment-chained-functions-format')

]);

// lock in the configuration so that calling plugin method throw and exception
// this would be irreversible but you can get a unlocked version by calling copy
// this will force people to get a "copy" of the configuration before doing 
// anything stupid -- or help them find the mistake if they add it later
moment.lock();

// you now just include this file where you need it
module.exports = moment;

Let's pretend the above is in something like lib/moment and represents your default boilerplate configuration for it. Obviously you may eventually encounter situations where you need more advanced functions. If we add to the default boilerplate we unfortunately add to every other context that doesn't need it. This is a big bummer if we're trying to keep client size down with things like webpack code splitting.

However, so long as the modular system is capable of being extending any time there's no problem whatsoeve. Ideally, to avoid subtle race condition bugs, we should be able to get a new "advanced" version as a separate instance:

// load boilerplate we defined previously
// we request a copy of the instance so no funny business happens
var moment = require('lib/moment').copy(); 

// we can also create a separate boilerplate if we re-use this a lot
moment.plugin(require('expensive-internationalization-timezone-nonsense'));
moment.lock(); // lock the new copy just in case its passed around

// moment instances should be able to do a quick copy between instances
// to ensure functionality, ie. moment(createdAt) could just swap plugin pointers

Now only the module that actually uses that feature pays the cost. If you use moment in 100 places and only 1 actually needs internationalization just that one place will ever pay for it. This applies to all functions, all the core needs to do is store a plain date object and some getters. Is everything you do just pass unix time from the server? you can just have unixtime parser. Do you only ever validate dates on the server? you can skip on any and all validation, etc.

It's effectively as light as you building your own specialized helpers. And much like projects like gulp, postcss and so on the community can contribute easily to it though easily maintainable chunks.

And in this way, momentjs can, once again, be called "lightweight javascript date library".

@naartjie
Copy link

@naartjie naartjie commented Jun 12, 2015

right now at 12kb (gziped no less)

Are you using the version from CDN or npm? My size increase is more like 48kb gzipped. #2416

@srcspider
Copy link
Author

@srcspider srcspider commented Jun 12, 2015

@naartjie

You'll want to use webpack's ignore plugin (sorry cant recall name of the top of my head) to exclude locale information. That should bring it down to something more reasonable.

48kb gzip is indeed pretty crazy, my largest entry point (react + various util functions + application code for full rendering) sits at around 50kb gzip. I've switched to just using unix timestamps and completely custom functions to process those into a format as needed... a bit sad, would love to use a date manipulation library but just can't take a +100% initial load javascript bump. It's obviously even worse on subsequent incremental loads (caused by require.ensure) since those average at 10kb gzip as it's mostly application specific code, so should initial load avoid dates but one of those require dates then that's a 6x size increase.

@naartjie
Copy link

@naartjie naartjie commented Jun 12, 2015

Thanks for the rundown @srcspider, I have read about IgnorePlugin before, but I didn't click that it was applicable for these kinds of situations, so it helps to match theory and practical together 👍

Does anyone need a library that gets bigger and bigger?

Don't you want to edit that line out? It might seem a little too brash, where as I think your general tone of the issue is very helpful, and you have a valid point. Plus you seem to know how this should all go down, I think a PR would go down well, I hear they're looking for help. ;-)

@naartjie
Copy link

@naartjie naartjie commented Jun 15, 2015

I think it would be great to have the option to require a version with or without locales, that would be good at least for a start, and probably not too massive a refactor. I could have a stab at a PR. What say you @srcspider, do you think that would be useful to anyone else?

I know it's a 👍 from me, but I'm not sure if there would be any other takers out there.

@srcspider
Copy link
Author

@srcspider srcspider commented Jun 16, 2015

@naartjie not to be the bearer of bad news but would probably recommend waiting on one of the owners to give their thoughts on this before putting any considerable effort in. No point in pushing only to be shot down (or never approved). However if you need it yourself right now, by all means.

Plus you seem to know how this should all go down, I think a PR would go down well, I hear they're looking for help. ;-)

Sadly I'm very much on the fence on ES6. It doesn't integrate with my current workflows, and can't see any advantage to the various recommendations of ES6 workflows I've encountered (and by "no advantage" what I mean is they're far far inferior in resulting size, architecture and just a lot more unnecessarily complex in general).

It's hard to get exited to contributing to a "Port to ES6" when it's, overall, just a worse thing (for me).

@ichernev
Copy link
Contributor

@ichernev ichernev commented Jun 25, 2015

The port to es6 is supposed to benefit development, not users. There are packaged versions of moment, with and without locales, uploaded to npmjs.

About making a small core that is extensible - that is going to be a big step back in usability for most users. If you feel like it patch the src/moment to include what you want and transpile.

I'm closing this for now. If a moment without locales is not bundled properly feel free to reopen.

@ichernev ichernev closed this Jun 25, 2015
@naartjie
Copy link

@naartjie naartjie commented Jun 25, 2015

There are packaged versions of moment, with and without locales, uploaded to npmjs

@ichernev I tried looking, and all I found was moment and moment-timezone, could you point me to the version of moment without locales in npmjs.

I actually asked for this in #2416. It feels like using the IgnorePlugin is a hack/workaround, if there is already a packaged version without locales.

Thanks.

@ichernev
Copy link
Contributor

@ichernev ichernev commented Jun 29, 2015

Aaah, I see. Npmjs is historically used for server side, where you don't care about size. But for other build tools that go on top of it, I guess we shall add another target moment-core or something like this.

@ichernev ichernev reopened this Jun 29, 2015
@naartjie
Copy link

@naartjie naartjie commented Jun 29, 2015

That would be great, thanks @ichernev. It will make integrating with tools like webpack a breeze (without needing the likes of IgnorePlugin).

I see you've reopened this one, so I'm going to close #2416 again ;-)

@fresheneesz
Copy link

@fresheneesz fresheneesz commented Jul 15, 2015

@ichernev I use npm for both frontend and backend, and I think this has become much more common. I'm also a bit concerned with loading in a giant library just for the use of a couple nice date manipulation apis. +1 for a lean-core via npm, and an easy way to optionally add locales / peripheral functionality with the default being exclusion (unless explicitly included).

One thing I think would be great to be able to do, is load a single locale as needed via webpack's ensure functionality - so you only load locale information when the user actually needs it (eg loads the page in a particular locale or switches their configured locale)

@reywright
Copy link

@reywright reywright commented Jul 16, 2015

+1 definitely

@jeffbski
Copy link

@jeffbski jeffbski commented Aug 4, 2015

+1

@seethroughtrees
Copy link

@seethroughtrees seethroughtrees commented Aug 27, 2015

would love this as well.

@dbrugne
Copy link

@dbrugne dbrugne commented Sep 3, 2015

+1

@jhubert
Copy link

@jhubert jhubert commented Sep 21, 2015

One of the first (and best) optimizations we did was remove moment.js from our client side app. I would love to use moment.js more frequently but the additional page weight just isn't worth it for the basic date manipulation we do.

So, I'm a big +1 on this as well.

@reywright
Copy link

@reywright reywright commented Sep 24, 2015

@jhubert I'm actually starting to consider that. What did you replace moment with? It's one of the largest things in my app.

@jhubert
Copy link

@jhubert jhubert commented Sep 25, 2015

@rey-wright I was really only using it for formatting, so I just wrote a few functions that formatted the dates exactly as I needed them and used them throughout the site. It's nothing elegant, but it's extremely fast and light.

@reywright
Copy link

@reywright reywright commented Sep 28, 2015

@jhubert yeah we were doing that but... I really wish moment would be setup better...but now it's like Moment is one of the biggest pieces of our app...

So yeah we might eventually go back to this method as well. Thanks for the insight.

@gilbert
Copy link

@gilbert gilbert commented Oct 7, 2015

+1. Moment.js looks great, but the 12kb makes it not worth the include (that's bigger than the framework we use!)

@DerekDomino
Copy link

@DerekDomino DerekDomino commented Nov 19, 2015

tests.js file could be removed from the npm package. This file amounts to 63% of the total npm package size. A dedicated development npm package could could include this tests.js file.

For desktop applications (electron) using npm packages using moment, moment contributes significantly to the final application size (moment folder is duplicated in nested nod_modules dir).

@fresheneesz
Copy link

@fresheneesz fresheneesz commented Nov 19, 2015

@DerekDomino The point of modularizing moment.js is for two reasons:

  • Less code for browsers to download
  • Easier to maintain many smaller packages than one large one

Removing a tests file doesn't accomplish either of those goals, and in fact doing what you suggest would make it harder to develop moment. And if you're for some reason having browsers forced to download the tests.js code, something else is going wrong.

@adalinesimonian
Copy link

@adalinesimonian adalinesimonian commented Nov 19, 2015

@fresheneesz While yes, the suggestion doesn't fix the main problem, why would excluding a test file from the npm package make it harder to develop moment? It isn't the same as removing tests from the repository, and, generally, test code is not meant to be packaged.

@fresheneesz
Copy link

@fresheneesz fresheneesz commented Nov 20, 2015

Oh, just the npm package? I guess it wouldn't then. Still don't think its a road worth traveling.

@iagopiimenta
Copy link

@iagopiimenta iagopiimenta commented Dec 6, 2015

👍

@mmalomo
Copy link

@mmalomo mmalomo commented Feb 5, 2019

I need this since years ago. I can not believe it is not done yet.
Im changing to moment-mini for the moment

https://github.com/ksloan/moment-mini

@xxyuk
Copy link

@xxyuk xxyuk commented Feb 19, 2019

Day.Js is a nice alternative to me

Day.js 2KB immutable date library alternative to Moment.js with the same modern API

https://github.com/iamkun/dayjs

@nephi5
Copy link

@nephi5 nephi5 commented Mar 9, 2020

Hi, very interested still in this feature. Any progress made?

@Carniatto
Copy link

@Carniatto Carniatto commented Mar 12, 2020

@nephi5 @rianfowler Since this issue seems to be abandoned, you probably want to check this: https://github.com/you-dont-need/You-Dont-Need-Momentjs

@renet
Copy link

@renet renet commented Jun 9, 2020

@ichernev Almost every experienced developer I talk to now recommends not using moment.js anymore. The reactions on many threads regarding this topic are pretty clear.

Can you please give us a feedback if you consider (or even already work on) a modularized moment.js package? It seems like you're ignoring this thread - please let us know, whether or not there's a chance for a modularized version. Thanks!

@MickL
Copy link

@MickL MickL commented Jun 9, 2020

With date-fns do we really need moment.js anymore?

@jeffbski-rga
Copy link

@jeffbski-rga jeffbski-rga commented Jun 9, 2020

I typically recommend date-fns these days. I like the fp form myself.

@marwahaha
Copy link
Member

@marwahaha marwahaha commented Sep 14, 2020

See https://momentjs.com/docs/#/-project-status/

As mentioned before, the moment build without locales is of comparable size to date-fns.

@marwahaha marwahaha closed this Sep 14, 2020
@MickL
Copy link

@MickL MickL commented Sep 15, 2020

Instead of solving something, just close the issue 👍🏻

@tomastan
Copy link

@tomastan tomastan commented Sep 15, 2020

I think @marwahaha explained things pretty well in Project status section. At least it is good to know there is no reason to wait for this functionality in Moment.

@csvan
Copy link

@csvan csvan commented Sep 16, 2020

@MickL moment.js is effectively dead, there is nothing to solve.

https://www.theregister.com/2020/09/15/moment_js_javascript_library_future/

We are migrating to https://github.com/iamkun/dayjs instead. Almost fully API-compatible with moment and extremely lightweight.

@LeoEatle
Copy link

@LeoEatle LeoEatle commented Sep 17, 2020

For webpack project, use this: https://github.com/jmblog/how-to-optimize-momentjs-with-webpack

@baoanhng
Copy link

@baoanhng baoanhng commented Sep 17, 2020

The project status page effectively explains all the thing.
https://momentjs.com/docs/#/-project-status/

You should move to other libraries if moment.js is not suitable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
You can’t perform that action at this time.