Back to Blog

Compiling and Enqueuing Assets in WordPress with @wordpress/scripts

|

Dealing with WebPack is no picnic, and the problem only worsens the bigger or more complicated your project gets. Say you want to add SCSS compiling, or TypeScript, or SVG/imports imports in your CSS, or CSS modules — the list goes on — now you’ve not only got a ton of things you have to configure properly, you have a bunch of npm dependencies to manage.

What if I told you that @wordpress/scripts does all that FOR you?

And with no WebPack config (unless you want it, and perhaps in a future post, I can show you how to extend the built-in @wordpress/scripts WebPack).

Let me tell you how.

📦 Step 1: Install @wordpress/scripts

In your plugin or theme directory:

bash
npm init -y
npm install @wordpress/scripts --save-dev

🛠️ Step 2: Configure package.json

Add custom scripts:

json
"scripts": {
  "build": "wp-scripts build",
  "watch": "wp-scripts start",
  "watch:hot": "wp-scripts start --hot"
}

Optionally, you can specify specific JavaScript files to compile, or even a custom output path:

json
"scripts": {
  "build": "wp-scripts build assets/src/one.js assets/src/two.js --output-path=assets/dist/",
  "watch": "wp-scripts start assets/src/one.js assets/src/two.js --output-path=assets/dist/",
  "watch:hot": "wp-scripts start assets/src/one.js assets/src/two.js --output-path=assets/dist/ --hot"
}

📁 Step 3: Set Up Your Project Structure

text
assets/
  src/
    index.js     (or index.ts)
    style.scss
  build/
    index.js
    index.asset.php
    style.css

Inside index.js, import styles directly — this will make it so we don’t have to tell the wp-scripts handler to compile them individually:

text
import './style.scss';

⚙️ Step 4: Compile Assets

Build assets for production:

bash
npm run build

For development (watch mode):

bash
npm run watch

For hot module replacement (HMR) mode:

bash
npm run watch:hot

This will output the following files:

text
build/index.js

build/index.asset.php

build/style.css

🧩 Step 5: Register and Enqueue in PHP

Notice the build/index.asset.php? The reason that’s there is so we can auto-register it so we can enqueue it wherever we need it.

Here’s a generalized function that will handle auto-registration for you (NOTE: you should customize the my-plugin parts to fit your plugin/theme so it doesn’t get confused with other plugins or themes):

javascript
function register_assets() {
	$asset_root = plugin_dir_path( __FILE__ ) . 'assets/build/';
	$asset_uri  = plugin_dir_url( __FILE__ ) . 'assets/build/';
	$asset_files = glob( $asset_root . '*.asset.php' );

	// Load runtime if present (used by webpack for chunking).
	if ( true === is_readable( $asset_root . 'runtime.js' ) ) {
		enqueue_script(
			'my-plugin/runtime',
			$asset_uri . 'runtime.js',
			array(),
			filemtime( $asset_root . 'runtime.js' )
		);
	}

	foreach ( $asset_files as $file ) {
		$script_meta = require $file;
		$slug = basename( $file, '.asset.php' );

		$handle = "my-plugin/{$slug}";
		$js_path = $asset_root . "{$slug}.js";
		$js_uri  = $asset_uri . "{$slug}.js";
		$css_path = $asset_root . "{$slug}.css";
		$css_uri  = $asset_uri . "{$slug}.css";

		if ( true === is_readable( $css_path ) ) {
			wp_register_style(
				$handle,
				$css_uri,
				array_filter( $script_meta['dependencies'], 'wp_style_is' ),
				$script_meta['version']
			);
		}

		if ( true === is_readable( $js_path ) ) {
			wp_register_script(
				$handle,
				$js_uri,
				array_filter( $script_meta['dependencies'], 'wp_script_is' ),
				$script_meta['version'],
				array( 'in_footer' => true )
			);
		}
	}
}

add_action( 'init', 'register_assets' );

And now you can easily enqueue the scripts where you need them, like this:

javascript
function enqueue_my_scripts() {
    wp_enqueue_script( 'my-plugin/index' ); // NOTE: 'index' comes from index.asset.php.
    wp_enqueue_style( 'my-plugin/index' );
}

add_action( 'wp_enqueue_scripts', 'enqueue_my_scripts' );

🧼 Bonus: Keep It Clean

Add the following to .gitignore so it does not get included in your source code (unless you want it to be!).

text
assets/build/

You can build before deployment or commit the built assets as needed.

Share this article: