Minify CSS, JavaScript ir HTML: geriausia praktika

Kodėl apskritai turėtume minifikuoti kodą?

Kiekvieną kartą, kai vartotojas atidaro jūsų svetainę, naršyklė turi parsisiųsti visus reikalingus failus – HTML, CSS, JavaScript. Ir čia prasideda tikrasis iššūkis: kuo didesni šie failai, tuo ilgiau trunka jų parsisiuntimas. O kai kalbame apie mobiliuosius įrenginius su lėtesniais ryšiais, kiekvienas kilobaitas tampa kritiniu.

Minifikacija – tai procesas, kurio metu iš kodo pašalinami visi nereikalingi simboliai: tarpai, naujos eilutės, komentarai, kartais net sutrumpinami kintamųjų pavadinimai. Rezultatas? Failai tampa gerokai mažesni, o funkcionalumas išlieka tas pats. Tarkime, jūsų 150 KB JavaScript failas po minifikacijos gali sumažėti iki 50-60 KB. Tai ne tik teorija – realūs projektai rodo, kad minifikacija gali sumažinti failo dydį 40-60%.

Bet čia ne tik apie dydį. Google ir kiti paieškos varikliai tiesiogiai vertina puslapio įkėlimo greitį. Lėtas puslapis reiškia blogesnę poziciją paieškos rezultatuose. Be to, vartotojai tiesiog palieka svetaines, kurios kraunasi ilgiau nei 3 sekundes. Tai jau ne optimizavimo prabanga – tai būtinybė.

CSS minifikacija: daugiau nei tik tarpų šalinimas

Kai žmonės galvoja apie CSS minifikaciją, dažniausiai įsivaizduoja paprastą tarpų pašalinimą. Realybė šiek tiek sudėtingesnė ir įdomesnė. Modernus CSS minifikatorius daro daug daugiau.

Pirma, jie optimizuoja spalvų kodus. Pavyzdžiui, #ffffff tampa #fff, o rgb(255,255,255)#fff. Antra, šalinami pertekliniai nuliniai dydžiai – margin: 0px 0px 0px 0px tampa tiesiog margin:0. Trečia, sujungiami identiški selektoriai ir optimizuojamos taisyklės.

Praktiškai dirbant su CSS minifikacija, rekomenduoju naudoti cssnano arba clean-css. Abu įrankiai puikiai integruojasi su build sistemomis kaip Webpack ar Gulp. Štai paprastas pavyzdys su clean-css:


const CleanCSS = require('clean-css');
const input = 'a { font-weight: bold; }';
const output = new CleanCSS({}).minify(input);
console.log(output.styles);

Svarbus niuansas – visada laikykite originalius, neminifikuotus failus. Minifikuoti turėtumėte tik production versijoje. Development aplinkoje dirbkite su normaliais failais, kitaip debuginimas taps košmaru. Ir dar vienas patarimas: jei naudojate CSS preprocesorus kaip SASS ar LESS, minifikaciją atlikite po kompiliavimo, ne prieš.

JavaScript minifikacija ir jos pavojai

JavaScript minifikacija – tai jau kitas lygis. Čia procesas daug sudėtingesnis, nes JavaScript yra programavimo kalba su logika, kintamaisiais, funkcijomis. Blogai minifikuotas JavaScript gali tiesiog nebeveikti.

Populiariausi įrankiai šiai užduočiai – Terser (UglifyJS įpėdinis) ir esbuild. Terser yra patikimas ir plačiai naudojamas, o esbuild pasižymi neįtikėtinu greičiu. Jei turite didelį projektą su šimtais JavaScript failų, esbuild gali sutaupyti daug laiko build procese.

Štai ką daro geras JavaScript minifikatorius:

  • Pašalina komentarus ir nereikalingus tarpus
  • Sutrumpina kintamųjų ir funkcijų pavadinimus
  • Optimizuoja loginius išsireiškimus
  • Pašalina nepasiekiamą kodą (dead code elimination)
  • Sujungia deklaracijas kur įmanoma

