Best way to extend Sage and UTIL objects in main.js

I think the way Sage handles javascript is brilliant. It’s nice to know that scripts are only firing on the pages I intend them too. However, as my themes get more and more js intensive I’m finding that my main.js file is getting a bit out of hand. I’ve added a few of my own methods to the UTIL object that I need to have access to throughout the site. I would like to be able to break some page specific scripts out into their own files. I know that I can easily add then to the assets/scripts dir and the will be concatenated during the build process. That’s all working perfectly. I was also able to add some additional namespaces to the UTIL object to loop over and make sure the methods in my new files were being fired at the correct times. My only issue (if an issue at all) is that in order to have access to the additional UTIL methods I needed to cast it as a global variable (as well as my new namespaces). Not sure I like doing that. I’m curious if anyone has “correctly” been able to accomplish something similar to what I’m doing? Any and all insight is appreciated!

Without modules via something like browserify, webpack, or requirejs you are stuck with the global scope.

Take a look at: http://eloquentjavascript.net/10_modules.html

You should definitely be wrapping your methods in closures so they get a private scope so no side effects can happen.

(function(exports) {
  var names = ["Sunday", "Monday", "Tuesday", "Wednesday",
               "Thursday", "Friday", "Saturday"];

  exports.name = function(number) {
    return names[number];
  };
  exports.number = function(name) {
    return names.indexOf(name);
  };
})(this.weekDay = {});

console.log(weekDay.name(weekDay.number("Saturday")));
// → Saturday

Sage would use browserify by default if I had my way. Sadly browserify and friends are too complex for most WP developers that do not have javascript chops. When doing things “properly” you lose the ability to install random jQuery plugins from 2010. This is definitely a no-go for most WP use cases.

@austin thanks for your reply. I think I’m going to explore using browserify or requirejs. I would really like to find a solution and don’t want to abandon Sage’s built in functionality. Thank you guys so much for the quick responses and keep up the good work!

Afk but search the forums and you will find a post I made about integrating browserify. I had some code examples.

I know this is an outdated post but in case others are looking.

You can get around this by writing the main.js using the JS Module Pattern, if you’re not familiar here is an explanation - https://toddmotto.com/mastering-the-module-pattern/

You can change UTIL to this pattern and then expose the fire and loadEvents for other JS files included in manifest.json.

// Sage Routing using JS Module Pattern
var UTIL = (function() {

  var Sage = {
    // All pages
    'common': {
      init: function() {
        // add functions here
      }
    },
    // Home page
    'home': {
      init: function() {
        // example of another returned scope/function
        Carousel.init();
      }
    }
  };

  var fire = function(func, funcname, args) {
    var fire;
    var namespace = Sage;
    funcname = (funcname === undefined) ? 'init' : funcname;
    fire = func !== '';
    fire = fire && namespace[func];
    fire = fire && typeof namespace[func][funcname] === 'function';
    if (fire) {
      namespace[func][funcname](args);
    }
  };

  var loadEvents = function() {
    fire('common');
   $.each(document.body.className.replace(/-/g, '_').split(/\s+/), function(i, classnm) {
      fire(classnm);
      fire(classnm, 'finalize');
    });
    fire('common', 'finalize');
  };

  // Load Events
  $(document).ready(loadEvents);

  return {
    fire: fire,
    loadEvents: loadEvents
  };

})();

You can then access this from other JS files using -

UTIL.loadEvents();

2 Likes