Zend_Dojo-BuildLayers.xml 15 KB

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