The way I build WordPress sites has fundamentally changed. In 2026, the performance of your build chain is just as important as the performance of your website. If your “npm run dev” takes 30 seconds to start, you are losing hours of productivity every week. For professional WordPress developers working on enterprise projects, this inefficiency compounds into thousands of dollars in lost productivity annually.
Here is the comprehensive 2026 guide to professional WordPress tooling, covering everything from build tools to deployment pipelines.
Why Vite is replacing webpack in WordPress
Vite has become the gold standard for modern WordPress development. While Webpack served us well for a decade, its “bundle-first” approach is too slow for modern, data-heavy Gutenberg projects that require instant feedback during development.
Cold start and reload times in Vite and webpack
Webpack’s Approach:
- Bundles the entire codebase before starting the dev server
- Cold start time: 15-45 seconds for large projects
- Hot reload: 2-5 seconds for changes
- Memory intensive: Often requires 4GB+ RAM
Vite’s Approach:
- Uses native ES modules in the browser during development
- Cold start time: <1 second, regardless of project size
- Hot Module Replacement: <100ms for most changes
- Efficient memory usage: Typically under 1GB RAM
How much time does Vite save per day
Consider a typical day for a WordPress developer:
- 50 file saves during development
- Webpack workflow: 50 × 5 seconds = 250 seconds (4+ minutes) lost to reloads
- Vite workflow: 50 × 0.1 seconds = 5 seconds total
- Time saved per day: 4 minutes. Per year: 16+ hours
Setting up vite for WordPress
The key challenge with Vite is integrating it with WordPress’s PHP backend. Small plugins such as vite-plugin-wordpress (version 1.0.4 on npm) handle the handshake, and according to its readme they do less than the name suggests:
- Write a
vite.config.phpfile into the project’s config directory, with the information PHP needs to resolve the paths of the assets Vite generated - In development mode, write a
.devfile containing the URL of the Vite dev server, so PHP knows whether to load from the dev server or from the build - Optionally watch files and trigger a full reload (the
watchoption, built onvite-plugin-live-reload)
Printing the script tags and enqueuing the files stays your theme’s job, covered in the manifest section below.
// vite.config.js - Modern WordPress Setup
import { defineConfig } from 'vite';
import wordpress from 'vite-plugin-wordpress';
export default defineConfig({
plugins: [
wordpress({
watch: true,
devDir: process.cwd(),
wordpressConfigDir: 'config'
})
],
build: {
outDir: 'dist',
manifest: true,
rolldownOptions: {
input: {
main: './src/index.js',
blocks: './src/blocks/index.js'
}
}
}
});When to still use webpack
Webpack remains necessary for:
- Legacy projects that can’t be migrated immediately
- Complex bundling requirements (code splitting across multiple entry points)
- Projects requiring extensive plugin ecosystems
- Teams with deep Webpack expertise and no time to retrain
For new projects in 2026, however, Vite is almost always the better choice.
How @wordpress/scripts builds WordPress blocks with webpack
Before moving a block plugin to Vite, it helps to know what the official toolchain already does, because that is what you are replacing. The @wordpress/scripts reference on developer.wordpress.org describes the package as a collection of reusable scripts for WordPress development, configured through the scripts section of package.json. Its build and start commands run on webpack. Version 36.1.0 was published on npm on 7 October 2026, so this is an actively maintained webpack setup, not a legacy one.
wp-scripts build produces one production build, and wp-scripts start rebuilds incrementally while you work. When you pass no entry points, the source directory (./src by default) is scanned for block.json files, and the JavaScript files named in their script fields become the entry points. Without any block.json, the fallback entry is src/index.js (or .jsx, .ts, .tsx), written to build/index.js.
The flags that matter for the topics in this article:
| Flag | What it does |
|---|---|
--hot | Enables Fast Refresh. Requires SCRIPT_DEBUG enabled in WordPress and the Gutenberg plugin installed |
--experimental-modules | Adds support for the viewScriptModule field in block.json |
--blocks-manifest | Writes a PHP file with the metadata of every block.json, for wp_register_block_metadata_collection() |
--source-path, --output-path | Change the source directory and the output directory (build by default) |
So the official stack already has hot reloading for blocks, with two preconditions that are easy to miss on a staging copy where SCRIPT_DEBUG is off.
The same package covers the rest of the chain: lint-js (ESLint with @wordpress/eslint-plugin), lint-style (stylelint with @wordpress/stylelint-config), format, test-unit-js (runs the Vitest installed in the project), test-e2e (Playwright), plugin-zip and packages-update. To change the webpack setup you create a webpack.config.js in the project root, require the default config and extend it with the spread operator, and you keep running wp-scripts commands rather than calling webpack directly.
What the index.asset.php file contains
Every entry point built by the default config gets a matching .asset.php file. It comes from the Dependency Extraction Webpack Plugin, which leaves @wordpress/* imports out of the bundle and maps them to the wp global at runtime: @wordpress/blocks is read from wp.blocks and registered under the script handle wp-blocks. The generated file returns the list of dependencies and a version string calculated from the source code:
<?php return array( 'dependencies' => array( 'react' ), 'version' => 'dd4c2dc50d046ed9d4c063a7ca95702f' );Your PHP passes both values straight to the enqueue call, so nobody maintains the dependency list by hand:
$asset = include plugin_dir_path( __FILE__ ) . 'build/index.asset.php';
wp_enqueue_script( 'my-block', plugins_url( 'build/index.js', __FILE__ ), $asset['dependencies'], $asset['version'] );Vite has no equivalent built in. A Vite build that imports @wordpress/element bundles its own copy unless you declare those packages external and map them to the globals yourself, and that mapping is the main piece of work in a block plugin migration.
How to load Vite assets in WordPress PHP with the manifest
Vite’s own backend integration guide is the reference for any server-rendered setup, WordPress included. It has three parts.
Configuration. Set the entry and turn on build.manifest: true. After vite build, Vite writes .vite/manifest.json into the output directory.
Development. While vite runs, the PHP template prints two module scripts pointing at the dev server: @vite/client and your entry file, for example http://localhost:5173/@vite/client and http://localhost:5173/main.js. Set server.cors to the origin you open in the browser, which is your local WordPress URL. For images and fonts referenced from CSS, either proxy asset requests to Vite or set server.origin so the generated asset URLs resolve against the right host.
Production. PHP reads the manifest, a map of chunk names to chunks. For the entry it takes file (the script to load), prints a stylesheet link for every item in css, and follows imports recursively to add their CSS and optional modulepreload links. Unless the module preload polyfill is disabled, the entry should start with import 'vite/modulepreload-polyfill'.
Vite emits ES modules, so on the WordPress side the natural fit is wp_enqueue_script_module(), available since WordPress 6.5.0, rather than the classic wp_enqueue_script():
$manifest = json_decode( file_get_contents( get_theme_file_path( 'dist/.vite/manifest.json' ) ), true );
$entry = $manifest['src/index.js'];
wp_enqueue_script_module( 'theme-main', get_theme_file_uri( 'dist/' . $entry['file'] ) );
foreach ( $entry['css'] ?? array() as $i => $css ) {
wp_enqueue_style( 'theme-main-' . $i, get_theme_file_uri( 'dist/' . $css ) );
}The .dev file written by vite-plugin-wordpress is what this PHP can check first: if it exists, print the two dev server tags, otherwise read the manifest.
How to use TypeScript with WordPress blocks
In 2026, raw JavaScript is considered a risk for enterprise projects. TypeScript has become the industry standard, and for good reason.
Why typescript matters for WordPress
Error Prevention: TypeScript catches errors before code runs. Consider this common Gutenberg block mistake:
// ❌ Without TypeScript - Runtime Error
attributes: {
color: 'red' // Developer accidentally passes string
}
// Later in code:
setAttributes({ color: { r: 255, g: 0, b: 0 }}) // Expects object, gets string
// ✅ With TypeScript - Compile-time Error
interface ColorAttributes {
color: string;
}
// TypeScript catches the mismatch immediatelyBlock Development Safety: Since Gutenberg blocks rely heavily on complex attributes objects, TypeScript ensures type safety across:
- Block attributes
- Inspector controls
- Server-side rendering
- API responses
Typescript configuration for WordPress
// tsconfig.json - WordPress-optimized
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM"],
"jsx": "react",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"types": ["@wordpress/blocks"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}Where TypeScript is used in WordPress projects
Where TypeScript actually shows up in WordPress work:
- block editor code, where the data shapes are documented and stable
- anything touching the REST API, where a typo in a field name is otherwise a runtime surprise
- shared packages inside an agency, where the types are the contract between teams
How to migrate a WordPress project to TypeScript
For existing projects, migrating to TypeScript can be gradual:
- Start with new files (
.tsextension) - Gradually convert critical files (blocks, API handlers)
- Use
// @ts-checkcomments for quick wins on existing files - Enable strict mode incrementally
HMR in WordPress block development
HMR replaces the save-build-refresh loop with sub-200 ms patches that keep component state intact across edits.
Iteration time with and without HMR
Traditional Workflow:
- Edit CSS for a Gutenberg block
- Save file
- Wait for build (5 seconds)
- Refresh browser
- Navigate to the page (10 seconds)
- Open the block editor
- Navigate 10 levels deep to the setting you’re working on
- Check the change
- Repeat for next iteration
Total time per iteration: 20-30 seconds
Modern HMR Workflow:
- Edit CSS for a Gutenberg block
- Save file
- Change appears instantly in browser (<100ms)
- No navigation lost, no context switching
Total time per iteration: <1 second
What HMR updates in Gutenberg blocks
Modern build tools automatically handle HMR for:
- CSS changes (instant visual updates)
- JavaScript changes (preserving component state)
- React component updates (maintaining editor state)
- Asset changes (images, fonts)
Benefits of HMR in day-to-day block development
In day to day work, HMR shows up in three places:
- an iteration ends with a patched module instead of a full page reload
- you stay in the editor instead of bouncing to the browser and back
- a mistake surfaces while the change is still in your head, not after a rebuild
Per-block CSS and theme.json in FSE themes
Full Site Editing (FSE) themes require a fundamentally different approach to styles and asset management.
How to generate theme.json from design tokens
In 2026, I generate portions of theme.json dynamically from design tokens:
// build-theme-json.js
import designTokens from './figma-tokens.json' with { type: 'json' };
const themeJson = {
settings: {
color: {
palette: designTokens.colors.map(color => ({
slug: color.name,
color: color.value,
name: color.label
}))
},
typography: {
fontFamilies: designTokens.fonts.map(font => ({
slug: font.name,
fontFamily: font.value
}))
}
}
};
// Auto-generate theme.json from Figma tokensThis approach ensures:
- Design system consistency across the theme
- Single source of truth, from Figma to WordPress
- Automatic updates when design tokens change
- Reduced manual configuration errors
How to load CSS only for blocks on the page
In 2026, I don’t load one giant style.css. Modern build chains automatically:
- Analyze block usage on each page
- Split CSS by block type
- Load only required styles for blocks present on the page
- Inline critical CSS for above-the-fold content
This results in:
- the shipped stylesheet contains only the classes the templates actually use
- Faster First Contentful Paint (FCP)
- Improved Core Web Vitals scores
- Better mobile performance
How to configure CSS code splitting in Vite
// Modern CSS splitting strategy
export default {
build: {
cssCodeSplit: true,
rolldownOptions: {
output: {
assetFileNames: 'assets/[name].[hash][extname]',
chunkFileNames: 'assets/[name].[hash].js',
codeSplitting: {
groups: [
{ name: 'core-blocks', test: /src\/blocks\/core/ },
{ name: 'custom-blocks', test: /src\/blocks\/custom/ },
{ name: 'editor-styles', test: /src\/editor/ }
]
}
}
}
}
}Vite vs webpack vs Parcel vs esbuild in 2026
| Tool | Speed | Complexity | Best For | WordPress Integration |
|---|---|---|---|---|
| Vite | Ultra Fast | Medium | Modern FSE Themes / Plugins | Excellent (via plugins) |
| Webpack | Slow | High | Legacy Projects / Complex Bundling | Excellent (mature ecosystem) |
| Parcel | Fast | Low | Small / Simple Plugins | Good (zero-config) |
| Esbuild | Extreme | Medium | High-speed Backend Minification | Limited (build-only) |
| Turbopack | Extreme | Low | Next.js Projects | Not available |
When to choose each tool
Choose Vite if:
- Starting a new WordPress project
- Using modern JavaScript (ES modules)
- Need fast development experience
- Working with FSE themes or Gutenberg blocks
- Team values developer experience
Choose Webpack if:
- Maintaining legacy WordPress projects
- Require extensive plugin ecosystem
- Complex code-splitting requirements
- Team has deep Webpack expertise
- Migration risk is too high
Choose Parcel if:
- Building simple WordPress plugins
- Want zero-configuration setup
- Prefer convention over configuration
- Small to medium projects
npm vs yarn vs pnpm for WordPress themes
In 2026, package manager choice has a significant impact on build performance.
Install time and disk space of npm, yarn and pnpm
For a typical WordPress theme with 150 dependencies:
| Manager | Install Time | Disk Space | Node Modules Size |
|---|---|---|---|
| pnpm | 8 seconds | 250 MB | 280 MB |
| yarn | 15 seconds | 400 MB | 450 MB |
| npm | 20 seconds | 500 MB | 550 MB |
Why pnpm installs faster and uses less disk space
pnpm uses a content-addressable store:
- Packages are stored once globally
- Projects link to the global store (hard links)
- disk usage grows with distinct versions, not with project count
- Faster installs (no duplicate downloads)
The pnpm documentation explains the mechanism: when a dependency is updated, only the files that differ are added to the store, so a new version of a 100-file package that changes one file adds one file. Projects get hard links to the store instead of copies. The same page gives no benchmark figures, so read the install times in the table above as an illustration for one theme, not a measurement you can reproduce.
# How to set up a modern WordPress project with Vite or Webpack
pnpm create vite@latest my-wordpress-theme
cd my-wordpress-theme
pnpm installLatest Vite, webpack and @wordpress/scripts versions in 2026
Version claims in build tooling articles age fast, so these are the current releases as recorded in the npm registry (the time field of each package) on 15 October 2026:
| Package | Latest version | Published | Current major since |
|---|---|---|---|
| vite | 8.3.4 | 2026-10-08 | 8.0.0, 2026-03-12 |
| webpack | 5.111.1 | 2026-09-18 | 5.0.0, 2020-10-10 |
| @wordpress/scripts | 36.1.0 | 2026-10-07 | 36.0.0, 2026-09-23 |
| pnpm | 12.11.2 | 2026-10-09 | 12.0.0, 2026-08-26 |
| turbo | 2.11.8 | 2026-10-13 | 2.0.0, 2024-06-04 |
| vite-plugin-wordpress | 1.0.4 | 2026-06-09 | first published 2025-07-29 |
Two of these releases change the code in this article. Vite 8 uses Rolldown and Oxc instead of esbuild and Rollup: build.rollupOptions is deprecated and renamed build.rolldownOptions, the object form of output.manualChunks is no longer supported, and the function form is deprecated in favour of Rolldown’s codeSplitting option. The Vite examples above already use the new names. Turbo 2.0 renamed the pipeline key in turbo.json to tasks; the Turborepo codemod reference lists it as rename-pipeline, applied together with the other 2.0 changes by npx @turbo/codemod migrate.
webpack 5, by contrast, has been the current major for six years. @wordpress/scripts moves fast: majors 33 to 36 were all published between July and September 2026, so pin the version in package.json and read the changelog before running packages-update.
WordPress monorepo for agencies with Turbo
For agencies managing 50+ WordPress sites, 2026 is the year of the Monorepo.
Benefits of monorepo architecture
- Shared Component Library: One “Core Component” library used across all client sites
- Consistent Tooling: Same build tools, linting, testing across all projects
- Atomic Updates: Update a shared component once, deploy to all sites
- Parallel Builds: Turbo or Nx can build/test multiple projects simultaneously
How to configure turbo.json for WordPress
// turbo.json
{
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"test": {
"dependsOn": ["build"]
},
"lint": {}
}
}How a monorepo changes day-to-day agency work
What changes in day-to-day work:
- one install and one lockfile instead of one per project
- shared code moves to a package, so a fix lands once rather than in every repo
- a new developer runs the same commands on every project
- a dependency bump is reviewed once, in one pull request
WordPress build tools in CI/CD pipelines
Modern build tools integrate with professional WordPress development services:
- CI/CD Pipelines: Automated builds on every commit
- Code Quality: ESLint, Prettier, TypeScript integrated
- Testing: Jest, Vitest for unit tests
- Deployment: Automated deployment to staging/production
For WooCommerce stores, modern tooling enables:
- Faster development of custom checkout flows
- Real-time preview of payment integrations
- Rapid iteration on product display components
How to analyze bundle size and build time in WordPress
Modern build tools provide built-in performance insights:
- Bundle analysis: Identify large dependencies
- Build time tracking: Monitor build performance over time
- Asset optimization: Automatic minification, tree-shaking
- Source map generation: Better debugging in production
These tools help maintain fast WordPress performance throughout the development lifecycle.
Conclusion
The tools you use define the quality of the product you deliver. By embracing Vite, TypeScript, and modern build chains, you make sure that your development process is as fast and reliable as the websites you build.
For professional WordPress developers and agencies, modern tooling isn’t optional - it’s essential for remaining competitive. Faster builds, type safety at the IDE rather than at QA, and HMR that survives a component refactor compound into measurable hours saved per sprint.
Are you still waiting for Webpack to finish? It’s time to upgrade your tooling.
Looking to modernize your WordPress development workflow? I specialize in custom WordPress development using the latest 2026 tooling standards. I can help migrate your existing projects to Vite, set up TypeScript, or build new projects with modern architecture from the start.







