Asset Pipeline (SCSS/ESBuild/RTL)
warning
Build tools are part of your deployment chain. Do not depend on running Node builds manually on production. Build on a workstation/CI, then deploy artifacts.
Asset Pipeline (SCSS/ESBuild/RTL) Explained
| Folder | Purpose | Example |
|---|---|---|
assets/src/ | Source SCSS/JS | assets/src/app.scss |
assets/build/ | Compiled output | assets/build/app.css |
| Enqueue | Load build outputs | wp_enqueue_style() |
| RTL | Right-to-left CSS variant | app-rtl.css (optional) |
Why It Matters
- SCSS keeps styles modular and reduces copy/paste.
- Bundling JS helps avoid scattered scripts.
- Build outputs can be versioned and cached safely.
How It Works
You write source files, run a build command, and deploy only the compiled output. WordPress enqueues the build files.
flowchart LR
SRC[assets/src] --> BUILD[Build step]
BUILD --> OUT[assets/build]
OUT --> ENQ[wp_enqueue_*]
Practical Walkthrough
Step 1: Create Source/Build Folders
create-asset-pipeline-folders.sh
cd /var/www/html
mkdir -p wp-content/themes/generatepress-child/assets/src
mkdir -p wp-content/themes/generatepress-child/assets/build
Step 2: Create Minimal Source Files
create-source-files.sh
cat > wp-content/themes/generatepress-child/assets/src/app.scss <<'EOF'
.gp-pipeline-proof {
padding: 16px;
border: 2px solid #1e3a8a;
}
EOF
cat > wp-content/themes/generatepress-child/assets/src/app.js <<'EOF'
console.log('asset pipeline app.js');
EOF
Step 3: Minimal Build Scripts (Example)
wp-content/themes/generatepress-child/package.json
{
"name": "generatepress-child",
"private": true,
"devDependencies": {
"esbuild": "^0.20.0",
"sass": "^1.69.0"
},
"scripts": {
"build:css": "sass assets/src/app.scss assets/build/app.css --no-source-map",
"build:js": "esbuild assets/src/app.js --bundle --minify --outfile=assets/build/app.js",
"build": "npm run build:css && npm run build:js"
}
}
Step 4: Enqueue Build Outputs
wp-content/themes/generatepress-child/inc/enqueue.php
<?php
add_action( 'wp_enqueue_scripts', function() {
$css = get_stylesheet_directory() . '/assets/build/app.css';
$js = get_stylesheet_directory() . '/assets/build/app.js';
if ( file_exists( $css ) ) {
wp_enqueue_style(
'gp-child-build',
get_stylesheet_directory_uri() . '/assets/build/app.css',
array(),
filemtime( $css )
);
}
if ( file_exists( $js ) ) {
wp_enqueue_script(
'gp-child-build',
get_stylesheet_directory_uri() . '/assets/build/app.js',
array(),
filemtime( $js ),
true
);
}
} );
Practical Examples
Example 1: Commit Source, Deploy Build
| Keep in Git | Deploy to server |
|---|---|
assets/src/ | assets/build/ |
package.json | compiled CSS/JS |
Example 2: Cache Busting with filemtime()
When the build output changes, the version changes automatically.
Best Practices
| Practice | Why |
|---|---|
| Keep build outputs small | Performance |
| Prefer build in CI | Repeatable deploys |
Guard enqueues with file_exists | Prevents fatal/404 issues |
| Document build commands | Helps future maintainers |
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Build files 404 | Not deployed | Ensure assets/build/ is deployed |
| CSS changes not visible | Cache | Purge LSCache and verify version changes |
| Build fails | Node/tooling mismatch | Pin versions and build in CI |
Hands-On
- Create
assets/src/app.scssand build toassets/build/app.css. - Enqueue
assets/build/app.csswithfilemtime(). - Change SCSS, rebuild, and confirm cache-busting works.
Quick Reference
asset-pipeline-cheatsheet.sh
cd /var/www/html/wp-content/themes/generatepress-child
ls assets/src
ls assets/build
What's Next
- Next: Internationalization (i18n)
- Related: Loading Styles & Scripts