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

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Filip Procházka
Moderator | 4668
+
0
-

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í s TemplateConfiguratorem
  • TemplateConfigurator př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');
  • TemplateConfigurator mi 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 | 1245
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

Mám dilema, udělat aliasy {css} a {js}?

//edit: tak jsem to tam nakonec dal :)

Editoval HosipLan (13. 1. 2012 14:24)