In a previous post we covered what the best way was to include jQuery in WordPress.
In this post, I’m going to talk a little more about the best ways to include Javascipt files.
When your doing a lot with Javascript, you can end up with a few scripts/libraries supporting your custom script. You might also have several custom scripts to include, but what’s the best way of including these? Would you enqueue each of them seperately? Would you combine the custom ones but enqueue the third party ones? Or would you combine everything you are using in your project into one script and enqueue that?
I’m going to discuss my approach and why I think it’s best.
So, what you might do is to enqueue each supporting scrip then list your custom script, like so:
wp_enqueue_script( 'select2', trailingslashit( get_template_directory_uri() ) . 'select2.js', array( 'jquery' ) );
wp_enqueue_script( 'custom, trailingslashit( get_template_directory_uri() ) . custom.js', array( 'jquery', 'select2') );
It’s important in this scenario that you list the dependant scripts as dependencies, rather then just list them in order. This is to make sure that they are loaded prior to the one who needs it.
For the handles, the custom script should have a prefix; like ‘themename-custom’ or ‘themename-child-custom’ to avoid accidently ending up with the same handle as something else. For example; if two plugins loaded ‘main’ or ‘custom’ you’ll have a problem.
It’s considered best practice that third party scripts use their name as their handle, i.e.’select2′. This is so that if something else is already loading select2, it would not bother loading it twice. Also, loading them twice could course a problem.
There are pros and cons to this – listing the third party depencies seperately makes it availble to other plugins or a child theme. A plugin that wants to extent another plugin or a child theme now has access to any Javascript functions it provides. They also now have the ability to override it for any reason, they can remove it, or provide an updated version without editing the parent plugin or theme directly. That is pretty useful for someone looking to extent or fix a problem.
By not including the third party scripts in your custom script, it makes that custom script much easier to override.
By sharing scripts you potentally reduce bloat, if several items on the site are using select2 why increase network calls and download sizes by including them again?
That all sounds great right? Yes,v but there is a problem; WordPress’s dependency handling is not that great and the main problem we have is with versions.
Take this scenario. You enclude select2 in your theme. A user installs a plugin that also includes select2. But, they depend on a different version of select2. Dependant on load piorities, the theme or plugin could break. If they use a different handle you could end up loading it twice. Its likely now you’ll create a ‘already defined’ error unless the script has checked for this. If it has then you’re back to the other problem; only one version will load and it may not be the right one.
By enquing our third party scripts, we have introduced a potential point of failure. The dependacy option in the enqueue call is only really used for loading the scripts in the correct order. Also, the version number supplied only really helps you to programmically to check the version number of a script, something you can do in your own code to check a loaded script’s version number, but you can’t make a third party plugin do that too.
That really is the main problem with the approach. The next issue is network calls. If you have a few dependencies you might end up with a few too many network calls. You may say, well, that’s ok because you should be using a plugin to combine your scripts anyway. In my experience, most users don’t do that because they don’t know about it. It’s common that on clicking the combine button, all the Javascript breaks – WP Rockets warns about this next to the combine button.
When you combine the third party scripts yourself, you control the process and you can be sure that the scripts have been combined in the correct order and that nothing breaks. You’ve tested that the combined file is working before it gets released. With the magic combine scripts button, you don’t really know what’s going to happen.
When combining your scripts, you can isolute them so their functions are only available to your project and are not in the global namespace. This completely removes any fear of conflicts.
Sure, it means you can end up with the same select2 script being loaded in multiple projects accross your site and we all know that you should be DRY. But I think the potental conflict issues are more of a problem.
You should however, always, unless for good reason use the core’s supplied versions of scripts. Like with jQuery, you shouldn’t be suppling your own. You should be looking to make your script compatible with the cores version. The sharing situation there is different, because all plugins and themes that are keeping maintained will be keeping them selves up to date with the version of jQuery suppplied by core.
For example:
wp_enqueue_script( 'custom, trailingslashit( get_template_directory_uri() ) . custom.js', array( 'jquery' ) );
If you do have a good reason to not use the cores version of a script ( hasn’t happened to me yet ) then you should absolutley be combining it in and isolateing it from the glocal space, because if you don’t you are almost garenteed to create a comflict and break the sites Javascript.
What about the ability to override scipts then? Well, yes that is useful and it’s a alot easier
for people to override a enqueued file then one bundled up. But if you package your project correctly and provide the build script to your end users, then a developer will still be able to modify the project and just rebuild it after.
They would be able to unqueue the main project file, build there own from the build script you’ve provided then reload it in their extension plugin or child theme. The build script being the webpack file, gulp file, package.json etc or whatever you used. If you purely just combined files, then even just the unminified version will allow them to modify it.
There is, of course the matter of whether you want your users/clients to be able to override things… That is a different discussion.
We’ve talked mostly about third part scripts thus far; what about your own custom modules that wont be shared by other projects, other then potential extentions? Well the main benefit to listing them seperatly is for any extentions, whether your own or others, the same as with third party scripts.
I often find that when I try to reuse code accross projects, it doesn’t really work out that well. It introduces complexity in the form of compatibility – so I’m not really a fan. When combining and isolating those modules from the glocal namespace, you don’t have to worry about comflicts in the same way as with third party ones.
I think that there is much less reason to not combine than there is with common third party ones. Those doing exentions can build the project as discussed previously. I always build custom modules into one script and very rarely will I enqueue them seperately.
Summary
As with most things, it’s going to depend a bit on the circumstances on what the best way to handle a project is. Until the depencendy system in WordPress improves I always combine my Javascript project files and provide the parts and build script in the project.
I provide ( where appropraite ) the parts required to rebuild the Javascript file for others to be able to modify it. So I will provide the individial modules for the custom parts and reference the third party scripts in package.json or bower file. I will include the build file, be that gulp, grunt or webpack.
I feel that it’s not a cut and dry issue, so that’s my take on it. I’m interested to hear others thoughts on it.