Řešení všech Javascriptů, CSSek, obrázků a dalších výmyslů

- Filip Procházka
- Moderator | 4668
Odkud co
Prvně si stáhneme a inicializujeme Kdyby sandbox ;)
$ git clone git://github.com/Kdyby/sandbox.git
$ ./prepare # nastaví app/log a app/temp zapisovatelné a spustí script vendor/vendors
Nyní by vám po přechodu do složky www/ měl naběhnout nový
sandbox. Pokud nenaběhl, můžete mi vynadat a nebo lépe reportovat
chybu ;)
Jak to teďka vypadá
V @layout.latte se pár věcí změnilo, má novou hlavičku
<!DOCTYPE html>
<html>
{head title => "Nette Application Skeleton"}
<meta name="description" content="Nette Framework web application skeleton">
{stylesheet 'css/screen.css', media => "screen,projection,tv"}
{stylesheet 'css/print.css', media => "print"}
{javascript 'http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js',
'js/netteForms.js'}
<link rel="shortcut icon" href="{$basePath}/favicon.ico" type="image/x-icon">
{block head}{/block}
{/head}
Ničeho se nebojte, na začátek cest v makrech stylesheet a javascript
budou automaticky doplněny proměnné $basePath, stačí
neuvádět lomítko na začátku.
Makro stylesheet
Je určené pouze na csska, když neuvedete absolutní cestu ke stylu, bude
se brát %wwwDir%. Protože makro předává data dále do mnou
ohnutého Asseticu,
obsahuje i podporu balíčků, více zde.
Pokud ve vlastním balíčku budete mít nějaké statické soubory,
/MyPackage
/Resources
public/
css/
foo.css
js/
bar.js
je možné na ně odkazovat takto
{stylesheet '@MyPackage/public/css/foo.css'}
{javascript '@MyPackage/public/js/bar.js'}
Kouzlo je v tom, že makro se zkompiluje tak, aby se nezávisle na jakýchkoliv podmínkách přidaly soubory do manageru, který se jmenuje FormulaeManager. Tomuto manageru budou soubory předem připraveny a analyzovány, takže první vykreslení stránky může trvat krapet déle. Potom se vždy, když se začne vykreslovat šablona, soubory do něj připojí.
Má to jedno omezení, co nejméně v těchto makrech používejte proměnné. Proměnné se totiž zpracovávají runtime a já potřebuji už při compiletime vědět přesně, jaké soubory budou použity.
Makro podporuje i filtry (less, sass, …), ale ty jsem zatím nepotřeboval, takže ještě nejsou implementované, Assetic pro ně má ale podporu a bude možné psát vlastní filtry.
Makro javascript
Funguje úplně stejně, jenom má méně parametrů a je jenom pro javascripty
Makro head
Tady jsem se krapet nechal unést ;) Vytvořil jsem novou komponentu (promiň Honzo) HeaderControl
Komponenta se registruje do presenteru
protected function createComponentHead()
{
return new Kdyby\Components\Header\HeaderControl(
$this->context->application,
$this->context->assetic_formulaeManager,
$this->context->httpRequest
);
}
Její api je velice jednoduché. Určitě bude rozšiřováno, ale měnit už
snad nic nebudu. Je to jenom obálka na tagy a vytahuje z
FormulaeManageru cesty k assetům.
Mezi makry {head} a {/head} je možné používat
normálně Latte, ale netestoval jsem úplně všechno, takže na něčem to
může padat. Prostě to nehackujte ;)
Komponenta si při vykreslení sáhne na FormulaeManager, zeptá
se ho na cesty, které byly nasbírány z maker {stylesheet} a
{javascript} a ty pak vykreslí do hlavičky spolu
s vašimi tagy.
Jak je to s těmi komponentami?
Stačí kdekoliv v její šabloně napsat makro {stylesheet},
nebo {javascript} a Kdyby se postará, aby se soubory objevily tam
kde mají, v hlavičce ;)
Má to jednu podmínku, musí se šabloně předat do proměnné
$_fm instance FormulaeManager z DI Containeru a taky
musí mít registrována moje makra. Ale to s Kdyby není vůbec žádný
problém, protože samo při kompilování Containeru najde komponenty a
připojí k nim TemplateConfigurator
Takže si ty komponenty shrneme
- Podědím
Kdyby\Application\UI\Control, který kamarádí sTemplateConfiguratorem TemplateConfiguratorpředám, nebo dám komponentě v DIC Containeru tag „component“ a Kdyby jí to nastaví samo. Zde bych poprosil zatahat za nitky, kdo můžete zde.
$container->addDefinition('cms_rbacForm')
->setClass('Kdyby\Components\AccessControl\RbacForm', array('@doctrine'))
->addTag('component');
TemplateConfiguratormi nastaví makra a proměnnou_fm
Nevýhody
Není možné v rozumné době zjistit, jaké komponenty budou načteny do
stránky a jaké se vykreslí, prostě to nejde. Vykreslení šablony se tedy
funkcemi ob_start() a ob_get_clean() násilně
zdržuje, dokud nebude celá k dispozici do momentu, kdy už další komponenty
nepřibudou a pak teprve vykreslí hlavičku a za ní tělo šablony. Mírně se
tím oddálí první znak odeslaný uživateli a malinko to zvedne využití
paměti. Vím, že sám jsem to kritizoval (zdravím Venne :P), ale jinak to
asi nejde.
Pokud na #nettebc vymyslíme něco lepšího, určitě to vylepším ;)
PS: Psal jsem to tak trochu narychlo, kdyby něco nebylo jasné, rád doplním
Editoval HosipLan (10. 1. 2012 8:54)

