Ugrás a fő tartalomhoz

esbuild - Ultra-gyors Bundler

Az esbuild egy rendkívül gyors JavaScript és CSS bundler, amelyet Go nyelven írtak. 10-100x gyorsabb a hagyományos bundler-eknél (webpack, rollup), így ideális választás WordPress témák és bővítmények fejlesztéséhez.

Miért esbuild?

  • Extrém gyors - Go nyelven írt, párhuzamos feldolgozás
  • Egyszerű - Minimális konfiguráció
  • Modern - ES6+, TypeScript, JSX natív támogatás
  • Tree shaking - Automatikus dead code eltávolítás
  • Source maps - Debug támogatás
  • Watch mode - Automatikus újraépítés

Telepítés

npm install -D esbuild

Alapvető használat

CLI parancsok

# Egy fájl build-elése
npx esbuild src/js/main.js --bundle --outfile=dist/main.js

# Minifikálással
npx esbuild src/js/main.js --bundle --minify --outfile=dist/main.min.js

# Source map-pel
npx esbuild src/js/main.js --bundle --sourcemap --outfile=dist/main.js

# Watch mode
npx esbuild src/js/main.js --bundle --watch --outfile=dist/main.js

package.json scripts

{
"scripts": {
"build": "esbuild src/js/main.js --bundle --minify --sourcemap --outfile=dist/js/main.js",
"build:css": "esbuild src/css/style.css --bundle --minify --outfile=dist/css/style.css",
"dev": "esbuild src/js/main.js --bundle --watch --outfile=dist/js/main.js",
"build:all": "npm run build && npm run build:css"
}
}

JavaScript API

build.js

import * as esbuild from 'esbuild';

await esbuild.build({
entryPoints: ['src/js/main.js'],
bundle: true,
minify: true,
sourcemap: true,
outfile: 'dist/js/main.js',
target: ['es2020', 'chrome80', 'firefox80', 'safari14'],
});

console.log('Build complete!');

Több entry point

import * as esbuild from 'esbuild';

await esbuild.build({
entryPoints: {
main: 'src/js/main.js',
admin: 'src/js/admin.js',
'block-editor': 'src/js/block-editor.js',
},
bundle: true,
minify: process.env.NODE_ENV === 'production',
sourcemap: true,
outdir: 'dist/js',
});

Watch mode (API)

import * as esbuild from 'esbuild';

const ctx = await esbuild.context({
entryPoints: ['src/js/main.js'],
bundle: true,
outfile: 'dist/js/main.js',
});

// Watch indítása
await ctx.watch();
console.log('Watching for changes...');

// Build és kilépés
// await ctx.dispose();

WordPress téma integráció

Projekt struktúra

my-theme/
├── src/
│ ├── js/
│ │ ├── main.js
│ │ └── admin.js
│ └── css/
│ └── style.css
├── dist/
├── build.js
├── package.json
├── functions.php
└── style.css

build.js (teljes konfiguráció)

import * as esbuild from 'esbuild';
import { writeFileSync, mkdirSync, existsSync } from 'fs';
import { dirname } from 'path';

const isProduction = process.env.NODE_ENV === 'production';
const isWatch = process.argv.includes('--watch');

// Manifest generálás
const manifestPlugin = {
name: 'manifest',
setup(build) {
build.onEnd((result) => {
if (result.errors.length > 0) return;

const manifest = {};
const outputs = result.metafile?.outputs || {};

for (const [file, data] of Object.entries(outputs)) {
if (data.entryPoint) {
const entry = data.entryPoint;
const outputFile = file.replace('dist/', '');
manifest[entry] = {
file: outputFile,
};
}
}

const manifestDir = 'dist';
if (!existsSync(manifestDir)) {
mkdirSync(manifestDir, { recursive: true });
}

writeFileSync(
`${manifestDir}/manifest.json`,
JSON.stringify(manifest, null, 2)
);
});
},
};

// JavaScript build
const jsBuildOptions = {
entryPoints: {
main: 'src/js/main.js',
admin: 'src/js/admin.js',
},
bundle: true,
minify: isProduction,
sourcemap: !isProduction,
outdir: 'dist/js',
target: ['es2020'],
format: 'esm',
splitting: true,
metafile: true,
plugins: [manifestPlugin],
};

