1 <?xml version="1.0" encoding="UTF-8"?>
3 <sect1 id="zend.dojo.build-layers">
4 <title>Zend_Dojo build layer support</title>
6 <sect2 id="zend.dojo.build-layers.introduction">
7 <title>Introduction</title>
10 Dojo build layers provide a clean path from development to
11 production when using Dojo for your UI layer. In development, you
12 can have load-on-demand, rapid application prototyping; a build
13 layer takes all Dojo dependencies and compiles them to a single
14 file, optionally stripping whitespace and comments, and performing
15 code heuristics to allow further minification of variable names.
16 Additionally, it can do <acronym>CSS</acronym> minification.
20 In order to create a build layer, you would traditionally create a
21 JavaScript file that has <command>dojo.require</command> statements for
22 each dependency, and optionally some additional code that might run
23 when the script is loaded. As an example:
26 <programlisting language="javascript"><![CDATA[
27 dojo.provide("custom.main");
29 dojo.require("dijit.layout.TabContainer");
30 dojo.require("dijit.layout.ContentPane");
31 dojo.require("dijit.form.Form");
32 dojo.require("dijit.form.Button");
33 dojo.require("dijit.form.TextBox");
37 This script is generally referred to as a "layer" script.
41 Then, in your application's layout, you'd instruct Dojo to load this
45 <programlisting language="html"><![CDATA[
48 <script type="text/javascript" src="/js/dojo/dojo.js"></script>
49 <script type="text/javascript">
50 dojo.registerModulePath("custom", "../custom/");
51 dojo.require("custom.main");
56 If you use <classname>Zend_Dojo</classname> to do this, you'd do the
60 <programlisting language="php"><![CDATA[
61 $view->dojo()->registerModulePath('custom', '../custom/')
62 ->requireModule('custom.main');
66 But since <classname>Zend_Dojo</classname> aggregates your various
67 <command>dojo.require</command> statements, how do you create your layer
68 script? You could open each page and view the generated
69 <command>dojo.require</command> statements, and cut and paste them into a
70 layer script file manually.
74 However, a better solution exists: since
75 <classname>Zend_Dojo</classname> aggregates this information
76 already, you can simply pull that information and build your layer
77 file. This is the purpose of
78 <classname>Zend_Dojo_BuildLayer</classname>.
82 <sect2 id="zend.dojo.build-layers.usage">
83 <title>Generating Custom Module Layers with Zend_Dojo_BuildLayer</title>
86 At its simplest, you simply instantiate
87 <classname>Zend_Dojo_BuildLayer</classname>, feed it the view object
88 and the name of your custom module layer, and have it generate the
89 content of the layer file; it is up to you to then write it to disk.
93 As an example, let's say you wanted to create the module layer
94 "<filename>custom.main</filename>". Assuming you follow the recommended project
95 directory structure, and that you are storing your JavaScript files under
96 <filename>public/js/</filename>, you could do the following:
99 <programlisting language="php"><![CDATA[
100 $build = new Zend_Dojo_BuildLayer(array(
102 'layerName' => 'custom.main',
105 $layerContents = $build->generateLayerScript();
106 $filename = APPLICATION_PATH . '/../public/js/custom/main.js';
107 if (!dir_exists(dirname($filename))) {
108 mkdir(dirname($filename));
110 file_put_contents($filename, $layerContents);
114 When should you do the above? For it to work correctly, you need to
115 do it after all view scripts and the layout have been rendered, to
116 ensure that the <methodname>dojo()</methodname> helper is fully populated. One
117 easy way to do so is using a front controller plugin, with a
118 <methodname>dispatchLoopShutdown()</methodname> hook:
121 <programlisting language="php"><![CDATA[
122 class App_Plugin_DojoLayer extends Zend_Controller_Plugin_Abstract
124 public $layerScript = APPLICATION_PATH . '/../public/js/custom/main.js';
127 public function dispatchLoopShutdown()
129 if (!file_exists($this->layerScript)) {
130 $this->generateDojoLayer();
134 public function getBuild()
136 $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(
139 $viewRenderer->initView();
140 if (null === $this->_build) {
141 $this->_build = new Zend_Dojo_BuildLayer(array(
142 'view' => $viewRenderer->view,
143 'layerName' => 'custom.main',
146 return $this->_build;
149 public function generateDojoLayer()
151 $build = $this->getBuild();
152 $layerContents = $build->generateLayerScript();
153 if (!dir_exists(dirname($this->layerScript))) {
154 mkdir(dirname($this->layerScript));
156 file_put_contents($this->layerScript, $layerContents);
162 <title>Do not generate the layer on every page</title>
165 It's tempting to generate the layer script on each and every
166 page. However, this is resource intensive, as it must write to
167 the disk on each page. Additionally, since the mtime of the file
168 will keep changing, you will get no benefits of client-side
169 caching. Write the file once.
173 <sect3 id="zend.dojo.build-layers.usage.options">
174 <title>BuildLayer options</title>
177 The above functionality will suffice for most situations. For
178 those needing more customization, a variety of options may be
182 <sect4 id="zend.dojo.build-layers.usage.options.view">
183 <title>Setting the view object</title>
186 While the view object may be passed during instantiation,
187 you may also pass it in to an instance via the
188 <methodname>setView()</methodname> method:
191 <programlisting language="php"><![CDATA[
192 $build->setView($view);
196 <sect4 id="zend.dojo.build-layers.usage.options.layername">
197 <title>Setting the layer name</title>
200 While the layer name may be passed during instantiation,
201 you may also pass it in to an instance via the
202 <methodname>setLayerName()</methodname> method:
205 <programlisting language="php"><![CDATA[
206 $build->setLayerName("custom.main");
210 <sect4 id="zend.dojo.build-layers.usage.options.onload">
211 <title>Including onLoad events in the generated layer</title>
214 <command>dojo.addOnLoad</command> is a useful utility for
215 specifying actions that should trigger when the <acronym>DOM</acronym> has
216 finished loading. The <methodname>dojo()</methodname> view helper can
217 create these statements via its
218 <methodname>addOnLoad()</methodname> and
219 <methodname>onLoadCapture()</methodname> methods. In some
220 cases, it makes sense to push these into your layer file
221 instead of rendering them via your view scripts.
225 By default, these are not rendered; to enable them, pass the
226 <property>consumeOnLoad</property> configuration key during
230 <programlisting language="php"><![CDATA[
231 $build = new Zend_Dojo_BuildLayer(array(
233 'layerName' => 'custom.main',
234 'consumeOnLoad' => true,
239 Alternately, you can use the
240 <methodname>setConsumeOnLoad()</methodname> method after
244 <programlisting language="php"><![CDATA[
245 $build->setConsumeOnLoad(true);
249 <sect4 id="zend.dojo.build-layers.usage.options.javascript">
250 <title>Including captured JavaScript in the generated layer</title>
253 The <methodname>dojo()</methodname> view helper includes methods for
254 capturing arbitrary JavaScript to include in the
255 <script> tag containing the various
256 <command>dojo.require</command> and <command>dojo.addOnLoad</command>
257 statements. This can be useful when creating default data
258 stores or globally scoped objects used throughout your
263 By default, these are not rendered; to enable them, pass the
264 <property>consumeJavascript</property> configuration key during
268 <programlisting language="php"><![CDATA[
269 $build = new Zend_Dojo_BuildLayer(array(
271 'layerName' => 'custom.main',
272 'consumeJavascript' => true,
277 Alternately, you can use the
278 <methodname>setConsumeJavascript()</methodname> method after
282 <programlisting language="php"><![CDATA[
283 $build->setConsumeJavascript(true);
289 <sect2 id="zend.dojo.build-layers.profiles">
290 <title>Generating Build Profiles with Zend_Dojo_BuildLayer</title>
293 One of the chief benefits of a Dojo module layer is that it
294 facilitates the creation of a custom build.
295 <classname>Zend_Dojo_BuildLayer</classname> has functionality for
296 generate build profiles.
300 The simplest use case is to utilize the
301 <methodname>generateBuildProfile()</methodname> method and send the
305 <programlisting language="php"><![CDATA[
306 $build = new Zend_Dojo_BuildLayer(array(
308 'layerName' => 'custom.main',
311 $profile = $build->generateBuildProfile();
312 $filename = APPLICATION_PATH . '/../misc/scripts/custom.profile.js';
313 file_put_contents($filename, $profile);
317 Just like generating layers, you may want to automate this via a
318 <methodname>dispatchLoopShutdown()</methodname> plugin hook; you
319 could even simply modify the one shown for generating layers to read
323 <programlisting language="php"><![CDATA[
324 class App_Plugin_DojoLayer extends Zend_Controller_Plugin_Abstract
326 public $layerScript = APPLICATION_PATH
327 . '/../public/js/custom/main.js';
328 public $buildProfile = APPLICATION_PATH
329 . '/../misc/scripts/custom.profile.js';
332 public function dispatchLoopShutdown()
334 if (!file_exists($this->layerScript)) {
335 $this->generateDojoLayer();
337 if (!file_exists($this->buildProfile)) {
338 $this->generateBuildProfile();
342 public function generateDojoLayer() { /* ... */ }
344 public function generateBuildProfile()
346 $profile = $this->getBuild()->generateBuildProfile();
347 file_put_contents($this->buildProfile, $profile);
354 As noted, with module layers, you should only create the file once.
357 <sect3 id="zend.dojo.build-layers.profiles.options">
358 <title>Build Profile options</title>
361 The above functionality will suffice for most situations. The
362 only way to customize build profile generation is to provide
363 additional build profile options to utilize.
367 As an example, you may want to specify what type of
368 optimizations should be performed, whether or not to optimize
369 <acronym>CSS</acronym> files in the layer, whether or not to copy tests into the
370 build, etc. For a listing of available options, you should read
371 the <ulink url="http://docs.dojocampus.org/build/index">Dojo
372 Build documentation</ulink> and <ulink
373 url="http://www.dojotoolkit.org/book/dojo-book-0-9/part-4-meta-dojo/package-system-and-custom-builds">accompanying
374 documentation</ulink>.
378 Setting these options is trivial: use the
379 <methodname>addProfileOption()</methodname>,
380 <methodname>addProfileOptions()</methodname>, or
381 <methodname>setProfileOptions()</methodname> methods. The first
382 method adds a single key and value option pair, the second will add
383 several, and the third will overwrite any options with the list
384 of key and value pairs provided.
388 By default, the following options are set:
391 <programlisting language="javascript"><![CDATA[
394 optimize: "shrinksafe",
395 layerOptimize: "shrinksafe",
398 cssOptimize: "comments"
403 You can pass in whatever key and value pairs you want; the Dojo
404 build script will ignore those it does not understand.
408 As an example of setting options:
411 <programlisting language="php"><![CDATA[
413 $build->addProfileOption('version', 'zend-1.3.1');
416 $build->addProfileOptions(array(
417 'loader' => 'xdomain',
418 'optimize' => 'packer',
421 // Or overwrite options:
422 $build->setProfileOptions(array(
423 'version' => 'custom-1.3.1',
424 'loader' => 'shrinksafe',
425 'optimize' => 'shrinksafe',