npm package: @10up/ignite-dependency-extraction-webpack-plugin
Description: Webpack plugin for automatically externalizing Ignite WP packages and WordPress Interactivity API modules
Author: 10up
Latest version: 1.0.0

# Ignite Dependency Extraction Webpack Plugin

A webpack plugin that automatically externalizes Ignite WP packages and WordPress Interactivity API modules. This plugin extends `@wordpress/dependency-extraction-webpack-plugin` to handle Ignite-specific dependencies with zero configuration.

## Why Use This Plugin?

When building WordPress plugins or themes that use Ignite WP packages (like `@ignite-wp-carousel/splide`), you need to externalize these imports so they use the shared modules provided by Ignite plugins. This prevents code duplication and reduces bundle sizes.

This plugin automatically:

- Externalizes all `@ignite-wp-*` package imports as script modules
- Handles WordPress Interactivity API (`@wordpress/interactivity`) correctly
- Supports custom package prefixes
- Provides sensible defaults for WordPress development

## Installation

```bash
npm install --save-dev @10up/ignite-dependency-extraction-webpack-plugin
```

## Basic Usage

Replace the standard WordPress Dependency Extraction Plugin with the Ignite version:

```javascript
const IgniteDependencyExtractionWebpackPlugin = require('@10up/ignite-dependency-extraction-webpack-plugin');
const config = require('10up-toolkit/config/webpack.config.js');

const [scriptConfig, moduleConfig] = config;

module.exports = [
	scriptConfig,
	{
		...moduleConfig,
		plugins: [
			// Remove the default WordPress plugin
			...moduleConfig.plugins.filter(
				(plugin) => plugin.constructor.name !== 'DependencyExtractionWebpackPlugin',
			),
			// Add the Ignite plugin
			new IgniteDependencyExtractionWebpackPlugin(),
		],
	},
];
```

That's it! The plugin will now automatically externalize:

- **Any package starting with `@ignite-wp-`** → `import @ignite-wp-*/*`
  - `@ignite-wp-carousel/*` → `import @ignite-wp-carousel/*`
  - `@ignite-wp-core/*` → `import @ignite-wp-core/*`
  - `@ignite-wp-navigation/*` → `import @ignite-wp-navigation/*`
  - Future Ignite packages are automatically supported!
- `@wordpress/interactivity` → `module @wordpress/interactivity`
- `@wordpress/interactivity-router` → `import @wordpress/interactivity-router`

## Configuration

### Default Configuration

The plugin comes with sensible defaults:

```javascript
{
	ignitePackagePrefix: '@ignite-wp-',
	additionalPackagePrefixes: [],
	injectPolyfill: false,
}
```

The `ignitePackagePrefix` uses a wildcard pattern, so any package starting with `@ignite-wp-` is automatically externalized. This means new Ignite packages work without updating the plugin!

**Important**: This plugin extends the WordPress Dependency Extraction Plugin without breaking its default behavior. All WordPress packages (`@wordpress/*`), React, jQuery, Lodash, etc. continue to work exactly as they do in the core plugin.

### Adding Custom Package Prefixes

You can add additional package prefixes to externalize:

```javascript
new IgniteDependencyExtractionWebpackPlugin({
	additionalPackagePrefixes: [
		'@my-company/',  // Matches @my-company/anything
		'@my-plugin/',   // Matches @my-plugin/anything
	],
});
```

### Changing the Ignite Prefix

If you need to use a different prefix (not recommended):

```javascript
new IgniteDependencyExtractionWebpackPlugin({
	ignitePackagePrefix: '@custom-prefix-',
});
```

### Custom Request Handlers

You can extend the plugin with custom logic. **Your handlers are called first**, then the plugin falls back to Ignite handling, and finally to WordPress defaults:

```javascript
new IgniteDependencyExtractionWebpackPlugin({
	// For script modules (called before Ignite and WordPress defaults)
	requestToExternalModule: (request) => {
		// Custom logic for specific packages
		if (request === '@my-custom/package') {
			return 'import @my-custom/package';
		}
		// Return undefined to let the plugin handle it
		return undefined;
	},
	// For regular scripts (called before Ignite and WordPress defaults)
	requestToExternal: (request) => {
		// Custom logic for non-module scripts
		if (request === '@my-custom/package') {
			return ['window', 'MyCustomPackage'];
		}
		return undefined;
	},
	// For WordPress script handles (called before WordPress defaults)
	requestToHandle: (request) => {
		// Custom logic for WordPress script handles
		if (request === '@my-custom/package') {
			return 'my-custom-package';
		}
		return undefined;
	},
});
```

**Handler Priority**:
1. Your custom handler (if provided)
2. Ignite package handling (`@ignite-wp-*` and `additionalPackagePrefixes`)
3. WordPress default handling (`@wordpress/*`, React, jQuery, etc.)

## Complete Example

Here's a complete example of using Ignite packages in your custom plugin:

### webpack.config.js