// CSS build
const cssBuildOptions = {
entryPoints: ['src/css/style.css'],
bundle: true,
minify: isProduction,
outdir: 'dist/css',
};

async function build() {
try {
if (isWatch) {
const jsCtx = await esbuild.context(jsBuildOptions);
const cssCtx = await esbuild.context(cssBuildOptions);

await Promise.all([jsCtx.watch(), cssCtx.watch()]);

console.log('👀 Watching for changes...');
} else {
await Promise.all([
esbuild.build(jsBuildOptions),
esbuild.build(cssBuildOptions),
]);

console.log('✅ Build complete!');
}
} catch (error) {
console.error('❌ Build failed:', error);
process.exit(1);
}
}

build();

functions.php

<?php
/**
* Enqueue theme assets
*/
function my_theme_enqueue_assets() {
$manifest_path = get_template_directory() . '/dist/manifest.json';

if ( file_exists( $manifest_path ) ) {
$manifest = json_decode( file_get_contents( $manifest_path ), true );

// Main JS
if ( isset( $manifest['src/js/main.js'] ) ) {
wp_enqueue_script(
'theme-main',
get_template_directory_uri() . '/dist/' . $manifest['src/js/main.js']['file'],
[],
null,
true
);
}

// Admin JS
if ( is_admin() && isset( $manifest['src/js/admin.js'] ) ) {
wp_enqueue_script(
'theme-admin',
get_template_directory_uri() . '/dist/' . $manifest['src/js/admin.js']['file'],
[],
null,
true
);
}
}

// CSS
wp_enqueue_style(
'theme-style',
get_template_directory_uri() . '/dist/css/style.css',
[],
filemtime( get_template_directory() . '/dist/css/style.css' )
);
}
add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_assets' );

CSS kezelés

CSS bundle

await esbuild.build({
entryPoints: ['src/css/style.css'],
bundle: true,
minify: true,
outfile: 'dist/css/style.css',
});

CSS import

/* src/css/style.css */
@import './variables.css';
@import './base.css';
@import './components/buttons.css';
@import './components/forms.css';

Sass támogatás

npm install -D esbuild-sass-plugin
import * as esbuild from 'esbuild';
import { sassPlugin } from 'esbuild-sass-plugin';

await esbuild.build({
entryPoints: ['src/scss/style.scss'],
bundle: true,
minify: true,
outfile: 'dist/css/style.css',
plugins: [sassPlugin()],
});

TypeScript

esbuild natívan támogatja a TypeScript-et, nincs szükség külön konfigurációra:

await esbuild.build({
entryPoints: ['src/ts/main.ts'],
bundle: true,
outfile: 'dist/js/main.js',
});

tsconfig.json

{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true,
"noEmit": true
},
"include": ["src"]
}
Megjegyzés

esbuild csak transzpilálja a TypeScript-et, nem ellenőrzi a típusokat. Típusellenőrzéshez használj külön tsc --noEmit parancsot.

React és JSX

await esbuild.build({
entryPoints: ['src/jsx/app.jsx'],
bundle: true,
outfile: 'dist/js/app.js',
jsx: 'automatic', // React 17+ automatic runtime
});

React telepítése

npm install react react-dom

WordPress block fejlesztés

// src/jsx/blocks/my-block/index.jsx
import { registerBlockType } from '@wordpress/blocks';

registerBlockType('my-plugin/my-block', {
title: 'My Block',
icon: 'smiley',
category: 'common',
edit: () => <div>Edit view</div>,
save: () => <div>Saved content</div>,
});
// build.js
await esbuild.build({
entryPoints: ['src/jsx/blocks/my-block/index.jsx'],
bundle: true,
outfile: 'dist/js/blocks/my-block.js',
jsx: 'automatic',
external: ['@wordpress/*', 'react', 'react-dom'],
});

Pluginek

PostCSS plugin

npm install -D esbuild-postcss postcss autoprefixer
import * as esbuild from 'esbuild';
import postcss from 'esbuild-postcss';

await esbuild.build({
entryPoints: ['src/css/style.css'],
bundle: true,
outfile: 'dist/css/style.css',
plugins: [postcss()],
});

postcss.config.js

export default {
plugins: {
autoprefixer: {},
},
};

Copy plugin