- Felix
- Nette Core | 1271
Hezke reseni urcite vyzkousim. Jak si psal, hodnekrat jsem to resil. Tedka
naposled jsem to vyresil tak, ze mam komponentu HeadLoader, ktera
ze seznamu komponent zkousi volat fci napriklad usedCss resp
usedJs, ktery vracej pole souboru :) neco jako
function usedCss() {
return array('%wwwDir%/css/theme.css', '%dataDir%/css/datepicker/example2.css');
}
PS: Slo by to teoreticky i pres anotace, ne?
/** @UsedCss */
public $usedCss = array('%wwwDir%/css/theme.css', '%dataDir%/css/datepicker/example2.css');
Jak je to s rychlosti? Kdyz uz to nette jednou nacte, tak by to melo bejt v pohode ne?
Editoval Felix (9. 1. 2012 18:23)

- Ani
- Člen | 226
Ahoj,
vypadá to pěkně. U sebe jsem si zavedl podobné makro javascript, je to obdoba capture, jen ho používám trochu jinak možná by se ti ta syntaxe líbila. Hlavní výhoda je v kombinaci s n variantou a tim pádem zvýrazňování syntaxe…
<script n:javascript>
alert('kokos');
</script>
případně i, ale to mám zatím rozdělané
přidá soubor
<script n:javascript="file" src="kokos.js"></script>
Editoval Ani (10. 1. 2012 15:48)

- Filip Procházka
- Moderator | 4668
To se mi líbí. N-makra jsem chtěl také přidávat, ale prioritou bylo, aby to fungovalo, hračičky se můžou dodělat kdykoliv :)

- Filip Procházka
- Moderator | 4668
Implementována podpora inline scriptů v e384d94e2ae, pro vyzkoušení nezapomenout aktualizovat sandbox
sandbox $ git pull origin
a vendory
sandbox $ vendor/vendors update

- Jan Jakeš
- Člen | 177
Vypadá to pěkně. Mám jeden dotaz – dá se nějak ovlivnit pořadí přidávání assets do hlavičky?
Sám jsem přemýšlel o nějakém komplexním řešení všech assets a zatím mám myšlenku, že by jakákoliv komponenta mohla mít assets a závislost na jiných komponentách. Jak assets tak závislosti bych asi rád nastavoval přes config, abych opravdu mohl přidat třeba pouze knihovnu JS tímto způsobem:
jquery:
assets: ['cesta-k-jquery']
myComponent:
assets: ['moje-assets'] # anebo jejich nastavení v šabloně komponenty
dependencies: [jquery]
A jQuery by se samo načetlo před assets myComponent. Je to
jen nástin, podstata je, že bych se rád dostal k řešení, kdy kompletní
instalace komponenty (např. stažené z doplňků) bude vyžadovat jen
přidání adresáře s komponentou např. do libs, její
přidání do config.neon s nastavením, na kterých knihovnách
závisí.
Editoval Juan (12. 1. 2012 11:16)

- Filip Procházka
- Moderator | 4668
Určitě by to šlo, ale nevidím důvod, proč dělit cesty k js knihovnám, které prakticky patří k view, někam do configu.

- Jan Jakeš
- Člen | 177
Mně šlo hlavně o to, jak řešit závislosti komponent a tedy pořadí načítání jejich JS, případně CSS. O ten zápis v konfigu nejde, to byla vlastně jen „zkratka“ pro to, abych nemusel pro čistě JS framework hned vytvářet komponentu se šablonou a přesto na něj mohl nějak vyjádřit závislost.

- 22
- Člen | 1478
já bych se rád někdy dožil toho, aby stačilo komponentu vzít a akorát nahrát do libs.. nebo kam vidí robotLoader. Zásadní zádrhel je v tom, že v šabloně komponenty nemůžu definovat např. {block head}<script>..{/block}, i když je jasný, že komponenta bez Presenteru je k ničemu a Presenter bez @layout.latte, kde je ten block definovanej, jak by smet.

- Filip Procházka
- Moderator | 4668
Však to už funguje (tedy, až znovu opravím Kdyby na nejnovější Nette :)
Stačí šabloně komponenty přidat makra a FormulaeManager,
o což se ti postará kdyby, když budeš dědit
Kdyby\Application\UI\Control a dáš tovírničce na komponentu
v DIC tag component.
<script n:javascript>
$(function () { });
</script>
A bude fungovat ;)

- Filip Procházka
- Moderator | 4668
Mám dilema, udělat aliasy {css} a {js}?
//edit: tak jsem to tam nakonec dal :)
Editoval HosipLan (13. 1. 2012 14:24)