```javascript
const IgniteDependencyExtractionWebpackPlugin = require('@10up/ignite-dependency-extraction-webpack-plugin');
const config = require('10up-toolkit/config/webpack.config.js');

const [scriptConfig, moduleConfig] = config;

module.exports = [
	scriptConfig,
	{
		...moduleConfig,
		plugins: [
			...moduleConfig.plugins.filter(
				(plugin) => plugin.constructor.name !== 'DependencyExtractionWebpackPlugin',
			),
			new IgniteDependencyExtractionWebpackPlugin(),
		],
	},
];
```

### my-carousel.js

```javascript
import { store, getElement, getContext } from '@wordpress/interactivity';
import { Splide } from '@ignite-wp-carousel/splide';

store('my-plugin/carousel', {
	actions: {
		init: () => {
			const { ref } = getElement();
			const slider = new Splide(ref, {
				type: 'loop',
				perPage: 3,
			});
			slider.mount();
		},
	},
});
```

### register-module.php

```php
add_action('init', function() {
	wp_register_script_module(
		'my-plugin/carousel',
		MY_PLUGIN_URL . 'dist/js/my-carousel.js',
		[
			'@wordpress/interactivity',
			'@ignite-wp-carousel/splide',
		],
		MY_PLUGIN_VERSION
	);
});
```

## How It Works

The plugin wraps `@wordpress/dependency-extraction-webpack-plugin` and extends its behavior:

1. **Handler Chain**: For each import, the plugin calls handlers in this order:
   - Your custom handler (if provided)
   - Ignite package handler (wildcard match on `@ignite-wp-*`)
   - WordPress default handler (`@wordpress/*`, React, jQuery, etc.)

2. **Detect Ignite Packages**: When webpack encounters an import like `import { Splide } from '@ignite-wp-carousel/splide'`, it recognizes the `@ignite-wp-` prefix pattern using a wildcard match.

3. **Externalize as Module**: Instead of bundling the code, webpack marks it as an external dependency: `import @ignite-wp-carousel/splide`.

4. **Generate Dependencies**: The plugin creates a `.asset.php` file listing the external dependencies, which WordPress uses to load them in the correct order.

5. **Runtime Loading**: At runtime, WordPress loads the Ignite plugin's shared module before your code, ensuring the import resolves correctly.

### Wildcard Pattern Matching

The plugin uses `startsWith()` to match package names, which means:

- `@ignite-wp-carousel/splide` ✅ Matches `@ignite-wp-`
- `@ignite-wp-core/icons` ✅ Matches `@ignite-wp-`
- `@ignite-wp-future-package/utils` ✅ Matches `@ignite-wp-` (future packages work automatically!)
- `@wordpress/interactivity` ✅ Handled by WordPress defaults
- `@other-package/utils` ❌ Does not match (unless in `additionalPackagePrefixes`)

This wildcard approach means new Ignite packages are automatically supported without updating the plugin, and all WordPress core functionality remains intact.

## Benefits

- **Zero Configuration**: Works out of the box for all Ignite packages
- **Smaller Bundles**: Shared code isn't duplicated in your bundle
- **Better Performance**: Shared modules are cached by the browser
- **Automatic Updates**: When Ignite plugins update, your code uses the new version
- **Type Safety**: Import errors are caught at build time

## Supported Ignite Packages

The plugin automatically handles **any package starting with `@ignite-wp-`**, including:

- **@ignite-wp-carousel/splide**: Shared Splide carousel library
- **@ignite-wp-core/***: Core utilities and components
- **@ignite-wp-navigation/***: Navigation components
- **@ignite-wp-***: Any future Ignite packages (automatically supported!)

The wildcard pattern means you never need to update the plugin when new Ignite packages are released.

## Requirements

- Node.js 18+
- Webpack 5+
- `@wordpress/dependency-extraction-webpack-plugin` 5.0+ or 6.0+
- WordPress 6.5+ (for script module support)

## Troubleshooting

### Module not found error

If you see "Module not found: @ignite-wp-*":

1. Ensure the corresponding Ignite plugin is active in WordPress
2. Verify your webpack config uses the Ignite plugin
3. Check that you're building for production (script modules)

### Dependencies not loading

If dependencies aren't loading in the correct order:

1. Check that your PHP code lists the Ignite modules as dependencies
2. Verify the `.asset.php` file is being generated
3. Ensure you're using `wp_register_script_module()` (not `wp_register_script()`)

### Custom packages not externalizing

If your custom packages aren't being externalized:

1. Add them to `additionalPackages` in the plugin config
2. Ensure they're registered as script modules in WordPress
3. Verify the package prefix matches exactly (case-sensitive)

## Contributing

Contributions are welcome! Please open an issue or pull request on the [Ignite WP Monorepo](https://github.com/10up/ignite-wp-monorepo).

## License

MIT

## Credits

Created by [10up](https://10up.com) as part of the Ignite WP project.