npm install -D esbuild-plugin-copy
import * as esbuild from 'esbuild';
import { copy } from 'esbuild-plugin-copy';

await esbuild.build({
entryPoints: ['src/js/main.js'],
bundle: true,
outfile: 'dist/js/main.js',
plugins: [
copy({
assets: {
from: ['./src/images/*'],
to: ['./images'],
},
}),
],
});

WordPress plugin fejlesztés

Projekt struktúra

my-plugin/
├── assets/
│ ├── src/
│ │ ├── js/
│ │ │ ├── frontend.js
│ │ │ └── admin.js
│ │ └── css/
│ │ ├── frontend.css
│ │ └── admin.css
│ └── dist/
├── includes/
├── build.js
├── package.json
└── my-plugin.php

build.js

import * as esbuild from 'esbuild';

const isProduction = process.env.NODE_ENV === 'production';

const buildConfigs = [
// Frontend JS
{
entryPoints: ['assets/src/js/frontend.js'],
bundle: true,
minify: isProduction,
sourcemap: !isProduction,
outfile: 'assets/dist/js/frontend.js',
},
// Admin JS
{
entryPoints: ['assets/src/js/admin.js'],
bundle: true,
minify: isProduction,
sourcemap: !isProduction,
outfile: 'assets/dist/js/admin.js',
},
// Frontend CSS
{
entryPoints: ['assets/src/css/frontend.css'],
bundle: true,
minify: isProduction,
outfile: 'assets/dist/css/frontend.css',
},
// Admin CSS
{
entryPoints: ['assets/src/css/admin.css'],
bundle: true,
minify: isProduction,
outfile: 'assets/dist/css/admin.css',
},
];

await Promise.all(buildConfigs.map((config) => esbuild.build(config)));

console.log('✅ Plugin assets built!');

Plugin asset betöltés

<?php
class My_Plugin_Assets {

public static function init() {
add_action( 'wp_enqueue_scripts', [ __CLASS__, 'enqueue_frontend' ] );
add_action( 'admin_enqueue_scripts', [ __CLASS__, 'enqueue_admin' ] );
}

public static function enqueue_frontend() {
wp_enqueue_style(
'my-plugin-frontend',
plugins_url( 'assets/dist/css/frontend.css', __FILE__ ),
[],
self::get_version( 'assets/dist/css/frontend.css' )
);

wp_enqueue_script(
'my-plugin-frontend',
plugins_url( 'assets/dist/js/frontend.js', __FILE__ ),
[],
self::get_version( 'assets/dist/js/frontend.js' ),
true
);
}

public static function enqueue_admin( $hook ) {
// Csak a plugin oldalain
if ( strpos( $hook, 'my-plugin' ) === false ) {
return;
}

wp_enqueue_style(
'my-plugin-admin',
plugins_url( 'assets/dist/css/admin.css', __FILE__ ),
[],
self::get_version( 'assets/dist/css/admin.css' )
);

wp_enqueue_script(
'my-plugin-admin',
plugins_url( 'assets/dist/js/admin.js', __FILE__ ),
[],
self::get_version( 'assets/dist/js/admin.js' ),
true
);
}

private static function get_version( $file ) {
$path = plugin_dir_path( __FILE__ ) . $file;
return file_exists( $path ) ? filemtime( $path ) : '1.0.0';
}
}

My_Plugin_Assets::init();

Környezeti változók

Define plugin

await esbuild.build({
entryPoints: ['src/js/main.js'],
bundle: true,
outfile: 'dist/js/main.js',
define: {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
'API_URL': JSON.stringify('https://api.example.com'),
},
});

Használat JavaScript-ben

if (process.env.NODE_ENV === 'development') {
console.log('Development mode');
}

fetch(API_URL + '/endpoint');

Development server

esbuild beépített dev server-rel rendelkezik:

import * as esbuild from 'esbuild';

const ctx = await esbuild.context({
entryPoints: ['src/js/main.js'],
bundle: true,
outdir: 'dist',
});

const { host, port } = await ctx.serve({
servedir: 'dist',
port: 8000,
});

console.log(`Server running at http://${host}:${port}`);

Teljesítmény összehasonlítás

Bundler1000 modulos projekt build ideje
esbuild~0.3s
Vite (esbuild)~0.5s
Rollup~4s
Webpack~15s

Források