-
Notifications
You must be signed in to change notification settings - Fork 0
Aspects
To follow along with this section, start with tag v2.0.11
.
The pedestal-app development tools are themselves just a Clojure web application and can easily be modified to meet the specific needs of a project.
The Tools menu contains several links which allow you to view and work with the application in different ways. Each of these "ways" is called an aspect because it allows you to focus on one part of the application in isolation.
- Data UI - run application logic without a renderer and with a simulated back-end
- Render - render without running application logic
- Development - run everything in development mode
- Production - run everything with advanced compilation
In this section you will see that it is easy to add new custom aspects.
It would good to have a new aspect that combined the simulated back-end with the custom renderer. This would allow you to see and interact with a more realistic version of the application without having to run a service and simulate activity from multiple browsers.
To add an aspect, open the configuration file for the project.
tutorial-client/config/config.clj
This is a Clojure file with a var named configs
. Within this
configuration map is an :aspects
key associated with a map
containing each aspect.
The new aspect will have the key :ui
and is shown below.
:ui {:uri "/tutorial-client-dev-ui.html"
:name "UI"
:order 2
:out-file "tutorial-client-dev-ui.js"
:main 'tutorial_client.simulated.start
:recording? true
:logging? true
:output-root :tools-public}
Most of this configuration is straight forward. You give the aspect a unique URI, name and the order in which it will appear in the tools menu. You also provide a name for the JavaScript output file. Special flags can be set to enable recording or logging for each aspect.
As you can see in other aspects, the optimization level for each
aspect can be set using the :optimizations
key. Each aspect can also
have a :compiler-options
key with a map as value. The compiler
options map will passed along to the ClojureScript compiler.
The :output-root
key determines where compiled output will be
written on the file system. There are two possibilities: :public
and
:tools-public
. :public
will put compiled output into out/public
and :tools-public
will compile output to out/tools/public
. Because
this aspect is only used for development and will not be deployed, we
compile output to :tools-public
.
The main thing that makes each aspect different is the main
function
which is run to start the application. Each main
function will wire
things together in a different way. In the config file you will notice
that the :data-ui
aspect starts from
tutorial_client.simulated.start
while the :development
and
:production
aspects start from tutorial_client.start
. These are
namespaces which contain a function named main
.
The new :ui
aspect will use the same starting point as the
:data-ui
aspect.
If you were to restart the server, you would see that there is now a
new aspect named UI that is exactly the same as the Data UI
aspect. They are the same because they have the same starting
point. You could make a new starting point but the only difference
between these two aspects is the renderer which will be used. It would
be better to update the main
function in
tutorial_client.simulated.start
to dynamically select the renderer
based an a URL parameter.
To cause an aspect to send a parameter, add a :params
key. Add the
following key and value to the :data-ui
aspect.
:params "renderer=auto"
You can now restart the server to test that the two aspects work and the new parameter is being sent when you use the Data UI aspect.
In the namespace tutorial-client.simulated.start
, add the following
new required namespaces.
[tutorial-client.rendering :as rendering]
[goog.Uri :as guri]
Update the main function to choose the renderer to use based on the
value of the renderer
parameter in the URL. The updated version of
main
is shown below.
(defn ^:export main []
(let [uri (goog.Uri. (.toString (.-location js/document)))
renderer (.getParameterValue uri "renderer")
render-config (if (= renderer "auto")
d/data-renderer-config
(rendering/render-config))
app (start/create-app render-config)
services (services/->MockServices (:app app))]
(app/consume-effects (:app app) services/services-fn)
(p/start services)
app))
If you now refresh the browser, you will see that the Data UI aspect uses the data renderer while the UI aspect now uses the custom renderer. Both aspects use the same simulated back-end so you can now see updates to the other counters in the custom renderer.
This technique of selecting a renderer at runtime based on parameters can be very useful. It could be used for A/B testing or for incrementally releasing a new renderer or for selecting completely different renderers based on the device type.
You have created a working client. It is now time create a service. In the next section you will build a simple service for the client to talk to. In the section after that you will connect to the server and have a completely working interactive counter application.
If you not interested in creating the service code, checkout tag
v2.0.13
and skip to Connecting to the Service.
The tag for this section is v2.0.12
.