Tačiau būkite atsargūs su labai agresyvia minifikacija. Kartais per daug optimizuotas kodas gali sukelti problemų su trečiųjų šalių bibliotekomis arba specifinėmis naršyklių versijomis. Rekomenduoju pradėti nuo bazinės minifikacijos ir palaipsniui didinti optimizavimo lygį, testuojant kiekvieną pakeitimą.

Dar vienas svarbus aspektas – source maps. Minifikuotas kodas yra visiškai neįskaitomas, todėl debuginimas tampa neįmanomas. Source maps leidžia naršyklei „susieti” minifikuotą kodą su originalu. Visada generuokite source maps production versijoms, bet neįkelkite jų į serverį – laikykite lokaliai debuginimui.

HTML minifikacija: ar tikrai verta?

HTML minifikacija yra kontraversiškiausia tema. Kai kurie developeriai teigia, kad tai bereikalinga, nes HTML failai paprastai nėra dideli. Kiti prisiekia, kad kiekvienas baitas svarbus. Tiesa, kaip dažnai, yra kažkur per vidurį.

Jei turite paprastą landing page su 20 KB HTML, minifikacija sutaupys gal 3-4 KB. Ne kažkas. Bet jei kuriate single-page aplikaciją su dideliu pirminiu HTML payload, arba turite daug inline JavaScript ir CSS, minifikacija gali būti naudinga.

HTML minifikacija pašalina:

  • Tarpus tarp tagų
  • Komentarus
  • Nebūtinus atributų kabutes
  • Tuščius atributus
  • Perteklinius DOCTYPE ir meta tagus

Naudokite html-minifier arba html-minifier-terser. Bet būkite atsargūs su nustatymais. Pernelyg agresyvi HTML minifikacija gali sugadinti formatavimą, ypač jei turite <pre> tagus arba specifinį whitespace elgesį. Štai saugūs nustatymai:


{
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true
}

Asmeniškai HTML minifikaciją naudoju tik didesnėse aplikacijose. Mažiems projektams tai dažnai būna overkill, ypač jei jau naudojate gzip ar brotli kompresiją serveryje.

Automatizavimas: integruojame minifikaciją į workflow

Rankinė minifikacija – tai kelias į beprotybę. Kiekvienas normalus projektas turi turėti automatizuotą build procesą, kuris pasirūpina minifikacija už jus. Ir čia turime keletą populiarių variantų.

Webpack – jei jau naudojate Webpack, minifikacija yra beveik triviali. TerserPlugin JavaScript minifikacijai ateina iš dėžės, o CSS galite minifikuoti su css-minimizer-webpack-plugin:


const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin(),
new CssMinimizerPlugin(),
],
},
};

Gulp vis dar populiarus, nors ir ne toks madingas kaip anksčiau. Gulp privalumas – paprastumas ir lankstumas. Galite sukurti task’ą, kuris minifikuoja visus failus vienu metu:


const gulp = require('gulp');
const terser = require('gulp-terser');
const cleanCSS = require('gulp-clean-css');
const htmlmin = require('gulp-htmlmin');

gulp.task('minify-js', () => {
return gulp.src('src/*.js')
.pipe(terser())
.pipe(gulp.dest('dist'));
});

gulp.task('minify-css', () => {
return gulp.src('src/*.css')
.pipe(cleanCSS())
.pipe(gulp.dest('dist'));
});

Vite – jei kuriate modernią aplikaciją, Vite yra fantastiška. Minifikacija veikia automatiškai production build metu, nereikia jokios papildomos konfigūracijos. Tiesiog vite build ir viskas padaryta.

Nepriklausomai nuo pasirinkto įrankio, svarbu turėti aiškų skirtumą tarp development ir production režimų. Development metu minifikacija tik trukdo – debuginti minifikuotą kodą yra košmaras. Naudokite environment variables arba skirtingus config failus.

Gzip, Brotli ir minifikacijos sąveika

Daug kas klausia: jei serveris jau naudoja gzip kompresiją, ar minifikacija vis dar reikalinga? Trumpas atsakymas – taip, absoliučiai. Ilgas atsakymas – tai dvi skirtingos optimizacijos, kurios puikiai papildo viena kitą.

Minifikacija veikia kodo lygmenyje – šalina nereikalingus simbolius, optimizuoja struktūrą. Gzip veikia failo lygmenyje – suspaudžia duomenis naudojant kompresijos algoritmus. Kai minifikuojate kodą prieš gzip, gaunate geriausius rezultatus, nes gzip efektyviau suspaudžia jau optimizuotą kodą.

Štai realūs skaičiai iš vieno mano projekto:

  • Originalus JavaScript failas: 245 KB
  • Po minifikacijos: 98 KB (60% sumažėjimas)
  • Po gzip: 28 KB (88% sumažėjimas nuo originalo)
  • Tik gzip be minifikacijos: 52 KB (78% sumažėjimas)

Matote skirtumą? Minifikacija + gzip duoda 28 KB, tik gzip – 52 KB. Tai beveik dvigubas skirtumas.

Brotli yra dar efektyvesnė alternatyva gzip. Moderniose naršyklėse Brotli gali pasiekti 15-20% geresnę kompresiją nei gzip. Bet čia yra niuansas – Brotli kompresija yra lėtesnė, todėl geriau failą suspausti iš anksto build metu, o ne dinamiškai serveryje.

Nginx konfigūracija su Brotli:


brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml;

Testavimas ir matavimas: ar tikrai greičiau?

Optimizacija be matavimo – tai šaudymas tamsoje. Kaip žinote, ar jūsų minifikacija tikrai padeda? Reikia matuoti.

Lighthouse – Chrome DevTools integruotas įrankis, kuris duoda išsamią ataskaitą apie puslapio našumą. Paleiskite Lighthouse prieš ir po minifikacijos, palyginkite rezultatus. Atkreipkite dėmesį į „Time to Interactive” ir „First Contentful Paint” metrikus.

WebPageTest – puikus įrankis išsamiam testavimui. Galite pasirinkti skirtingas lokacijas, įrenginius, ryšio greičius. Ypač naudinga testuoti su lėtais 3G ryšiais – ten minifikacijos nauda labiausiai matoma.

Chrome DevTools Network tab – paprasčiausias būdas pamatyti failo dydžius. Pasižiūrėkite „Size” ir „Transferred” stulpelius. „Size” rodo dekompressuotą dydį, „Transferred” – tai, kas realiai perduota per tinklą.

Praktinis patarimas: sukurkite performance budget. Pavyzdžiui, nustatykite, kad visas JavaScript negali viršyti 200 KB (minifikuotas ir gzipped). Jei viršijate limitą, build procesas turėtų failinti. Webpack turi bundle size limitus, kuriuos galite konfigūruoti:


performance: {
maxAssetSize: 200000,
maxEntrypointSize: 200000,
hints: 'error'
}

Dar vienas svarbus aspektas – testuokite ne tik desktop, bet ir mobile. Mobilieji įrenginiai dažnai turi lėtesnius procesorius, todėl JavaScript parsing ir execution užtrunka ilgiau. Minifikacija čia padeda dvigubai – mažesnis failas greičiau parsisiunčia IR greičiau parseinamas.

Kai minifikacija sukelia problemų

Ne viskas visada vyksta sklandžiai. Minifikacija gali sukelti problemų, ir geriau žinoti apie jas iš anksto.

Problemos su eval() ir Function() – jei jūsų kodas naudoja eval() arba new Function(), minifikatorius gali sutrumpinti kintamųjų pavadinimus, ir kodas nustos veikti. Sprendimas – arba vengti šių konstrukcijų, arba naudoti minifikatoriaus nustatymus, kurie išsaugo tam tikrus pavadinimus.

