Google Compiler not assigning empty arrays to variables?

62 views Asked by At

So I am pretty new to using Google Compiler and am running into a few issues. The first is that in my preprocessed code I am setting an empty array to a variable which will be populated later on, but when compiling it removes the variable altogether so that it becomes undefined when trying to use it later on.

Here is the code I have slightly modified. Line 19 ends up being removed so therefore rowDivs is showing up as undefined on line 44:

/**
 * Equal Heights
 *
 * @see https://css-tricks.com/equal-height-blocks-in-rows/
 */
goog.provide('EqualHeights');

(function($) {

    // =  Equalize columns on load and resize
    equal_heights();

    $(window).resize(function() {
        equal_heights();
    })

    var currentTallest = 0;
    var currentRowStart = 0;
    var rowDivs = new Array();

    function setConformingHeight(el, newHeight) {

        // set the height to something new, but remember the original height in case things change
        el.data("originalHeight", (el.data("originalHeight") == undefined) ? (el.height()) : (el.data("originalHeight")));
        el.height(newHeight);
    }

    function getOriginalHeight(el) {

        // if the height has changed, send the originalHeight
        return (el.data("originalHeight") == undefined) ? (el.height()) : (el.data("originalHeight"));
    }

    function equal_heights() {

        // find the tallest DIV in the row, and set the heights of all of the DIVs to match it.
        $('[data-equalizer-watch]').each(function() {

            // "caching"
            var $el = $(this);
            var topPosition = $el.position().top;

            if (currentRowStart != topPosition) {

                // we just came to a new row. Set all the heights on the completed row
                for(currentDiv = 0 ; currentDiv < rowDivs.length ; currentDiv++) setConformingHeight(rowDivs[currentDiv], currentTallest);

                // set the variables for the new row 
                rowDivs.length = 0; 

                // empty the array 
                currentRowStart = topPosition; 
                currentTallest = getOriginalHeight($el);
                rowDivs.push($el);
            } 
            else { 

                // another div on the current row. Add it to the list and check if it's taller
                rowDivs.push($el);
                currentTallest = (currentTallest < getOriginalHeight($el)) ? (getOriginalHeight($el)) : (currentTallest);
            }
        }); 

        // do the last row
        for (currentDiv = 0 ; currentDiv < rowDivs.length ; currentDiv++) { 
            setConformingHeight(rowDivs[currentDiv], currentTallest);

        }
    } 

})(jQuery);

For the compiler settings, I am using the following flags. Note that I am not even using the advanced optimizations complication level:

--closure_entry_point main.js
--externs node_modules/google-closure-compiler/contrib/externs/jquery-1.9.js
--language_in ECMASCRIPTS5
--warning_level: VERBOSE

I am probably missing something obvious, but just want to get on the right track. Thanks.

1

There are 1 answers

0
owler On

With simple-compile mode local variables are minimized and potentially removed if not used. Probably what's happening is: based on the entry point you specified, closure compiler determines that rowDivs can never used.

To fix you need to tell closure compiler more information.

(Disclaimer: I've never used jquery so I might be way off track in what follows. I've also never used node or modules, and there are special ways to write for those which I'm not familiar with.)

One thing to try is the special flag for jquery: --process_jquery_primitives see https://github.com/google/closure-compiler/wiki/jQuery-Expansions

The jquery-1.9 extern defines $ as a global variable, so you don't need to pass it in to your function.

You might need to tell closure-compiler to export the functions you define. See "Export the Symbols You Want to Keep" in https://developers.google.com/closure/compiler/docs/api-tutorial3

If you are open to using "object-oriented style", here are some ideas. There is probably a way to write your code without changing to an object-oriented style, but I'm not familiar enough with that style to help you.

(I don't know how to get jquery to be activated when your program starts, but I assume this happens in your startup code somewhere.)

It looks like you designed this code to be a self-executing function that happens whenever you say goog.require('EqualHeights'). But you don't actually define anything for the EqualHeights namespace. Maybe this instead:

goog.provide('EqualHeights');

/**
* @constructor
*/
EqualHeights = function() {
    this.currentTallest = 0;
    this.currentRowStart = 0;
    this.rowDivs = new Array();
};

/**
* @param {!Element} el
* @param {number} newHeight
*/
EqualHeights.prototype.setConformingHeight = function(el, newHeight) {

    // set the height to something new, but remember the original height in case things change
    el.data("originalHeight", (el.data("originalHeight") == undefined) ? (el.height()) : (el.data("originalHeight")));
    el.height(newHeight);
};

/**
* @param {!Element} el
* @return {number}
*/
EqualHeights.prototype.getOriginalHeight = function(el) {

    // if the height has changed, send the originalHeight
    return (el.data("originalHeight") == undefined) ? (el.height()) : (el.data("originalHeight"));
}

/**
* @return {undefined}
*/
EqualHeights.prototype.equal_heights = function() {

    // find the tallest DIV in the row, and set the heights of all of the DIVs to match it.
    $('[data-equalizer-watch]').each(function() {

        // "caching"
        var $el = $(this);
        var topPosition = $el.position().top;

        if (this.currentRowStart != topPosition) {

            // we just came to a new row. Set all the heights on the completed row
            for(currentDiv = 0 ; currentDiv < this.rowDivs.length ; currentDiv++) 
              setConformingHeight(this.rowDivs[currentDiv], this.currentTallest);

            // set the variables for the new row 
            this.rowDivs.length = 0; 

            // empty the array 
            this.currentRowStart = topPosition; 
            this.currentTallest = getOriginalHeight($el);
            this.rowDivs.push($el);
        } 
        else { 

            // another div on the current row. Add it to the list and check if it's taller
            this.rowDivs.push($el);
            this.currentTallest = (this.currentTallest < getOriginalHeight($el)) ? (getOriginalHeight($el)) : (this.currentTallest);
        }
    }); 

    // do the last row
    for (currentDiv = 0 ; currentDiv < this.rowDivs.length ; currentDiv++) { 
        setConformingHeight(this.rowDivs[currentDiv], this.currentTallest);

    }
} 

Then in your startup code have this:

goog.require('EqualHeights');

var eh = new EqualHeights();

// =  Equalize columns on load and resize
eh.equal_heights();

$(window).resize(function(){eh.equal_heights();});

I'm unclear what this line is doing:

var $el = $(this);

The value of this should be the EqualHeights object inside each method. You can use the goog.bind function (if it's available for you) to ensure that this is what you want it to be for that function.