|
|
@@ -0,0 +1,423 @@
|
|
|
+<?xml version="1.0" encoding="UTF-8"?>
|
|
|
+<sect1 id="zend.dojo.build-layers">
|
|
|
+ <title>Zend_Dojo build layer support</title>
|
|
|
+
|
|
|
+ <sect2 id="zend.dojo.build-layers.introduction">
|
|
|
+ <title>Introduction</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Dojo build layers provide a clean path from development to
|
|
|
+ production when using Dojo for your UI layer. In development, you
|
|
|
+ can have load-on-demand, rapid application prototyping; a build
|
|
|
+ layer takes all Dojo dependencies and compiles them to a single
|
|
|
+ file, optionally stripping whitespace and comments, and performing
|
|
|
+ code heuristics to allow further minification of variable names.
|
|
|
+ Additionally, it can do CSS minification.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ In order to create a build layer, you would traditionally create a
|
|
|
+ JavaScript file that has <code>dojo.require</code> statements for
|
|
|
+ each dependency, and optionally some additional code that might run
|
|
|
+ when the script is loaded. As an example:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting role="javascript"><![CDATA[
|
|
|
+dojo.provide("custom.main");
|
|
|
+
|
|
|
+dojo.require("dijit.layout.TabContainer");
|
|
|
+dojo.require("dijit.layout.ContentPane");
|
|
|
+dojo.require("dijit.form.Form");
|
|
|
+dojo.require("dijit.form.Button");
|
|
|
+dojo.require("dijit.form.TextBox");
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ This script is generally referred to as a "layer" script.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Then, in your application's layout, you'd instruct Dojo to load this
|
|
|
+ module:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting role="html"><![CDATA[
|
|
|
+<html>
|
|
|
+<head>
|
|
|
+ <script type="text/javascript" src="/js/dojo/dojo.js"></script>
|
|
|
+ <script type="text/javascript">
|
|
|
+ dojo.registerModulePath("custom", "../custom/");
|
|
|
+ dojo.require("custom.main");
|
|
|
+ </script>
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ If you use <classname>Zend_Dojo</classname> to do this, you'd do the
|
|
|
+ following:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting role="php"><![CDATA[
|
|
|
+$view->dojo()->registerModulePath('custom', '../custom/')
|
|
|
+ ->requireModule('custom.main');
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ But since <classname>Zend_Dojo</classname> aggregates your various
|
|
|
+ <code>dojo.require</code> statements, how do you create your layer
|
|
|
+ script? You could open each page and view the generated
|
|
|
+ <code>dojo.require</code> statements, and cut and paste them into a
|
|
|
+ layer script file manually.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ However, a better solution exists: since
|
|
|
+ <classname>Zend_Dojo</classname> aggregates this information
|
|
|
+ already, you can simply pull that information and build your layer
|
|
|
+ file. This is the purpose of
|
|
|
+ <classname>Zend_Dojo_BuildLayer</classname>.
|
|
|
+ </para>
|
|
|
+ </sect2>
|
|
|
+
|
|
|
+ <sect2 id="zend.dojo.build-layers.usage">
|
|
|
+ <title>Generating Custom Module Layers with Zend_Dojo_BuildLayer</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ At its simplest, you simply instantiate
|
|
|
+ <classname>Zend_Dojo_BuildLayer</classname>, feed it the view object
|
|
|
+ and the name of your custom module layer, and have it generate the
|
|
|
+ content of the layer file; it is up to you to then write it to disk.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ As an example, let's say you wanted to create the module layer
|
|
|
+ "custom.main". Assuming you follow the recommended project directory
|
|
|
+ structure, and that you are storing your JavaScript files under
|
|
|
+ <filename>public/js/</filename>, you could do the following:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting role="php"><![CDATA[
|
|
|
+$build = new Zend_Dojo_BuildLayer(array(
|
|
|
+ 'view' => $view,
|
|
|
+ 'layerName' => 'custom.main',
|
|
|
+));
|
|
|
+
|
|
|
+$layerContents = $build->generateLayerScript();
|
|
|
+$filename = APPLICATION_PATH . '/../public/js/custom/main.js';
|
|
|
+if (!dir_exists(dirname($filename))) {
|
|
|
+ mkdir(dirname($filename));
|
|
|
+}
|
|
|
+file_put_contents($filename, $layerContents);
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ When should you do the above? For it to work correctly, you need to
|
|
|
+ do it after all view scripts and the layout have been rendered, to
|
|
|
+ ensure that the <code>dojo()</code> helper is fully populated. One
|
|
|
+ easy way to do so is using a front controller plugin, with a
|
|
|
+ <code>dispatchLoopShutdown()</code> hook:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting role="php"><![CDATA[
|
|
|
+class App_Plugin_DojoLayer extends Zend_Controller_Plugin_Abstract
|
|
|
+{
|
|
|
+ public $layerScript = APPLICATION_PATH . '/../public/js/custom/main.js';
|
|
|
+ protected $_build;
|
|
|
+
|
|
|
+ public function dispatchLoopShutdown()
|
|
|
+ {
|
|
|
+ if (!file_exists($this->layerScript)) {
|
|
|
+ $this->generateDojoLayer();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getBuild()
|
|
|
+ {
|
|
|
+ if (null === $this->_build) {
|
|
|
+ $this->_build = new Zend_Dojo_BuildLayer(array(
|
|
|
+ 'view' => $view,
|
|
|
+ 'layerName' => 'custom.main',
|
|
|
+ ));
|
|
|
+ }
|
|
|
+ return $this->_build;
|
|
|
+ }
|
|
|
+
|
|
|
+ public function generateDojoLayer()
|
|
|
+ {
|
|
|
+ $build = $this->getBuild();
|
|
|
+ $layerContents = $build->generateLayerScript();
|
|
|
+ if (!dir_exists(dirname($this->layerScript))) {
|
|
|
+ mkdir(dirname($this->layerScript));
|
|
|
+ }
|
|
|
+ file_put_contents($this->layerScript, $layerContents);
|
|
|
+ }
|
|
|
+}
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <note>
|
|
|
+ <title>Do not generate the layer on every page</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ It's tempting to generate the layer script on each and every
|
|
|
+ page. However, this is resource intensive, as it must write to
|
|
|
+ the disk on each page. Additionally, since the mtime of the file
|
|
|
+ will keep changing, you will get no benefits of client-side
|
|
|
+ caching. Write the file once.
|
|
|
+ </para>
|
|
|
+ </note>
|
|
|
+
|
|
|
+ <sect3 id="zend.dojo.build-layers.usage.options">
|
|
|
+ <title>BuildLayer options</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ The above functionality will suffice for most situations. For
|
|
|
+ those needing more customization, a variety of options may be
|
|
|
+ invoked.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <sect4 id="zend.dojo.build-layers.usage.options.view">
|
|
|
+ <title>Setting the view object</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ While the view object may be passed during instantiation,
|
|
|
+ you may also pass it in to an instance via the
|
|
|
+ <methodname>setView()</methodname> method:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting role="php"><![CDATA[
|
|
|
+$build->setView($view);
|
|
|
+]]></programlisting>
|
|
|
+ </sect4>
|
|
|
+
|
|
|
+ <sect4 id="zend.dojo.build-layers.usage.options.layername">
|
|
|
+ <title>Setting the layer name</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ While the layer name may be passed during instantiation,
|
|
|
+ you may also pass it in to an instance via the
|
|
|
+ <methodname>setLayerName()</methodname> method:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting role="php"><![CDATA[
|
|
|
+$build->setLayerName("custom.main");
|
|
|
+]]></programlisting>
|
|
|
+ </sect4>
|
|
|
+
|
|
|
+ <sect4 id="zend.dojo.build-layers.usage.options.onload">
|
|
|
+ <title>Including onLoad events in the generated layer</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ <code>dojo.addOnLoad</code> is a useful utility for
|
|
|
+ specifying actions that should trigger when the DOM has
|
|
|
+ finished loading. The <code>dojo()</code> view helper can
|
|
|
+ create these statements via its
|
|
|
+ <methodname>addOnLoad()</methodname> and
|
|
|
+ <methodname>onLoadCapture*()</methodname> methods. In some
|
|
|
+ cases, it makes sense to push these into your layer file
|
|
|
+ instead of rendering them via your view scripts.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ By default, these are not rendered; to enable them, pass the
|
|
|
+ <code>consumeOnLoad</code> configuration key during
|
|
|
+ instantiation:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting role="php"><![CDATA[
|
|
|
+$build = new Zend_Dojo_BuildLayer(array(
|
|
|
+ 'view' => $view,
|
|
|
+ 'layerName' => 'custom.main',
|
|
|
+ 'consumeOnLoad' => true,
|
|
|
+));
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Alternately, you can use the
|
|
|
+ <methodname>setConsumeOnLoad()</methodname> method after
|
|
|
+ instantiation:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting role="php"><![CDATA[
|
|
|
+$build->setConsumeOnLoad(true);
|
|
|
+]]></programlisting>
|
|
|
+ </sect4>
|
|
|
+
|
|
|
+ <sect4 id="zend.dojo.build-layers.usage.options.javascript">
|
|
|
+ <title>Including captured JavaScript in the generated layer</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ The <code>dojo()</code> view helper includes methods for
|
|
|
+ capturing arbitrary JavaScript to include in the
|
|
|
+ <script> tag containing the various
|
|
|
+ <code>dojo.require</code> and <code>dojo.addOnLoad</code>
|
|
|
+ statements. This can be useful when creating default data
|
|
|
+ stores or globally scoped objects used throughout your
|
|
|
+ application.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ By default, these are not rendered; to enable them, pass the
|
|
|
+ <code>consumeJavascript</code> configuration key during
|
|
|
+ instantiation:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting role="php"><![CDATA[
|
|
|
+$build = new Zend_Dojo_BuildLayer(array(
|
|
|
+ 'view' => $view,
|
|
|
+ 'layerName' => 'custom.main',
|
|
|
+ 'consumeJavascript' => true,
|
|
|
+));
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Alternately, you can use the
|
|
|
+ <methodname>setConsumeJavascript()</methodname> method after
|
|
|
+ instantiation:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting role="php"><![CDATA[
|
|
|
+$build->setConsumeJavascript(true);
|
|
|
+]]></programlisting>
|
|
|
+ </sect4>
|
|
|
+ </sect3>
|
|
|
+ </sect2>
|
|
|
+
|
|
|
+ <sect2 id="zend.dojo.build-layers.profiles">
|
|
|
+ <title>Generating Build Profiles with Zend_Dojo_BuildLayer</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ One of the chief benefits of a Dojo module layer is that it
|
|
|
+ facilitates the creation of a custom build.
|
|
|
+ <classname>Zend_Dojo_BuildLayer</classname> has functionality for
|
|
|
+ generate build profiles.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ The simplest use case is to utilize the
|
|
|
+ <methodname>generateBuildProfile()</methodname> method and send the
|
|
|
+ output to a file:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting role="php"><![CDATA[
|
|
|
+$build = new Zend_Dojo_BuildLayer(array(
|
|
|
+ 'view' => $view,
|
|
|
+ 'layerName' => 'custom.main',
|
|
|
+));
|
|
|
+
|
|
|
+$profile = $build->generateBuildProfile();
|
|
|
+$filename = APPLICATION_PATH . '/../misc/scripts/custom.profile.js';
|
|
|
+file_put_contents($filename, $profile);
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Just like generating layers, you may want to automate this via a
|
|
|
+ <methodname>dispatchLoopShutdown()</methodname> plugin hook; you
|
|
|
+ could even simply modify the one shown for generating layers to read
|
|
|
+ as follows:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting role="php"><![CDATA[
|
|
|
+class App_Plugin_DojoLayer extends Zend_Controller_Plugin_Abstract
|
|
|
+{
|
|
|
+ public $layerScript = APPLICATION_PATH . '/../public/js/custom/main.js';
|
|
|
+ public $buildProfile = APPLICATION_PATH . '/../misc/scripts/custom.profile.js';
|
|
|
+ protected $_build;
|
|
|
+
|
|
|
+ public function dispatchLoopShutdown()
|
|
|
+ {
|
|
|
+ if (!file_exists($this->layerScript)) {
|
|
|
+ $this->generateDojoLayer();
|
|
|
+ }
|
|
|
+ if (!file_exists($this->buildProfile)) {
|
|
|
+ $this->generateBuildProfile();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public function generateDojoLayer() { /* ... */ }
|
|
|
+
|
|
|
+ public function generateBuildProfile()
|
|
|
+ {
|
|
|
+ $profile = $this->getBuild()->generateBuildProfile();
|
|
|
+ file_put_contents($this->buildProfile, $profile);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ As noted, with module layers, you should only create the file once.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <sect3 id="zend.dojo.build-layers.profiles.options">
|
|
|
+ <title>Build Profile options</title>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ The above functionality will suffice for most situations. The
|
|
|
+ only way to customize build profile generation is to provide
|
|
|
+ additional build profile options to utilize.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ As an example, you may want to specify what type of
|
|
|
+ optimizations should be performed, whether or not to optimize
|
|
|
+ CSS files in the layer, whether or not to copy tests into the
|
|
|
+ build, etc. For a listing of available options, you should read
|
|
|
+ the <ulink url="http://docs.dojocampus.org/build/index">Dojo
|
|
|
+ Build documentation</ulink> and <ulink
|
|
|
+ url="http://www.dojotoolkit.org/book/dojo-book-0-9/part-4-meta-dojo/package-system-and-custom-builds">accompanying
|
|
|
+ documentation</ulink>.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ Setting these options is trivial: use the
|
|
|
+ <methodname>addProfileOption()</methodname>,
|
|
|
+ <methodname>addProfileOptions()</methodname>, or
|
|
|
+ <methodname>setProfileOptions()</methodname> methods. The first
|
|
|
+ method adds a single key/value option pair, the second will add
|
|
|
+ several, and the third will overwrite any options with the list
|
|
|
+ of key/value pairs provided.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ By default, the following options are set:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting role="javascript"><![CDATA[
|
|
|
+{
|
|
|
+ action: "release",
|
|
|
+ optimize: "shrinksafe",
|
|
|
+ layerOptimize: "shrinksafe",
|
|
|
+ copyTests: false,
|
|
|
+ loader: "default",
|
|
|
+ cssOptimize: "comments"
|
|
|
+}
|
|
|
+]]></programlisting>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ You can pass in whatever key/value pairs you want; the Dojo
|
|
|
+ build script will ignore those it does not understand.
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <para>
|
|
|
+ As an example of setting options:
|
|
|
+ </para>
|
|
|
+
|
|
|
+ <programlisting role="php"><![CDATA[
|
|
|
+// A single option:
|
|
|
+$build->addProfileOption('version', 'zend-1.3.1');
|
|
|
+
|
|
|
+// Several options:
|
|
|
+$build->addProfileOptions(array(
|
|
|
+ 'loader' => 'xdomain',
|
|
|
+ 'optimize' => 'packer',
|
|
|
+));
|
|
|
+
|
|
|
+// Or overwrite options:
|
|
|
+$build->setProfileOptions(array(
|
|
|
+ 'version' => 'custom-1.3.1',
|
|
|
+ 'loader' => 'shrinksafe',
|
|
|
+ 'optimize' => 'shrinksafe',
|
|
|
+));
|
|
|
+]]></programlisting>
|
|
|
+ </sect3>
|
|
|
+ </sect2>
|
|
|
+</sect1>
|