Webpack, Webpack Encore, Turbo — das Symfony-Ökosystem hat über die Jahre verschiedene Build-Tools empfohlen. Für meine Projekte nutze ich keines davon. Stattdessen: drei schlanke Node.js-Skripte, die genau das tun, was gebraucht wird.
Warum kein Webpack?
Webpack ist ein mächtiges Tool — aber für Projekte, die primär SCSS kompilieren und ein paar Vendor-Dateien kopieren müssen, ist es Overkill. Die Konfiguration ist komplex, die Build-Zeiten lang, und jedes Update birgt das Risiko von Breaking Changes in der Plugin-Kette.
Mein Ansatz: Drei kleine Scripts, jedes unter 50 Zeilen, jedes für eine Aufgabe.
Schritt 1: SCSS kompilieren
import * as sass from 'sass';
import fs from 'fs';
import path from 'path';
const cssDir = path.join(process.cwd(), 'public/assets/css');
const cssOut = path.join(cssDir, 'all.css');
const scssFile = path.join(
process.cwd(),
'templates/assets/scss/all.scss'
);
if (!fs.existsSync(cssDir)) {
fs.mkdirSync(cssDir, { recursive: true });
}
const result = sass.compile(scssFile, {
style: 'compressed',
loadPaths: [
path.join(process.cwd(), 'node_modules/bootstrap/scss')
]
});
fs.writeFileSync(cssOut, result.css, 'utf8');
Das kompiliert die komplette SCSS-Kette — eigene Variablen, Bootstrap 5 mit Custom-Overrides, Komponenten, Seiten — in eine einzige, minifizierte CSS-Datei.
Schritt 2: Assets kopieren
import fse from 'fs-extra';
const copies = [
{ from: 'templates/assets/img', to: 'public/assets/img' },
{ from: 'templates/assets/fonts', to: 'public/assets/fonts' },
{
from: 'node_modules/bootstrap/dist/js/bootstrap.min.js',
to: 'public/assets/js/vendor/bootstrap.min.js'
},
];
for (const { from, to } of copies) {
await fse.copy(from, to, { overwrite: true });
}
Einfaches Kopieren — Bilder, Fonts, Vendor-JavaScript. Keine Transformationen, keine Loader, keine Plugins.
Schritt 3: Komprimierung
import { readFile, writeFile } from 'fs/promises';
import { gzipSync, brotliCompressSync } from 'zlib';
import { glob } from 'glob';
const files = await glob('public/assets/**/*.{css,js}');
for (const file of files) {
const content = await readFile(file);
// Gzip
const gzipped = gzipSync(content, { level: 9 });
await writeFile(file + '.gz', gzipped);
// Brotli
const brotli = brotliCompressSync(content);
await writeFile(file + '.br', brotli);
}
nginx serviert die pre-komprimierten Dateien direkt mit brotli_static on und gzip_static on — ohne zur Laufzeit komprimieren zu müssen.
Bootstrap 5 mit Custom Variables
Der Kern des SCSS-Setups: Eigene Variablen vor dem Bootstrap-Import definieren, damit Bootstrap die Overrides übernimmt:
// _variables.scss — VOR Bootstrap importieren
$primary: #1a365d;
$accent: #3182ce;
$font-family-sans-serif: 'Inter', -apple-system, sans-serif;
$border-radius: 0.5rem;
// all.scss
@import "fonts";
@import "variables";
@import "../../../node_modules/bootstrap/scss/bootstrap";
@import "_components/navbar";
@import "_components/hero";
@import "_pages/home";
@import "_pages/blog";
Das Ergebnis: Eine einzige CSS-Datei mit Bootstrap-Basis und projektspezifischen Styles, komprimiert auf unter 50 KB (Brotli).
Self-Hosted Fonts
Google Fonts extern zu laden ist ein DSGVO-Problem — jeder Seitenaufruf sendet die IP-Adresse des Besuchers an Google. Die Lösung: Fonts herunterladen und lokal servieren.
// _fonts.scss
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400 800;
font-display: swap;
src: url('../fonts/inter-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153;
}
font-weight: 400 800 nutzt die Variable-Font-Technologie — eine einzige Datei für alle Gewichtungen, statt fünf separate Dateien.
Build-Befehl
{
"scripts": {
"build": "node build-scss.js && node copy-assets.js && node compress.js"
}
}
Build-Zeit: unter 3 Sekunden. Zum Vergleich: Webpack Encore braucht für ein vergleichbares Setup 15-20 Sekunden.
Wann doch Vite?
Für Projekte mit reaktiven JavaScript-Komponenten (Svelte, Vue) nutze ich Vite. Die SCSS-Kompilierung bleibt trotzdem in den Node-Scripts — Vite übernimmt nur den TypeScript/Svelte-Teil. Diese Trennung hält die Komplexität gering und jedes Tool macht genau eine Sache.
Fazit
Nicht jedes Projekt braucht einen komplexen Bundler. Für Symfony-Seiten mit Bootstrap und SCSS reichen drei Node-Scripts völlig aus. Die Build-Pipeline ist transparent, schnell und hat keine versteckten Konfigurationsschichten. Wenn etwas nicht funktioniert, öffnen Sie ein 40-Zeilen-Script statt eines 200-Zeilen-Webpack-Configs.
Kommentare
Kommentare werden von Remark42 bereitgestellt. Beim Laden werden Daten an unseren Kommentar-Server übertragen.