Zend_Dojo-BuildLayers.xml 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- Reviewed: no -->
  3. <sect1 id="zend.dojo.build-layers">
  4. <title>Zend_Dojo build layer support</title>
  5. <sect2 id="zend.dojo.build-layers.introduction">
  6. <title>Introduction</title>
  7. <para>
  8. Dojo build layers provide a clean path from development to
  9. production when using Dojo for your UI layer. In development, you
  10. can have load-on-demand, rapid application prototyping; a build
  11. layer takes all Dojo dependencies and compiles them to a single
  12. file, optionally stripping whitespace and comments, and performing
  13. code heuristics to allow further minification of variable names.
  14. Additionally, it can do <acronym>CSS</acronym> minification.
  15. </para>
  16. <para>
  17. In order to create a build layer, you would traditionally create a
  18. JavaScript file that has <command>dojo.require</command> statements for
  19. each dependency, and optionally some additional code that might run
  20. when the script is loaded. As an example:
  21. </para>
  22. <programlisting language="javascript"><![CDATA[
  23. dojo.provide("custom.main");
  24. dojo.require("dijit.layout.TabContainer");
  25. dojo.require("dijit.layout.ContentPane");
  26. dojo.require("dijit.form.Form");
  27. dojo.require("dijit.form.Button");
  28. dojo.require("dijit.form.TextBox");
  29. ]]></programlisting>
  30. <para>
  31. This script is generally referred to as a "layer" script.
  32. </para>
  33. <para>
  34. Then, in your application's layout, you'd instruct Dojo to load this
  35. module:
  36. </para>
  37. <programlisting language="html"><![CDATA[
  38. <html>
  39. <head>
  40. <script type="text/javascript" src="/js/dojo/dojo.js"></script>
  41. <script type="text/javascript">
  42. dojo.registerModulePath("custom", "../custom/");
  43. dojo.require("custom.main");
  44. </script>
  45. ]]></programlisting>
  46. <para>
  47. If you use <classname>Zend_Dojo</classname> to do this, you'd do the
  48. following:
  49. </para>
  50. <programlisting language="php"><![CDATA[
  51. $view->dojo()->registerModulePath('custom', '../custom/')
  52. ->requireModule('custom.main');
  53. ]]></programlisting>
  54. <para>
  55. But since <classname>Zend_Dojo</classname> aggregates your various
  56. <command>dojo.require</command> statements, how do you create your layer
  57. script? You could open each page and view the generated
  58. <command>dojo.require</command> statements, and cut and paste them into a
  59. layer script file manually.
  60. </para>
  61. <para>
  62. However, a better solution exists: since
  63. <classname>Zend_Dojo</classname> aggregates this information
  64. already, you can simply pull that information and build your layer
  65. file. This is the purpose of
  66. <classname>Zend_Dojo_BuildLayer</classname>.
  67. </para>
  68. </sect2>
  69. <sect2 id="zend.dojo.build-layers.usage">
  70. <title>Generating Custom Module Layers with Zend_Dojo_BuildLayer</title>
  71. <para>
  72. At its simplest, you simply instantiate
  73. <classname>Zend_Dojo_BuildLayer</classname>, feed it the view object
  74. and the name of your custom module layer, and have it generate the
  75. content of the layer file; it is up to you to then write it to disk.
  76. </para>
  77. <para>
  78. As an example, let's say you wanted to create the module layer
  79. "<filename>custom.main</filename>". Assuming you follow the recommended project
  80. directory structure, and that you are storing your JavaScript files under
  81. <filename>public/js/</filename>, you could do the following:
  82. </para>
  83. <programlisting language="php"><![CDATA[
  84. $build = new Zend_Dojo_BuildLayer(array(
  85. 'view' => $view,
  86. 'layerName' => 'custom.main',
  87. ));
  88. $layerContents = $build->generateLayerScript();
  89. $filename = APPLICATION_PATH . '/../public/js/custom/main.js';
  90. if (!file_exists(dirname($filename))) {
  91. mkdir(dirname($filename));
  92. }
  93. file_put_contents($filename, $layerContents);
  94. ]]></programlisting>
  95. <para>
  96. When should you do the above? For it to work correctly, you need to
  97. do it after all view scripts and the layout have been rendered, to
  98. ensure that the <methodname>dojo()</methodname> helper is fully populated. One
  99. easy way to do so is using a front controller plugin, with a
  100. <methodname>dispatchLoopShutdown()</methodname> hook:
  101. </para>
  102. <programlisting language="php"><![CDATA[
  103. class App_Plugin_DojoLayer extends Zend_Controller_Plugin_Abstract
  104. {
  105. public $layerScript = APPLICATION_PATH . '/../public/js/custom/main.js';
  106. protected $_build;
  107. public function dispatchLoopShutdown()
  108. {
  109. if (!file_exists($this->layerScript)) {
  110. $this->generateDojoLayer();
  111. }
  112. }
  113. public function getBuild()
  114. {
  115. $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(
  116. 'ViewRenderer'
  117. );
  118. $viewRenderer->initView();
  119. if (null === $this->_build) {
  120. $this->_build = new Zend_Dojo_BuildLayer(array(
  121. 'view' => $viewRenderer->view,
  122. 'layerName' => 'custom.main',
  123. ));
  124. }
  125. return $this->_build;
  126. }
  127. public function generateDojoLayer()
  128. {
  129. $build = $this->getBuild();
  130. $layerContents = $build->generateLayerScript();
  131. if (!file_exists(dirname($this->layerScript))) {
  132. mkdir(dirname($this->layerScript));
  133. }
  134. file_put_contents($this->layerScript, $layerContents);
  135. }
  136. }
  137. ]]></programlisting>
  138. <note>
  139. <title>Do not generate the layer on every page</title>
  140. <para>
  141. It's tempting to generate the layer script on each and every
  142. page. However, this is resource intensive, as it must write to
  143. the disk on each page. Additionally, since the mtime of the file
  144. will keep changing, you will get no benefits of client-side
  145. caching. Write the file once.
  146. </para>
  147. </note>
  148. <sect3 id="zend.dojo.build-layers.usage.options">
  149. <title>BuildLayer options</title>
  150. <para>
  151. The above functionality will suffice for most situations. For
  152. those needing more customization, a variety of options may be
  153. invoked.
  154. </para>
  155. <sect4 id="zend.dojo.build-layers.usage.options.view">
  156. <title>Setting the view object</title>
  157. <para>
  158. While the view object may be passed during instantiation,
  159. you may also pass it in to an instance via the
  160. <methodname>setView()</methodname> method:
  161. </para>
  162. <programlisting language="php"><![CDATA[
  163. $build->setView($view);
  164. ]]></programlisting>
  165. </sect4>
  166. <sect4 id="zend.dojo.build-layers.usage.options.layername">
  167. <title>Setting the layer name</title>
  168. <para>
  169. While the layer name may be passed during instantiation,
  170. you may also pass it in to an instance via the
  171. <methodname>setLayerName()</methodname> method:
  172. </para>
  173. <programlisting language="php"><![CDATA[
  174. $build->setLayerName("custom.main");
  175. ]]></programlisting>
  176. </sect4>
  177. <sect4 id="zend.dojo.build-layers.usage.options.onload">
  178. <title>Including onLoad events in the generated layer</title>
  179. <para>
  180. <command>dojo.addOnLoad</command> is a useful utility for
  181. specifying actions that should trigger when the <acronym>DOM</acronym> has
  182. finished loading. The <methodname>dojo()</methodname> view helper can
  183. create these statements via its
  184. <methodname>addOnLoad()</methodname> and
  185. <methodname>onLoadCapture()</methodname> methods. In some
  186. cases, it makes sense to push these into your layer file
  187. instead of rendering them via your view scripts.
  188. </para>
  189. <para>
  190. By default, these are not rendered; to enable them, pass the
  191. <property>consumeOnLoad</property> configuration key during
  192. instantiation:
  193. </para>
  194. <programlisting language="php"><![CDATA[
  195. $build = new Zend_Dojo_BuildLayer(array(
  196. 'view' => $view,
  197. 'layerName' => 'custom.main',
  198. 'consumeOnLoad' => true,
  199. ));
  200. ]]></programlisting>
  201. <para>
  202. Alternately, you can use the
  203. <methodname>setConsumeOnLoad()</methodname> method after
  204. instantiation:
  205. </para>
  206. <programlisting language="php"><![CDATA[
  207. $build->setConsumeOnLoad(true);
  208. ]]></programlisting>
  209. </sect4>
  210. <sect4 id="zend.dojo.build-layers.usage.options.javascript">
  211. <title>Including captured JavaScript in the generated layer</title>
  212. <para>
  213. The <methodname>dojo()</methodname> view helper includes methods for
  214. capturing arbitrary JavaScript to include in the
  215. &lt;script&gt; tag containing the various
  216. <command>dojo.require</command> and <command>dojo.addOnLoad</command>
  217. statements. This can be useful when creating default data
  218. stores or globally scoped objects used throughout your
  219. application.
  220. </para>
  221. <para>
  222. By default, these are not rendered; to enable them, pass the
  223. <property>consumeJavascript</property> configuration key during
  224. instantiation:
  225. </para>
  226. <programlisting language="php"><![CDATA[
  227. $build = new Zend_Dojo_BuildLayer(array(
  228. 'view' => $view,
  229. 'layerName' => 'custom.main',
  230. 'consumeJavascript' => true,
  231. ));
  232. ]]></programlisting>
  233. <para>
  234. Alternately, you can use the
  235. <methodname>setConsumeJavascript()</methodname> method after
  236. instantiation:
  237. </para>
  238. <programlisting language="php"><![CDATA[
  239. $build->setConsumeJavascript(true);
  240. ]]></programlisting>
  241. </sect4>
  242. </sect3>
  243. </sect2>
  244. <sect2 id="zend.dojo.build-layers.profiles">
  245. <title>Generating Build Profiles with Zend_Dojo_BuildLayer</title>
  246. <para>
  247. One of the chief benefits of a Dojo module layer is that it
  248. facilitates the creation of a custom build.
  249. <classname>Zend_Dojo_BuildLayer</classname> has functionality for
  250. generate build profiles.
  251. </para>
  252. <para>
  253. The simplest use case is to utilize the
  254. <methodname>generateBuildProfile()</methodname> method and send the
  255. output to a file:
  256. </para>
  257. <programlisting language="php"><![CDATA[
  258. $build = new Zend_Dojo_BuildLayer(array(
  259. 'view' => $view,
  260. 'layerName' => 'custom.main',
  261. ));
  262. $profile = $build->generateBuildProfile();
  263. $filename = APPLICATION_PATH . '/../misc/scripts/custom.profile.js';
  264. file_put_contents($filename, $profile);
  265. ]]></programlisting>
  266. <para>
  267. Just like generating layers, you may want to automate this via a
  268. <methodname>dispatchLoopShutdown()</methodname> plugin hook; you
  269. could even simply modify the one shown for generating layers to read
  270. as follows:
  271. </para>
  272. <programlisting language="php"><![CDATA[
  273. class App_Plugin_DojoLayer extends Zend_Controller_Plugin_Abstract
  274. {
  275. public $layerScript = APPLICATION_PATH
  276. . '/../public/js/custom/main.js';
  277. public $buildProfile = APPLICATION_PATH
  278. . '/../misc/scripts/custom.profile.js';
  279. protected $_build;
  280. public function dispatchLoopShutdown()
  281. {
  282. if (!file_exists($this->layerScript)) {
  283. $this->generateDojoLayer();
  284. }
  285. if (!file_exists($this->buildProfile)) {
  286. $this->generateBuildProfile();
  287. }
  288. }
  289. public function generateDojoLayer() { /* ... */ }
  290. public function generateBuildProfile()
  291. {
  292. $profile = $this->getBuild()->generateBuildProfile();
  293. file_put_contents($this->buildProfile, $profile);
  294. }
  295. }
  296. ]]></programlisting>
  297. <para>
  298. As noted, with module layers, you should only create the file once.
  299. </para>
  300. <sect3 id="zend.dojo.build-layers.profiles.options">
  301. <title>Build Profile options</title>
  302. <para>
  303. The above functionality will suffice for most situations. The
  304. only way to customize build profile generation is to provide
  305. additional build profile options to utilize.
  306. </para>
  307. <para>
  308. As an example, you may want to specify what type of
  309. optimizations should be performed, whether or not to optimize
  310. <acronym>CSS</acronym> files in the layer, whether or not to copy tests into the
  311. build, etc. For a listing of available options, you should read
  312. the <ulink url="http://docs.dojocampus.org/build/index">Dojo
  313. Build documentation</ulink> and <ulink
  314. url="http://dojotoolkit.org/reference-guide/dojo/index.html#package-system">accompanying
  315. documentation</ulink>.
  316. </para>
  317. <para>
  318. Setting these options is trivial: use the
  319. <methodname>addProfileOption()</methodname>,
  320. <methodname>addProfileOptions()</methodname>, or
  321. <methodname>setProfileOptions()</methodname> methods. The first
  322. method adds a single key and value option pair, the second will add
  323. several, and the third will overwrite any options with the list
  324. of key and value pairs provided.
  325. </para>
  326. <para>
  327. By default, the following options are set:
  328. </para>
  329. <programlisting language="javascript"><![CDATA[
  330. {
  331. action: "release",
  332. optimize: "shrinksafe",
  333. layerOptimize: "shrinksafe",
  334. copyTests: false,
  335. loader: "default",
  336. cssOptimize: "comments"
  337. }
  338. ]]></programlisting>
  339. <para>
  340. You can pass in whatever key and value pairs you want; the Dojo
  341. build script will ignore those it does not understand.
  342. </para>
  343. <para>
  344. As an example of setting options:
  345. </para>
  346. <programlisting language="php"><![CDATA[
  347. // A single option:
  348. $build->addProfileOption('version', 'zend-1.3.1');
  349. // Several options:
  350. $build->addProfileOptions(array(
  351. 'loader' => 'xdomain',
  352. 'optimize' => 'packer',
  353. ));
  354. // Or overwrite options:
  355. $build->setProfileOptions(array(
  356. 'version' => 'custom-1.3.1',
  357. 'loader' => 'shrinksafe',
  358. 'optimize' => 'shrinksafe',
  359. ));
  360. ]]></programlisting>
  361. </sect3>
  362. </sect2>
  363. </sect1>