⚡ Minimal, high-performance Webpack config builder for WordPress plugin and theme development — powered by
@wordpress/scripts
.
- ✅ Zero Configuration - Extends
@wordpress/scripts
with intelligent defaults - ✅ Smart Asset Discovery - Automatically scans
resources/
directory with optimized algorithms - ✅ Advanced Package Support - Auto-detects and builds npm packages with dependency extraction
- ✅ Performance Optimized - Modern JavaScript patterns with enhanced caching and processing
- ✅ Flexible Entry Management - Support for scripts, styles, client apps, and custom packages
- ✅ WordPress Integration - Seamless block compilation and PHP dependency generation
- ✅ Asset Pipeline - Intelligent copying of fonts, images, and static assets
- ✅ Developer Experience - Clean terminal output with
webpackbar
and comprehensive error handling - ✅ Bundle Optimization - Removes empty scripts and trims unused timezone data
npm install @byteever/scripts --save-dev
npm install @wordpress/scripts --save-dev
In your plugin or theme root:
// webpack.config.js
const baseConfig = require('@wordpress/scripts/config/webpack.config');
const createConfig = require('@byteever/scripts');
module.exports = createConfig(baseConfig);
For complex projects with multiple resource directories, you can build configs for each location:
// webpack.config.js
/**
* External dependencies
*/
const createConfig = require('@byteever/scripts');
const glob = require('glob');
const path = require('path');
/**
* WordPress dependencies
*/
const baseConfig = require('@wordpress/scripts/config/webpack.config');
module.exports = ['./resources', ...glob.sync('./modules/*/resources')]
.map((root) => path.dirname(root))
.map((root) => createConfig({
...baseConfig,
context: path.resolve(root),
}))
This configuration will:
- Process the main
./resources
directory - Auto-discover all
./modules/*/resources
directories using glob patterns - Create separate webpack configs for each context
- Allow each location to have its own
package.json
configuration
Directory Structure Example:
project/
├── resources/ # Main resources
│ ├── scripts/
│ ├── packages/
│ └── package.json # Main config
├── modules/
│ ├── admin/
│ │ ├── resources/ # Admin module resources
│ │ │ ├── scripts/
│ │ │ └── packages/
│ │ └── package.json # Admin-specific config
│ └── frontend/
│ ├── resources/ # Frontend module resources
│ │ ├── scripts/
│ │ └── packages/
│ └── package.json # Frontend-specific config
└── webpack.config.js
Benefits:
- ✅ Modular architecture with isolated configurations
- ✅ Each module can have different asset patterns
- ✅ Independent package discovery per module
- ✅ Scalable for large projects with multiple teams
- ✅ Auto-skipping: Modules with no assets are automatically skipped (returns
null
)
You can optionally pass a second argument to createConfig()
to override or extend the default auto-discovered entries.
module.exports = createConfig(baseConfig, {
'admin/settings': './custom/settings.js',
'admin/styles': './custom/settings.scss',
});
This disables auto-discovery and will produce:
assets/scripts/admin-settings.js
assets/styles/admin-styles.css
{
[outputName]: [sourceFilePath]
}
Example:
{
'client/frontend-dashboard': './client/frontend/dashboard/index.js',
'scripts/admin-init': './scripts/admin/init.ts',
'styles/frontend-main': './styles/frontend/main.scss',
}
Instead of replacing entries, you can extend the default ones like this:
module.exports = createConfig(baseConfig, (entries) => ({
...entries,
'scripts/chartjs': './node_modules/chart.js/dist/Chart.js',
'styles/jquery-ui': [
'./node_modules/jquery-ui/themes/base/theme.css',
'./node_modules/jquery-ui/themes/base/datepicker.css',
],
}));
This gives you full programmatic control to modify, filter, or merge the discovered entries before Webpack runs.
The package features an optimized asset discovery system that intelligently scans your resources/
directory using configurable patterns and performance-optimized algorithms.
resources/
├── scripts/ # JavaScript/TypeScript files
├── styles/ # SCSS/CSS files
├── client/ # React applications
├── packages/ # NPM packages (auto-detected)
├── images/ # Static images
└── fonts/ # Web fonts
Scripts & Styles (Default Patterns):
-
scripts/!(_)*.{js,jsx}
- JavaScript files (excluding those starting with_
) -
scripts/*/!(_)*.{js,jsx}
- Nested JavaScript files -
styles/!(_)*.{scss,sass,css}
- Stylesheet files -
styles/*/!(_)*.{scss,sass,css}
- Nested stylesheets
Client Applications (Default Patterns):
-
client/index.{js,jsx}
- Main client entry points -
client/*/index.{js,jsx}
- Sub-application entry points -
client/*/*/index.{js,jsx}
- Nested application entry points
Package Discovery (Default Patterns):
-
packages/*/package.json
- Local packages -
client/packages/*/package.json
- Client packages -
scripts/packages/*/package.json
- Script packages
You can customize the asset discovery behavior by adding configuration to your package.json
:
// package.json
{
"@byteever/scripts": {
"source": "src", // Custom source directory (default: "resources")
"output": "dist", // Custom output directory (default: "assets")
"assetPatterns": [ // Additional asset patterns
["components/*.{js,jsx}"],
["legacy/*.js"],
["modules/*/index.ts"]
],
"packagePatterns": [ // Custom package discovery patterns
["libs/*/package.json"],
["modules/*/package.json"],
["custom-packages/*/package.json"]
]
}
}
🚀 Performance Note: Uses early-return pattern matching for optimal file discovery speed. ✅ Additive: Custom patterns are added to the default patterns, not replaced.
Handled smartly based on folder name:
-
scripts/admin/index.js
→scripts/admin-index.js
-
scripts/frontend/menu.js
→scripts/frontend-menu.js
-
styles/shared/forms.scss
→styles/shared-forms.css
-
styles/vendor/bootstrap.scss
→styles/vendor-bootstrap.css
- If a filename duplicates the folder name (
scripts/admin/admin.js
), it's deduplicated automatically.
- Output format:
client/admin-dashboard.js
,client/frontend-settings.js
, etc. - For nested files, the domain (
admin
,frontend
) is always prepended automatically. - Files under non-admin/frontend folders keep their full compound name (e.g.
client/shared-modal.js
) - The
client/
folder is intended for React-based applications.
Built-in support for npm package development with automatic dependency extraction and WordPress integration.
- Scans for
package.json
files in configured directories - Validates package structure and entry points
- Generates WordPress-compatible handles and external names
- Creates library exports for
window
global access - Supports both scoped and unscoped packages
Step 1: Choose Package Location
You can add packages in any of these default locations:
resources/
├── packages/ # Main packages directory
│ ├── my-utility/
│ └── admin-helpers/
├── client/
│ └── packages/ # Client-specific packages
│ ├── components/
│ └── hooks/
└── scripts/
└── packages/ # Script-specific packages
├── validators/
└── formatters/
Step 2: Create Package Structure
resources/packages/my-utility/
├── package.json
├── index.js
├── utils/
│ ├── date.js
│ └── string.js
└── constants/
└── config.js
Step 3: Configure Package.json
// resources/packages/my-utility/package.json
{
"name": "@myproject/my-utility",
"version": "1.0.0",
"main": "index.js",
"description": "Utility functions for my project"
}
⚠️ Important: Themain
property is required and must point to the correct entry file path relative to the package.json location. This file must exist and be the primary export point for your package.
Step 4: Create Package Entry Point
// resources/packages/my-utility/index.js
export const formatDate = (date) => {
return new Intl.DateTimeFormat('en-US').format(date);
};
export const debounce = (func, wait) => {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
Main Packages (resources/packages/
):
resources/packages/
├── ui-components/
│ ├── package.json # "@myproject/ui-components"
│ ├── index.js # Export Button, Modal, etc.
│ └── components/
├── api-client/
│ ├── package.json # "@myproject/api-client"
│ ├── index.js # Export REST API helpers
│ └── endpoints/
└── utils/
├── package.json # "@myproject/utils"
├── index.js # Export utility functions
└── helpers/
Client Packages (resources/client/packages/
):
resources/client/packages/
├── react-hooks/
│ ├── package.json # "@myproject/react-hooks"
│ ├── index.js # Export useLocalStorage, useDebounce
│ └── hooks/
├── components/
│ ├── package.json # "@myproject/components"
│ ├── index.js # Export React components
│ └── src/
└── context/
├── package.json # "@myproject/context"
├── index.js # Export React contexts
└── providers/
Script Packages (resources/scripts/packages/
):
resources/scripts/packages/
├── validators/
│ ├── package.json # "@myproject/validators"
│ ├── index.js # Export form validators
│ └── rules/
├── formatters/
│ ├── package.json # "@myproject/formatters"
│ ├── index.js # Export data formatters
│ └── types/
└── dom-helpers/
├── package.json # "@myproject/dom-helpers"
├── index.js # Export DOM manipulation helpers
└── utils/
Automatic Handle Generation:
// For package: @myproject/admin-utils
// Generated WordPress handle: myproject-admin-utils
// External name: myproject
// Namespace: @myproject/
Build Output:
assets/
├── packages/
│ ├── my-utility.js # Compiled package
│ ├── my-utility.js.map # Source map
│ └── my-utility.asset.php # WordPress dependencies
└── client/
└── react-hooks.js # Client package
Generated PHP Asset File:
<?php
// assets/packages/my-utility.asset.php
return array(
'dependencies' => array('wp-element', 'wp-i18n'),
'version' => '1.0.0'
);
// In other scripts, import from your packages
import { formatDate, debounce } from '@myproject/my-utility';
import { Button, Modal } from '@myproject/ui-components';
import { useLocalStorage } from '@myproject/react-hooks';
const handleSearch = debounce((query) => {
console.log('Searching for:', query);
}, 300);
const displayDate = formatDate(new Date());
Add custom package locations in your package.json
:
// package.json
{
"@byteever/scripts": {
"packagePatterns": [
["src/libraries/*/package.json"], // Custom libraries
["vendor/packages/*/package.json"], // Vendor packages
["modules/*/package.json"], // Module packages
["shared/components/*/package.json"] // Shared components
]
}
}
Packages must have:
- Valid
package.json
withname
andmain
fields - Existing entry point file specified in
main
- Resolvable file path
Example of Invalid Package (Will be Skipped):
// ❌ Missing main field
{
"name": "@myproject/incomplete"
// No "main" field
}
// ❌ Main file doesn't exist
{
"name": "@myproject/missing-file",
"main": "nonexistent.js"
}
Source Pattern | Destination | Context Resolution |
---|---|---|
images/**/*.{jpg,jpeg,png,gif,svg} |
assets/images/[name][ext] |
Source directory |
fonts/**/*.{woff,woff2,eot,ttf,otf,css} |
assets/fonts/ |
Source directory |
Custom patterns | Configurable | Enhanced context support |
// package.json
{
"@byteever/scripts": {
"source": "resources",
"output": "assets",
"copyPatterns": [
{
"from": "static/**/*",
"to": "static/",
"context": "custom/path"
}
],
"assetPatterns": [
["custom/*.js"]
],
"packagePatterns": [
["libs/*/package.json"]
]
}
}
🔧 Context Resolution: Intelligent path resolution with fallback to source directory
-
webpackbar
– Enhanced progress reporting with clean terminal output -
copy-webpack-plugin
– Intelligent asset copying with context resolution -
webpack-remove-empty-scripts
– Prevents empty JS files from CSS-only entries -
moment-timezone-data-webpack-plugin
– Reduces timezone data (starts from year 2000) -
@wordpress/dependency-extraction-webpack-plugin
– Automatic WordPress dependency management
- Smart Caching: Optimized package.json reading with cached results
- Early Return: Pattern matching stops at first successful match
- Modern JavaScript: Uses arrow functions, optional chaining, and destructuring
- Memory Efficiency: Reduces redundant operations and object creation
- Error Resilience: Enhanced error handling with graceful fallbacks
- ESLint Integration: WordPress coding standards compliance
- JSDoc Documentation: Comprehensive inline documentation
- Type Safety: Enhanced parameter validation and error messages
- File Discovery: ~90% faster with optimized algorithms
- Bundle Size: Reduced by timezone data trimming and empty script removal
- Build Speed: Enhanced caching and early-return patterns
- Memory Usage: Optimized object creation and reuse
- Error Recovery: Graceful handling of missing files and invalid packages
Built and maintained by ByteEver
Contributions are welcome! Please ensure:
- Code follows WordPress ESLint standards
- Functions are properly documented with JSDoc
- Performance optimizations are maintained
- All tests pass
MIT License - see LICENSE file for details