Zend_Dojo-BuildLayers.xml 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  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 <code>dojo.require</code> 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. <code>dojo.require</code> statements, how do you create your layer
  57. script? You could open each page and view the generated
  58. <code>dojo.require</code> 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. "custom.main". Assuming you follow the recommended project directory
  80. 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 (!dir_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. if (null === $this->_build) {
  116. $this->_build = new Zend_Dojo_BuildLayer(array(
  117. 'view' => $view,
  118. 'layerName' => 'custom.main',
  119. ));
  120. }
  121. return $this->_build;
  122. }
  123. public function generateDojoLayer()
  124. {
  125. $build = $this->getBuild();
  126. $layerContents = $build->generateLayerScript();
  127. if (!dir_exists(dirname($this->layerScript))) {
  128. mkdir(dirname($this->layerScript));
  129. }
  130. file_put_contents($this->layerScript, $layerContents);
  131. }
  132. }
  133. ]]></programlisting>
  134. <note>
  135. <title>Do not generate the layer on every page</title>
  136. <para>
  137. It's tempting to generate the layer script on each and every
  138. page. However, this is resource intensive, as it must write to
  139. the disk on each page. Additionally, since the mtime of the file
  140. will keep changing, you will get no benefits of client-side
  141. caching. Write the file once.
  142. </para>
  143. </note>
  144. <sect3 id="zend.dojo.build-layers.usage.options">
  145. <title>BuildLayer options</title>
  146. <para>
  147. The above functionality will suffice for most situations. For
  148. those needing more customization, a variety of options may be
  149. invoked.
  150. </para>
  151. <sect4 id="zend.dojo.build-layers.usage.options.view">
  152. <title>Setting the view object</title>
  153. <para>
  154. While the view object may be passed during instantiation,
  155. you may also pass it in to an instance via the
  156. <methodname>setView()</methodname> method:
  157. </para>
  158. <programlisting language="php"><![CDATA[
  159. $build->setView($view);
  160. ]]></programlisting>
  161. </sect4>
  162. <sect4 id="zend.dojo.build-layers.usage.options.layername">
  163. <title>Setting the layer name</title>
  164. <para>
  165. While the layer name may be passed during instantiation,
  166. you may also pass it in to an instance via the
  167. <methodname>setLayerName()</methodname> method:
  168. </para>
  169. <programlisting language="php"><![CDATA[
  170. $build->setLayerName("custom.main");
  171. ]]></programlisting>
  172. </sect4>
  173. <sect4 id="zend.dojo.build-layers.usage.options.onload">
  174. <title>Including onLoad events in the generated layer</title>
  175. <para>
  176. <code>dojo.addOnLoad</code> is a useful utility for
  177. specifying actions that should trigger when the <acronym>DOM</acronym> has
  178. finished loading. The <methodname>dojo()</methodname> view helper can
  179. create these statements via its
  180. <methodname>addOnLoad()</methodname> and
  181. <methodname>onLoadCapture*()</methodname> methods. In some
  182. cases, it makes sense to push these into your layer file
  183. instead of rendering them via your view scripts.
  184. </para>
  185. <para>
  186. By default, these are not rendered; to enable them, pass the
  187. <property>consumeOnLoad</property> configuration key during
  188. instantiation:
  189. </para>
  190. <programlisting language="php"><![CDATA[
  191. $build = new Zend_Dojo_BuildLayer(array(
  192. 'view' => $view,
  193. 'layerName' => 'custom.main',
  194. 'consumeOnLoad' => true,
  195. ));
  196. ]]></programlisting>
  197. <para>
  198. Alternately, you can use the
  199. <methodname>setConsumeOnLoad()</methodname> method after
  200. instantiation:
  201. </para>
  202. <programlisting language="php"><![CDATA[
  203. $build->setConsumeOnLoad(true);
  204. ]]></programlisting>
  205. </sect4>
  206. <sect4 id="zend.dojo.build-layers.usage.options.javascript">
  207. <title>Including captured JavaScript in the generated layer</title>
  208. <para>
  209. The <methodname>dojo()</methodname> view helper includes methods for
  210. capturing arbitrary JavaScript to include in the
  211. &lt;script&gt; tag containing the various
  212. <code>dojo.require</code> and <code>dojo.addOnLoad</code>
  213. statements. This can be useful when creating default data
  214. stores or globally scoped objects used throughout your
  215. application.
  216. </para>
  217. <para>
  218. By default, these are not rendered; to enable them, pass the
  219. <property>consumeJavascript</property> configuration key during
  220. instantiation:
  221. </para>
  222. <programlisting language="php"><![CDATA[
  223. $build = new Zend_Dojo_BuildLayer(array(
  224. 'view' => $view,
  225. 'layerName' => 'custom.main',
  226. 'consumeJavascript' => true,
  227. ));
  228. ]]></programlisting>
  229. <para>
  230. Alternately, you can use the
  231. <methodname>setConsumeJavascript()</methodname> method after
  232. instantiation:
  233. </para>
  234. <programlisting language="php"><![CDATA[
  235. $build->setConsumeJavascript(true);
  236. ]]></programlisting>
  237. </sect4>
  238. </sect3>
  239. </sect2>
  240. <sect2 id="zend.dojo.build-layers.profiles">
  241. <title>Generating Build Profiles with Zend_Dojo_BuildLayer</title>
  242. <para>
  243. One of the chief benefits of a Dojo module layer is that it
  244. facilitates the creation of a custom build.
  245. <classname>Zend_Dojo_BuildLayer</classname> has functionality for
  246. generate build profiles.
  247. </para>
  248. <para>
  249. The simplest use case is to utilize the
  250. <methodname>generateBuildProfile()</methodname> method and send the
  251. output to a file:
  252. </para>
  253. <programlisting language="php"><![CDATA[
  254. $build = new Zend_Dojo_BuildLayer(array(
  255. 'view' => $view,
  256. 'layerName' => 'custom.main',
  257. ));
  258. $profile = $build->generateBuildProfile();
  259. $filename = APPLICATION_PATH . '/../misc/scripts/custom.profile.js';
  260. file_put_contents($filename, $profile);
  261. ]]></programlisting>
  262. <para>
  263. Just like generating layers, you may want to automate this via a
  264. <methodname>dispatchLoopShutdown()</methodname> plugin hook; you
  265. could even simply modify the one shown for generating layers to read
  266. as follows:
  267. </para>
  268. <programlisting language="php"><![CDATA[
  269. class App_Plugin_DojoLayer extends Zend_Controller_Plugin_Abstract
  270. {
  271. public $layerScript = APPLICATION_PATH
  272. . '/../public/js/custom/main.js';
  273. public $buildProfile = APPLICATION_PATH
  274. . '/../misc/scripts/custom.profile.js';
  275. protected $_build;
  276. public function dispatchLoopShutdown()
  277. {
  278. if (!file_exists($this->layerScript)) {
  279. $this->generateDojoLayer();
  280. }
  281. if (!file_exists($this->buildProfile)) {
  282. $this->generateBuildProfile();
  283. }
  284. }
  285. public function generateDojoLayer() { /* ... */ }
  286. public function generateBuildProfile()
  287. {
  288. $profile = $this->getBuild()->generateBuildProfile();
  289. file_put_contents($this->buildProfile, $profile);
  290. }
  291. }
  292. ]]></programlisting>
  293. <para>
  294. As noted, with module layers, you should only create the file once.
  295. </para>
  296. <sect3 id="zend.dojo.build-layers.profiles.options">
  297. <title>Build Profile options</title>
  298. <para>
  299. The above functionality will suffice for most situations. The
  300. only way to customize build profile generation is to provide
  301. additional build profile options to utilize.
  302. </para>
  303. <para>
  304. As an example, you may want to specify what type of
  305. optimizations should be performed, whether or not to optimize
  306. <acronym>CSS</acronym> files in the layer, whether or not to copy tests into the
  307. build, etc. For a listing of available options, you should read
  308. the <ulink url="http://docs.dojocampus.org/build/index">Dojo
  309. Build documentation</ulink> and <ulink
  310. url="http://www.dojotoolkit.org/book/dojo-book-0-9/part-4-meta-dojo/package-system-and-custom-builds">accompanying
  311. documentation</ulink>.
  312. </para>
  313. <para>
  314. Setting these options is trivial: use the
  315. <methodname>addProfileOption()</methodname>,
  316. <methodname>addProfileOptions()</methodname>, or
  317. <methodname>setProfileOptions()</methodname> methods. The first
  318. method adds a single key and value option pair, the second will add
  319. several, and the third will overwrite any options with the list
  320. of key and value pairs provided.
  321. </para>
  322. <para>
  323. By default, the following options are set:
  324. </para>
  325. <programlisting language="javascript"><![CDATA[
  326. {
  327. action: "release",
  328. optimize: "shrinksafe",
  329. layerOptimize: "shrinksafe",
  330. copyTests: false,
  331. loader: "default",
  332. cssOptimize: "comments"
  333. }
  334. ]]></programlisting>
  335. <para>
  336. You can pass in whatever key and value pairs you want; the Dojo
  337. build script will ignore those it does not understand.
  338. </para>
  339. <para>
  340. As an example of setting options:
  341. </para>
  342. <programlisting language="php"><![CDATA[
  343. // A single option:
  344. $build->addProfileOption('version', 'zend-1.3.1');
  345. // Several options:
  346. $build->addProfileOptions(array(
  347. 'loader' => 'xdomain',
  348. 'optimize' => 'packer',
  349. ));
  350. // Or overwrite options:
  351. $build->setProfileOptions(array(
  352. 'version' => 'custom-1.3.1',
  353. 'loader' => 'shrinksafe',
  354. 'optimize' => 'shrinksafe',
  355. ));
  356. ]]></programlisting>
  357. </sect3>
  358. </sect2>
  359. </sect1>