| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <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 <acronym>CSS</acronym> minification.
- </para>
- <para>
- In order to create a build layer, you would traditionally create a
- JavaScript file that has <command>dojo.require</command> statements for
- each dependency, and optionally some additional code that might run
- when the script is loaded. As an example:
- </para>
- <programlisting language="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 language="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 language="php"><![CDATA[
- $view->dojo()->registerModulePath('custom', '../custom/')
- ->requireModule('custom.main');
- ]]></programlisting>
- <para>
- But since <classname>Zend_Dojo</classname> aggregates your various
- <command>dojo.require</command> statements, how do you create your layer
- script? You could open each page and view the generated
- <command>dojo.require</command> 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
- "<filename>custom.main</filename>". 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 language="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 (!file_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 <methodname>dojo()</methodname> helper is fully populated. One
- easy way to do so is using a front controller plugin, with a
- <methodname>dispatchLoopShutdown()</methodname> hook:
- </para>
- <programlisting language="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()
- {
- $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(
- 'ViewRenderer'
- );
- $viewRenderer->initView();
- if (null === $this->_build) {
- $this->_build = new Zend_Dojo_BuildLayer(array(
- 'view' => $viewRenderer->view,
- 'layerName' => 'custom.main',
- ));
- }
- return $this->_build;
- }
- public function generateDojoLayer()
- {
- $build = $this->getBuild();
- $layerContents = $build->generateLayerScript();
- if (!file_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 language="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 language="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>
- <command>dojo.addOnLoad</command> is a useful utility for
- specifying actions that should trigger when the <acronym>DOM</acronym> has
- finished loading. The <methodname>dojo()</methodname> 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
- <property>consumeOnLoad</property> configuration key during
- instantiation:
- </para>
- <programlisting language="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 language="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 <methodname>dojo()</methodname> view helper includes methods for
- capturing arbitrary JavaScript to include in the
- <script> tag containing the various
- <command>dojo.require</command> and <command>dojo.addOnLoad</command>
- 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
- <property>consumeJavascript</property> configuration key during
- instantiation:
- </para>
- <programlisting language="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 language="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 language="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 language="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
- <acronym>CSS</acronym> 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://dojotoolkit.org/reference-guide/dojo/index.html#package-system">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 and value option pair, the second will add
- several, and the third will overwrite any options with the list
- of key and value pairs provided.
- </para>
- <para>
- By default, the following options are set:
- </para>
- <programlisting language="javascript"><![CDATA[
- {
- action: "release",
- optimize: "shrinksafe",
- layerOptimize: "shrinksafe",
- copyTests: false,
- loader: "default",
- cssOptimize: "comments"
- }
- ]]></programlisting>
- <para>
- You can pass in whatever key and 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 language="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>
|