Skip to content

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

Description

@srcspider

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".

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions