Machy8\Webloader – PHP bundler pro JS a CSS
- Machy8
- Člen | 59
Ahoj,
protože jsem v průběhu posledních 2 měsíců často řešil načítání
CSS a JS souborů a pluginy, které jsou na componette mi na to v některých
případech nestačily, rozhodl jsem se vytvořit vlastní řešení.
Odkazy
Instalace
composer require machy8/webloader
Co umí
- Vytvářet kolekce souborů
- Sloučit více kolekcí pomocí kontejneru a vygenerovat je najednou
- Generování pouze těch kolekcí, které jsou na dané stránce nebo všech najednou
- Zapnout nebo vypnout cache (při vypnutém cache bude opakovaně přegenerovávat soubory při načtení stránky)
- Konfigurovat kolekce i kontejnery v neon souborech a toto nastavení popřípadě modifikovat klidně i v šabloně
- Pro každou kolekci vygenerovat link s atributem preload a prefetch
- Vytvořit cestu k vygenerovanému souboru nebo ho načíst do stránky (například pro critical css)
- Generovat elementy link, script, style s libovolnými atributy
- Registrovat filtry a placeholdery pro cesty k souborům
- Spouštět filtry jednou po načtení kolekce souborů nebo pro každý soubor zvlášť
- Nastavit delimiter pro placeholdery
- + je v repozitáři již vytvořený filtr pro url v CSS souborech a bridge pro Tracy
Ukázka
Neon
extensions:
webloader: WebLoader\Bridges\Nette\WebLoaderExtension
webloader:
outputDir: %wwwDir%/webtemp
documentRoot: %wwwDir%
filesCollections:
critical:
cssFiles:
- path/to/file.css
cssLoadContent: TRUE
homepage:
jsFiles:
- path/to/file.js
jsFilters:
- minify
Presenter
/**
* @var Engine
*/
private $webLoader;
public function __construct(\WebLoader\Engine $engine)
{
$this->webLoader = $engine;
}
public function beforeRender()
{
$this->webLoader->addJsFilter('minify', function(string $code) {
// Minify
return $code;
});
$this->template->setParameters([
'webloaderFilesCollectionRender' => $this->webLoader->getFilesCollectionRender()
]);
}
Šablona
{$webloaderFilesCollectionRender->css('critical')|noescape}
{$webloaderFilesCollectionRender->js('homepage')|noescape}
Output
<style type="text/css">
/* critical.css */
</style>
<script async type="text/javascript" src="/webtemp/homepage.js?v=1508851219"></script>
TODO?
- Přidat možnost slučovat kolekce v kontejneru do jednoho souboru?
- Povolit přidání filtrů i přez neon soubor (pouze pro Nette)?
- Přidat další možnost generování link elementu s rel=„subresource“?
Budu rád za jakoukoliv připomínku, nápad či hejt :).
- Machy8
- Člen | 59
@pitr82
- Je to použito například zde www.lekarna.cz a www.mojalekaren.sk + to chci použít na dalších webech.
- Soubory jsou minifikovány na základě zvoleného minifikátoru (naprosto libovolné). WebLoader soubory pouze načítá z různých míst a spojuje dohromady. Filtry pak aplikuje podle nastavení (pro celou kolekci nebo pro každý soubor zvlášť).
- Pospojované kolekce, vygenerované html soubory a minifikované soubory, přez níže uvedené filtry, lze nalézt ve složce tests.
- Filtry:
- Hanz25
- Člen | 38
Pěkné! Něco takového jsem už chvíli hledal, vypadá to dobře.
Jak se dá rozchodit linkování v případě, že používám XAMPP a tedy mám root aplikace přístupný z url
http://localhost/<jmenoapp>/www
To se mi ještě nepodařilo zjistit. Pořád tam přidává na začátek lomítko a odkazuje to od rootu localhostu. Pokud změním parametry outputDir nebo documentRoot (mám nastavené stejně jak je výše), tak to zas řve, že daná cesta neexistuje.
Díky
- Machy8
- Člen | 59
@Hanz25 děkuju za připomínku! Tato možnost zde zatím není, protože jsem ji doposud nevyužil. Všechny soubory mám většinou postahované u sebe. Vytvořil jsem na to issue a zvážím, jestli tuto funkcionalitu přidat.
Prozatím je potřeba soubory načítat přes root nebo vytvořit patch na soubor Compiler.php, kde bude zakomentovaná / odstraněná podmínka na kontrolu existence souboru (r. 469–471).
Edit
Když nad tím tak přemýšlím, tak v podstatě nepotřebuješ načítat
soubory z jiné url (tato funkcionalita ale chybí, takže ji doplním).
Jediné co potřebuješ, je do webloaderu předat outputDir a documentRoot,
stejně jako je v ukázce. Webloader nemá funkcionalitu (a nevím, jestli ji
mám přidávat) na linkování souboru z něco://**.
webloader:
documentRoot: %wwwDir%
outputDir: %wwwDir%/webtemp
Editoval Machy8 (30. 10. 2017 20:05)
- Hanz25
- Člen | 38
@Machy8 zatím mám nad tím replace a přepisuju to
ale teoreticky by tam mělo jít dát něco jako basePath ne? To nastavení
co uvádíš tam přesně mám, ale v css mi to nalinkuje
/webtemp/collection.css
místo
<jmenoapp>/www/webtemp/collection.css
pak by to znamenalo,
že pokud bych chtěl přesunout web do nějaké podsložky, musel bych přesně
nastavit i cestu mimo aplikační adresář. Jestli to dobře chápu, tak to
asi bug je.
byl by super nějaký full config example. Chtěl bych co nejvíce věcí nastavit z configu a v presenteru upravovat jen to nejnutnější a pro ty možnosti a jejich názvy musím jít až do WebLoaderExtension
Jak se to chová k url v css souborech? Vypadá to, že je nemodifikuje, takže pokud chci zachovat správné linkování tak musím držet ty generované soubory na stejné úrovni jako psané css? A pokud se rozhodnu, že mi vygenerovaný soubor v podsložce nevyhovuje a rozhodnu si to vypsat do stránky, musím zároveň zaktualizovat i linky v css souborech?
koukal jsem na ty placeholdery, ale ty, co jsem pochopil a zkoušel, fungují jen v definicích cest k souborům a ne uvnitř samotného css souboru
díky za odpověď
- Machy8
- Člen | 59
@Hanz25 nějak nechápu o co přesně se snažíš
- Base path je generována následovně.
- Mám li document root například
/var/www/html/www
a k tomu pak webtemp adresář s cestou/var/www/html/www/webtemp
, tak výsledná basePath je/webtemp
a vygenerovaný element bude vypadat následovně
<link rel="stylesheet" href="/webtemp/collection.css">
- Pokud máš v Nette root /www, pak nenalinkuješ nic, co je za rootem a jedině by to šlo „přímo“ přez url, což WebLoader neumí
- Mohl bych tě poprosit o příklad kódu, o který ti jde?
- pitr82
- Člen | 121
Machy8 napsal(a):
Ahoj, @pitr82
Zatím jsem nad tím nepřemýšlel. Ty soubory se do konfiguráku přidají jen jednou. Je nějaký speciální důvod na to používat finder? O kolika souborech se bavíme?
Jan mě to napadlo, jako ulehčení, včetně exclude, když nechci načítat podadresáře.
Dá se nějak donutit webloader , aby kontroloval soubory na změnu?
Při každé změně css musím vymazat webtemp. Pro vývoj by tato možnost
nebyla vůbec špatná.
- GEpic
- Člen | 566
pitr82 napsal(a):
Ahoj, @Machy8
Planuješ podporu pro NEON config s využitím Nette/utils/finder, abych nemusel vypisovat všechny soubory ručně ?
To nechceš, co když máš natažený bootstrap např přes bower a
čerstvě zkompilovaný? V dist
se ti vytvoří jak
.css
, tak .min.css
, tak theme.css
i
theme.min.css
a to prostě nechceš načítat vše. To nemluvím
o dalších knihovnách. Toto je lepší mít přímo definované.
Editoval GEpic (6. 11. 2017 9:37)
- Hanz25
- Člen | 38
Machy8 napsal(a):
- Mohl bych tě poprosit o příklad kódu, o který ti jde?
teď to mám v layoutu implementované takto
{$webLoader->css('base')|noescape|replace:"/webloader":$basePath."/webloader"}
jde mi o to, abych do té vygenerované adresy (už přímo v kódu) přidal $basePath
protože když vyvíjím na localhostu a celý projekt mi funguje v nějaké podsložce, přistupuji k němu přes url (localhost/<jmenoprojektu>/). Takže když všechny vygenerované linky začínají vnějším rootem „/“ tak mi to nesedí.
- Hanz25
- Člen | 38
A ještě by mě zajímalo, jak by se mělo pracovat s tou keší na lokálu/produkci.
Zatím tedy mám v lokálním configu
webloader:
disableCache: TRUE
s tím, že mi to asi přegeneruje vše vždy že?
A když nahraju novou verzi na produkci? Se smazáním nette keše v temp/ to asi nic nemá že? Takže musím po nahrání smazat i ty vygenerované soubory, abych vynutil jejich přegenerování?
Editoval Hanz25 (23. 1. 2018 12:59)
- Hanz25
- Člen | 38
Nevím jestli s těmi cestami pracuji správně, ale stejně se mi tam zdá něco divného. Jakoby to občas bralo z rootu a občas z absolutní pozice ve které právě je… Načrtnu situaci a co očekávám, třeba to fakt špatně používám…
lokální adresa: http://localhost/mujprojekt/www
produkční adresa: http://mujprojekt.cz/
nastavení neonu:
webloader:
documentRoot: %wwwDir%
outputDir: %wwwDir%/webloader
$webloader->css()
vygeneruje
<link type="text/css" rel="stylesheet" href="/webloader/base.css?v=1516261067">
ovšem na localhostu potřebuji
<link type="text/css" rel="stylesheet" href="/mujprojekt/www/webloader/base.css?v=1516261067">
($basePath v nette to umí poznat)
Když spustím testy
WebLoader\Exception: Given output dir "C:\xampp\htdocs\mujprojekt\tests\cases\presenter\MujModule\presenters/webloader" doesn't exists or is not a directory.
Díky za odpověď :)
Editoval Hanz25 (23. 1. 2018 16:53)
- Machy8
- Člen | 59
@Hanz25 To máš nějaký složitý :D. WebLoader ti to generuje špatně, protože v něm máš nastavený stejný root, leč cesta je jiná.
WebLoader vždy vychází z rootu.
Tudíž když je root /var/www/html/www
a output má jít do složky /var/www/html/www/webtemp
tak se odebere /var/www/html/www a vygenerovaná cesta bude například
/webtemp/file.css.
Zkusil bych třeba na localhostu v presenteru pozměnit documentRoot nebo si nakonfigurovat jiná nastavení v config.neon a config.local.neon.
Editoval Machy8 (25. 1. 2018 19:58)
- Machy8
- Člen | 59
@pitr82
- Umí. Pomocí
$webLoader->getCompiler()
získáš kompiler kolekcí, který obsahuje metody jakocompileAllFilesCollections
(vygeneruje vše, vhodné pro read only deployment),compileCssFilesCollection
,compileJsFilesCollection
,compileFilesCollectionByType
. - Díky za poznámku, doplním to do dokumentace
- pitr82
- Člen | 121
@Machy8
To jsme si úplně neporozuměli, manuální kompilace je super :-), určitě
stojí za zmínku do dokumentace.
Spíš jsem myslel, když renderuješ CollectionContainer, tak se mi zvlášť
vypisují jednotlivé kontejnery.
Obvykle mám Homepage a HomepageToMinify – a chtěl jsem, aby tohle
vygenerovalo jeden soubor.
Machy8 napsal(a):
@pitr82
- Umí. Pomocí
$webLoader->getCompiler()
získáš kompiler kolekcí, který obsahuje metody jakocompileAllFilesCollections
(vygeneruje vše, vhodné pro read only deployment),compileCssFilesCollection
,compileJsFilesCollection
,compileFilesCollectionByType
.- Díky za poznámku, doplním to do dokumentace
- pitr82
- Člen | 121
Ahoj @Machy8
mam dotaz k
<?php
$this->webLoader->addJsFilter('minify', function(string $code) {
// Minify
return $code;
});
?>
pokud pouziju parametr forEachfile = true , tak mi projede soubory po jednom
= OK.
Pokud ale pouziju false, načte mi kompletně všechny soubory z zpracuje, pak
se ale ještě zavola se zpracovaným obsahem tolikrát, kolik jsem zpracovával
souborů.
A ještě jedna věc. když je mezi minimalizovanými soubory netteForms.min.js tak rozšíření tedivm/jshrink mi zkončí ve smyčce.
- Danny
- Člen | 146
@Hanz25
Ahoj, můžu se zeptat jak si ten problém s cestami vyřešil? Řeším stejný problém, mám projekt zde /var/www/html/projects/nazev-projektu/
mám nastavené cesty
webloader:
outputDir: %wwwDir%/webtemp
documentRoot: %wwwDir%
a webloader mi generuje cestu
<link type="text/css" rel="stylesheet" href="/webtemp/core.css?v=1563905846">
A já bych naopak potřeboval
<link type="text/css" rel="stylesheet" href="/projects/vehicles/www/webtemp/core.css?v=1563905846">
Přijde mi že webloader používá tu cestu správně ale jenom pro generování css/js do webtemp ale to cestu k tomu souboru pak vygeneruje špatně.
Nebo @Machy8
Díky za info.
Editoval Danny (24. 7. 2019 19:47)
- mrfazolka
- Člen | 24
Žije ještě tenhle projekt @Machy8 ?:)
Je možné nastavit outputDir i pro danou kolekci? Nebo něco jako podsložku v outputDir, nastavitelnou pro danou css/js kolekci bundelu?
Příklad:
webloader:
outputDir: %wwwDir%/webtemp
documentRoot: %wwwDir%
disableCache: TRUE
filesCollections:
testTinyMceBundle:
jsFiles:
- https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.7.1/tinymce.min.js
- https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.7.1/themes/silver/theme.min.js
- https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.7.1/icons/default/icons.min.js
jsFilters:
#- minify
jsOutputDir:
- tinymce
cssFiles:
- https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.7.1/skins/ui/oxide/skin.min.css
- https://cdnjs.cloudflare.com/ajax/libs/tinymce/5.7.1/skins/ui/oxide/content.inline.min.css
cssOutputDir:
- tinymce/skins/ui/oxide
Jde mi o použití něčeho jako jsOutputDir a cssOutputDir, které jsem si v příkladu domyslel, pro demonstraci možnosti nastavení cest generovaných souborů jednotlivých js/css kolekcí.