Compile moment.js with google closure and advanced optimizations

710 Views Asked by At

I work on a project which uses Google's closure compiler with advanced optimizations turned on. I would like to include moment.js in the compilation, however all of my attempts have been fruitless.

I have tried exporting the moment function, but there are still run time problems, and a some compile errors.

Has anyone successfully compiled moment.js with advanced optimizations, or know how to do so?

The only solution I can come up with, is to concatenate the minified file to the compiled source and use externs for every function I use from moment.js. But this is not an ideal solution.

3

There are 3 best solutions below

0
On BEST ANSWER

I saw two issues with the code which would have to be corrected before momentjs would be compatible with ADVANCED_OPTIMIZATIONS. There may be more, but these were the glaring ones:

  1. Using an alias for the prototype: All references to .fn would need to be replaced with .prototype.
  2. Using a helper function to add methods: the extend method hides definitions from the compiler. All uses of the extend helper function would have to be refactored so that they do not hide the property assignments from the compiler.
0
On

You've gotta write your own externs file for moment.js for what you use from it (or the entire object, but I find that a bit of extra work for no reason).

For example, I've got this snippet to test if an input's date is within 14 days from now

$checkout.find('.date-input').on('input', /** @this {Element} */ function () {
    const $this = $(this);
    const Days = Number($this.attr('data-days'));
    if (Days > 0 && moment(/** @type {string} */($this.val())).diff(moment(), 'days') < Days) {
        $checkout.find('.date-warning').removeClass('d-none');
    } else {
        $checkout.find('.date-warning').addClass('d-none');
    }
});

And the only way I'd get that to compile correctly with advanced mode is by creating this extern.

/**
 * @fileoverview Externs for moment
 *
 * @externs
 */

/**
 * @param {string=} date
 * @constructor
 * @return {!moment}
 */
function moment(date) {}

/**
 * @param {!moment} m
 * @param {string} unit
 * @return {number}
 */
moment.diff = function (m, unit) {};
moment.prototype.diff = moment.diff;

Now clearly that description of the moment function isn't perfect; it's missing some parameters that the moment function has, but I'm not using them so it doesn't matter to me.

But that's how I start my externs. I start basic as the need arises and then I continue to grow the externs file with the more functions I need from a library.

And don't forget to tell Closure Compiler where your extern is located with the flag --externs 'externs/moment.js'.

1
On

I can't get it to work either as of 26 March 2015, but the existence of this suggests that it's possible. Here are the externs