Konfliktai su trečiųjų šalių bibliotekomis – kartais minifikuotas kodas nesuderinamas su tam tikromis bibliotekomis. Ypač problemiškos senos jQuery plugins ar bibliotekos, kurios daro prielaidų apie kodo formatavimą. Sprendimas – minifikuokite savo kodą atskirai nuo vendor bibliotekų.

CSS specificity problemos – agresyvi CSS minifikacija gali pakeisti selektorių tvarką, o tai gali paveikti specificity. Jei pastebite, kad po minifikacijos stiliai atrodo kitaip, patikrinkite minifikatoriaus nustatymus ir išjunkite selektorių pertvarkymo optimizacijas.

Whitespace jautrumas HTML – kai kurie HTML elementai yra jautrūs whitespace, pavyzdžiui, <pre>, <code>, arba inline elementai su tarpais tarp jų. HTML minifikacija gali sugadinti formatavimą. Naudokite preserveLineBreaks arba conservativeCollapse nustatymus.

Asmeninis patarimas: visada testuokite minifikuotą versiją prieš deploy. Turėkite staging aplinką, kuri tiksliai atitinka production, ir ten patikrinkite, ar viskas veikia. Automatizuoti testai čia labai padeda – jei turite E2E testus, paleiskite juos prieš minifikuotą versiją.

Kas toliau: minifikacijos ateitis ir alternatyvos

Technologijos nestovi vietoje, ir minifikacijos pasaulis taip pat keičiasi. Nauji įrankiai ir metodai nuolat atsiranda, siūlydami geresnius rezultatus ar greitesnį veikimą.

esbuild jau minėjau, bet verta pabrėžti dar kartą – tai žaidimo keitėjas. Parašytas Go kalba, jis yra 10-100 kartų greitesnis už tradicinius JavaScript minifikatorius. Jei turite didelį projektą, esbuild gali sutaupyti minutes kiekviename build’e. Vienintelis trūkumas – mažiau konfigūracijos galimybių nei Terser.

SWC – kitas greitis demonas, parašytas Rust kalba. Naudojamas Next.js ir kitose moderniose framework’uose. Siūlo ne tik minifikaciją, bet ir transpilaciją, todėl gali pakeisti Babel + Terser kombinaciją.

HTTP/3 ir QUIC – nauji protokolai keičia tai, kaip galvojame apie optimizaciją. Su HTTP/2 ir HTTP/3, multiplexing reiškia, kad kelių mažų failų siuntimas nebėra toks brangus. Tai nereiškia, kad minifikacija tampa nereikalinga, bet galbūt nebereikia taip agresyviai jungti visų failų į vieną bundle.

Native CSS nesting ir kitos naujos funkcijos – naršyklės pradeda palaikyti funkcijas, kurias anksčiau turėdavome daryti su preprocessoriais. Tai gali pakeisti mūsų build procesus ateityje.

Bet nepaisant visų šių naujovių, pagrindiniai principai išlieka tie patys. Mažesni failai – greitesnis puslapis. Greitesnis puslapis – laimingesni vartotojai. Laimingesni vartotojai – sėkmingesnis projektas.

Minifikacija nėra sudėtinga, bet reikalauja dėmesio detalėms. Pasirinkite tinkamus įrankius, automatizuokite procesą, testuokite rezultatus. Ir nepamirškite – optimizacija yra iteratyvus procesas. Pradėkite nuo bazinių dalykų, matuokite rezultatus, ir palaipsniui tobulinkite. Nebūtinai iš karto pasieksite tobulą 100/100 Lighthouse score, bet kiekvienas pagerinimas skaičiuojasi. Ir jūsų vartotojai tai pajus, net jei patys nesupras kodėl puslapis tapo malonesnis naudoti.

Parašykite komentarą

El. pašto adresas nebus skelbiamas. Būtini laukeliai pažymėti *