Managing Javascript Dependencies for WordPress Blocks

Managing Javascript dependencies for custom Gutenberg blocks is tricky because most of the core packages such as components or core-data are made available by WordPress core in the window.wp global variable. But what happens if you want to use these packages outside of the post editor screen or when they change between versions of WordPress?

Below we’ll look at the available tooling and workflows for generating script bundles that either include or exclude references to the JS packages included with the version of WordPress running your block plugin.

It assumes that your source code is written in modern JS which is passed through a build step that transpiles it into something that is understood by the majority of the browsers, and helps with keeping the list of core JS package dependencies updated when enqueuing the script.

1. Define Dependencies

Define all @wordpress/... packages used by your blocks as regular NPM dependencies to your project. So npm install @wordpress/... for every package that you need.

2. Use Dependencies

Pull in the installed dependencies using the standard import { something } from "@wordpress/..." syntax in your block source code. This will also ensure that your code editor is able to autocomplete exports and APIs provided by these packages.

3. Collect Dependencies

Use the wp-scripts build command to generate index.assets.php which returns an array of all @wordpress/... dependencies (known to be bundled with the WordPress core) found in your block Javascript code. It looks something like this:

Behind the scenes it uses the @wordpress/dependency-extraction-webpack-plugin package to discover and collect all known dependencies bundled with the WordPress core in your source code during the Javascript transpilation step. For example, it assumes that packages such as lodash, moment and those starting with @wordpress/... are included in WordPress core and can be pulled in using known script handles.

Now, when calling wp_enqueue_script() for your script bundle build/index.js you can use the generated index.assets.php file to define the necessary WP core dependencies and your script revision:

Each of the defined bundle entry points will generate a matching *.assets.php file next to the generated *.js file. By default it looks for src/index.js and generates both build/index.js and build/index.assets.php.

To define custom entry points, pass a list of entry files to the build command along with the destination directory:

which will generate dist/one.js with a matching dist/one.assets.php and dist/two.js with a matching dist/two.assets.php.

Fun fact: here is the pull request that introduced this feature.

4. Transpile and Bundle

The same wp-scripts build step also transpiles your modern source JS into browser compatible JS according to the browser compatibility rules defined in the @wordpress/scripts Babel configuration along with all the browser polyfills.

By default it replaces all known @wordpress/... dependencies with references to global window.wp.* objects using the @wordpress/dependency-extraction-webpack-plugin package mentioned previously.

To keep all dependencies in the output bundle and prevent them from being rewritten with references to the global window.wp.* references pass the --webpack-no-externals flag to the wp-scripts build command or set the WP_NO_EXTERNALS environment variable to 1 or true.

This allows you to generate bundles that include the exact versions of packages defined in the package.json of your project instead of relying on the ones shipped with the version of WordPress that is running your block plugin. Here is a sample package.json config that does that:

which produces the following output:

  • npm run build creates build/example.js and a matching build/example.assets.php while
  • npm run build-with-externals creates only build-with-externals/example-with-externals.js and no *.assets.php file because all of the dependencies are included in the bundle!

Conclusion

The @wordpress/scripts tooling provides a lot of functionality for working with WordPress-specific and external dependencies in a reliable and consistent way while giving developers the option to configure the generated JS to their project needs.

3 Responses

+ Add a Response

Replying to

Your Response

All fields are required, but we won't publish your email. See our privacy policy.

Cancel

  1. What about other libraries that can be included in blocks as well? For example if two blocks rely on the same “masonry” library, how to properly load it without bundling it? The problem is that wp-scripts compiles everything from metadata of block.json file and there is no way to define dependencies there and if we import them in our blocks they don’t get exctracted from the block bundle.

    1. That’s a great question, Alex! As mentioned in the post, WordPress has this helper function that maps known JS libraries bundled with WP core as they are discovered in the import statements in your JS files. For example, importing the moment package will result in the moment script (bundled with WP core) registered here to be added as a dependency in the generated *.assets.php file. All other dependencies will be added to the generated bundle file like you mentioned.

      if we import them in our blocks they don’t get exctracted from the block bundle.

      Is there a basic code snippet you could share that illustrates the setup? Are you trying to use custom JS dependencies in blocks and want to enqueue them as separate JS files instead of being bundled with the particular block JS bundle?

      The @wordpress/dependency-extraction-webpack-plugin offers a way to map certain imports to script handles via the requestToHandle option. That link includes an example for how to configure it.

  2. Great idea to use –webpack-no-externals to use the exact versions of @wordpress/ packages.