DEV Community

Cover image for JavaScript Modules in WordPress
Kevinleary.net
Kevinleary.net

Posted on Originally published at kevinleary.net

JavaScript Modules in WordPress

WordPress 6.5 includes a new API that allows developers to finally work with JavaScript modules properly.

Using these two new functions, you can load JS modules in WordPress 6.5+:

  • wp_register_script_module
  • wp_enqueue_script_module

Both of these are pretty intuitiv and work just like their existing counterparts:

  • wp_register_script
  • wp_enqueue_script

Simple Demo

The following demonstration will show how everything works, covering common real-world developer scenarios like working with jQuery. The demo loads four modules, three of which contain a simple function that outputs a message to the browser console. The final initialize script calls these methods in order.

PHP

There are few important things to know about this code demo:

  1. Assumes you’re working inside a plugin. If you’re working in a theme, replace plugin_dir_url with get_stylesheet_directory_uri.
  2. Modules always load <script> tags right before the </body> tag. It’s operates like the in_footer parameter is defaulting to true.
/**
 * Modular JavaScript
 */
function enqueue_modules(): void {
  $plugin_url = plugin_dir_url( __FILE__ );

  $dependencies = [ [
    'id' => 'jquery',
    'import' => 'static', // Default
  ], [
    'id' => 'module-1',
    'import' => 'dynamic',
  ], [
    'id' => 'module-2',
    'import' => 'dynamic',
  ], [
    'id' => 'module-3',
    'import' => 'dynamic',
  ] ];

  wp_register_script_module( 'module-1', $plugin_url . 'module-1.js' );
  wp_register_script_module( 'module-2', $plugin_url . 'module-2.js' );
  wp_register_script_module( 'module-3', $plugin_url . 'module-3.js' );
  wp_enqueue_script_module( 'initialize', $plugin_url . 'initialize.js', $dependencies );
}
add_action( 'wp_enqueue_scripts', 'enqueue_modules' );
Enter fullscreen mode Exit fullscreen mode

I’ve used wp_register_script_module to register dependencies that will conditionally load. Conditionally loaded modules are possible with this pattern because I’ve set the import parameter to dynamic.

It also includes jquery as a static dependency, which is a global script, not a module. I’ve included a demo to show how to handle this common real-world scenario.

HTML

<script type="module" src="https://www.kevinleary.net/wp-content/plugins/js-modules-demo/module-1.js" id="module-1-js-module"></script>
<script type="module" src="https://www.kevinleary.net/wp-content/plugins/js-modules-demo/module-2.js" id="module-2-js-module"></script>
<script type="module" src="https://www.kevinleary.net/wp-content/plugins/js-modules-demo/module-3.js" id="module-3-js-module"></script>
<script type="module" src="https://www.kevinleary.net/wp-content/plugins/js-modules-demo/initialize.js" id="initialize-js-module"></script>
Enter fullscreen mode Exit fullscreen mode

JS

Basic JavaScript Modules Demo for WordPress 6.5+

Each individual module-*.js contains a simple function export, and the initialize.js serves as a bootstrap module that imports our other modules and executes them. Each one dumps a console.log("Module #* made this.") in order.

module-1.js

export function moduleOne() {
  console.log(`Module #1 made this.`);
}
Enter fullscreen mode Exit fullscreen mode

module-2.js

export function moduleTwo() {
  console.log(`Module #2 made this.`);
}
Enter fullscreen mode Exit fullscreen mode

module-3.js

export function moduleThree() {
  console.log(`Module #3 made this.`);
}
Enter fullscreen mode Exit fullscreen mode

initialize.js

import { moduleOne } from "module-1";
import { moduleTwo } from "module-2";
import { moduleThree } from "module-3";
const $ = window.jQuery;

moduleOne();
moduleTwo();
moduleThree();

$(document).on("ready", () => {
  console.log(`Good ol' DOM ready with jQuery.`);
});
Enter fullscreen mode Exit fullscreen mode

Console

The modules are executed sequentially, so these logs will always print in the same order.

Module #1 made this.
Module #2 made this.
Module #3 made this.
Good ol' DOM ready with jQuery.
Enter fullscreen mode Exit fullscreen mode

Conditionally Loaded Dynamic Modules

Setting the dynamic dependency property will conditionally load modules only when they’re imported. This is the real sweet sauce of working with JS modules, it allows us to loaded in only what we need on demand. It’s a great improvement over the outdated wp_enqueue_script approach.

To provide an example: if the initialize.js doesn’t use one of the dependent modules, then it’s not loaded. As an example, you can adjust the demo above to remove the use of moduleTwo. This will not load module-2.js, and will not add the associated message to the browser console.

JS

import { moduleOne } from "module-1";
import { moduleThree } from "module-3";

moduleOne();
moduleThree();
Enter fullscreen mode Exit fullscreen mode

Console

Module #1 made this.
Module #3 made this.
Enter fullscreen mode Exit fullscreen mode

Summary

This has been a large issue with numerous developers for some time. It took much longer than expected to get included in the core, but it’s finally here and is an exciting new addition.

Sources, Citations & Other Resources

Top comments (0)