dojo/parser

Ok, what is becoming a bit of a trend, I am adding a third to my series on forthcoming features in Dojo core in 1.8.  I have already covered dojo/promise and dojo/request, now I am going to cover changes to dojo/parser.  This is something I am quite passionate about, since I had my hand directly involved in the features that were added, with lots of help from Bill Keese and Ben Hockey (and others).

With the full conversion to AMD in 1.7, there were likely a few features that made the declarative syntax a bit more challenging to use, versus the programmatic syntax.  While the programmatic approach to Dojo is usually a better way of creating applications, the declarative way is very popular with developers, great for prototyping and a quick way to get started with Dojo, especially when using the Dijit package of widgets.

For those not familiar with programmatic, versus declarative syntax, here is a quick example of creating a Dijit button and making it log something to the console when clicked.  First here is how we would do it programatically:

Now the same HTML snippet done declaratively:

The declarative syntax is then converted by the dojo/parser into instantiated widgets, essentially converting your decorated HTML code into programmatic code.  It does the heavy lifting for you, so you don’t have to keep managing the nodes in your document for all your widgets.

Now for the improvements in 1.8.  The first was that you could only specify the class in declarative syntax using a global class name (the old way, dot notation, e.g. dijit.form.Button).  With AMD and the deprecation of Dojo declaring classes in the global namespace, this was starting to become a problem.  So now the dojo/parser accepts the Module ID (MID) as the type (e.g. dijit/form/Button).  In fact this is now the preferred way of referring to a object type in declarative markup.  For example, our button from above should be:

The second added feature is to bring the declarative scripting fully capable with the introduction of dojo/aspect as the preferred way of modifying the behaviour of an instance in Dojo.  dojo/aspect supports the semantic concepts of before, around and after which are part of Aspect Oriented Programming (AOP).  Now the declarative scripting supports those as well, so you can do the following:

Now for the “cool” feature, but which could easily cause quite unintended consequences, is something called auto-require.  This caused a lot of debate within the Dojo developer community, mostly because you don’t have to be explicit about your requirements with your declarative scripting.  Basically if the dojo/parser encounters a MID that isn’t loaded, it will attempt to load it for you.  It makes things easier, but it can mask problems and may cause a lot of negative impact on performance when using built layers that may not contain all the right modules.  At the end of the day though we thought it was useful enough to be included.  Without it, you would have had to require all your modules used in your declarative markup before invoking the parser, which would have looked something like this for our button:

[notice]It is still better, since 1.7 to manually invoke the parser.parse() instead of using parseOnLoad in dojoConfig.[/notice]

Another new feature which fits well in the world of AMD is a declarative require.  This allows you to require in modules without having to do it within a JavaScript code block in your code.  What it essentially does, is allow you to load modules and map them into the global namespace.  A declarative require is a <script> block that contains a JavaScript object that defines the mapping of the modules and would look like this:

Because of the auto-require and declarative require use Dojo’s loader (via require()) and require() operates in an async fashion, it has meant that dojo/parser now operates in a async fashion.  Historically the .parse() function returned an array of instantiated widgets.  For backwards compatibility reasons .parse() still returns an array, but it also behaves like a promise too.  When the parser does not need to use auto-require or declarative require or Dojo loader is running in sync mode, this array will be populated with the instantiated objects.  When it is running in an async fashion, the array will be empty but the promise will be resolved with an array of objects.

For new development it is best to ensure you treat parser.parse() as if it is always running in an async fashion.  So if you need access to the instantiated objects or if you need to do something once the .parse() is finished, you should do something like this:

One piece that I am still working as I write this is to get the Dojo builder to be able to analyse your HTML resources for a build, understand the dependencies in the marked up code and allow you to build that into your built Dojo or a layer.  Hopefully this will help people avoid some of the issues that could occur if they just used features like auto-require without thinking about the consequences.

There is a lot of “good” stuff in the dojo/parser in 1.8 that makes it more “modern” like other parts of Dojo.  Hopefully for those who use it, these features will help you take advantage of a modern Dojo and feel “left behind”.

2 thoughts on “dojo/parser

  1. Huh? Why is manually invoking the parser “better”? People are used to setting parseOnLoad:true and it’s basically the same identical logic (i.e. parser is fired when ready fires).

    In the first button on click example, does that even work? You never specified the event to bind to. How does the parser know to wire up the click event? Makes no sense.

    I’m not a fan of all this tag abuse. In the block, it’s unintuitive and error prone to write JSON-like syntax minus the curly braces. It’s fine in an attribute, but that’s a different context.

    I’m saddened that Dojo is getting bloated with all this garbage. There’s no reason the parser needs to be over 800 lines of code. I bet half of that code can be externalized into separate modules and pulled in if needed. Same holds true for the Promise/Deferred implementation and probably a bunch of other stuff that snuck into core.

    1. The reason is that it is better is because of the nature of AMD. While the dojo/parser, with parseOnLoad: true will fire when the document during the ready (as you noted), it isn’t guaranteed to fire before any required modules you may want to load prior to the invoking the parser occur, especially when the loader is running async. The only way to avoid this is by explicitly invoking the parser in the callback of your require.

      I apologise for the mistake, you are right, I missed the event in the <script> tag. Trying to write code in your head isn’t always the best way. I will correct that.

      Actually, there is good reason the dojo/parser is as big as it is… most of the code in there is for backwards compatibility, dealing with mapping attributes, in particular for IE, which goes back quite a ways in Dojo. Also there is a good chunk of code dealing with inheritance of DOM attributes like lang and dir. It is strange that your feeling is that Dojo is getting more bloated, when in fact with the move in recent releases, including 1.8, it has been getting more modularised and less and less is in the base and while there is an increasing level of modules in the Core, they are optional. For example, there are the dojo/dom* modules, which break out the whole DOM manipulation API.

      We looked at making the dojo/parser “pluggable” and extensible for 1.8. It was tabled because of concerns around the overhead of making it available. Again, parser is biggish, but a lot of it is to try to ensure it as performant as possible.

      Very few things (if any) sneak into core.

Comments are closed.