Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I tell Dojo build to ignore a 'missing' template

Tags:

build

dojo

Our application has a number of widgets that use templates that are generated on the fly via a JSP.

In the front-end code, they are included using the dojo/text plugin. This ensures that Widget lifecycle isn't kicked off until the template has been resolved and it works just fine.

Unfortunately, when we try to perform our build, we get a 311 error:

error(311) Missing dependency. module: app/navigation/NavigationManager; dependency: dojo/text!/author/app/templates/NavigationManager-content.html; error: Error: text resource (/author/app/templates/NavigationManager-content.html/x) missing

I understand what's happening here, the build process is trying to internalize the string, but when it goes to look for it, it can't locate it and so flags it as a missing dependency.

I see a number of options here:

  1. Somehow, tell Dojo to ignore this missing dependency - this would be fine, but I'd need to be able to be specific, so that I get alerted to any other dependencies that might be missing
  2. Somehow, tell Dojo not to try and internalize this template - this would also be fine, since there's nothing to internalize here.
  3. Somehow, stub out the dependency so that the dependency resolution passes, but the internalization doesn't occur.

I've seen references to the internStringsSkipList value, but none of the following helped:

internStringsSkipList: ['/author/pepper/templates/NavigationManager-content.html']
internStringsSkipList: ['dojo/text!/author/pepper/templates/NavigationManager-content.html']
internStringsSkipList: ['/author/pepper/templates/NavigationManager-content.html/x']

Any suggestions?

like image 972
Dancrumb Avatar asked Apr 29 '13 16:04

Dancrumb


1 Answers

I faced exactly the same problem and after reading lots of dojo documentation and source code I came to the conclusion that it's very difficult if almost impossible to do. There is, however, a very simple and elegant workaround. But before telling you how to solve the problem firstly why there is a workaround needed in the first place (so you can adjust the solution to your own circumstances):

First issue, the resource is undiscoverable

According to the Overview section of the dojo build system Reference Guide:

[The build system] “discovers” a set of resources and then applies a synchronized, ordered set of resource-dependent transforms to those resources. (…) When a resource is discovered, it is tagged with one or more flags that help identify the role of that resource. (…) After a resource is discovered and tagged, the system assigns a set of transforms that are to be applied to that resource.

So in short, any resources generated on the fly can't be discovered by the build system because they don't reside on the file system. If they can't be discovered, then they can't be tagged and no transformation can be applied to it. In particular, resourceTags is not called for such resources and you can't put them on the exclude list of a profile layer definition (compare section Layers in Creating Builds).

BTW, as far as I understand the documentation to depsScan transform, internStringsSkipList can only be used to skip resources specified using the legacy notation (dojo.something, e.g. dojo.moduleUrl).

Second issue, the plugin resolver expects a physical file

Notation dojo/text!/some/url says to use the dojo/text.js component as a plugin. I found this note in this ticket:

Every AMD plugin should have a plugin resolver in util/build/plugins and have it registered in util/build/buildControlDefault.

If you check util/build/plugins/text.js (e.g. on Github) you'll see that the error is being thrown because the dependency (that part after dojo/text! is stored in moduleInfo) is not in the resources array:

textResource = bc.resources[moduleInfo.url];
if (!textResource){
  throw new Error("text resource (" + moduleInfo.url + ") missing");
}

And this is precisely because the resource couldn't be discovered during the "discovery" phase.

The difficult solution

In the difficult solution, that might or might not work, you would need to change how the transformation depsScan works. Basically, when depsScan encounters dojo/text!/some/url it calls the plugin resolver to check if the dependency exists. From the depsScan documentation:

Once all dependencies are found, the transform ensures all dependencies exist in the discovered modules. Missing dependencies result in an error being logged to the console and the build report.

That might be possible by redefining transformJobs to contain a custom transform for depsScan. See util/build/buildControlDefault.js (on Github) and this forum post for more insights.

The simple workaround

Just create your own plugin to load the resource. Your own plugin won't have the plugin resolver registered (see the second issue above) and all you'll get when compiling is the dreaded

warn(224) A plugin dependency was encountered but there was no build-time plugin resolver.

This is my example of such plugin that loads a JSON resource dynamically:

define(["dojo/text", "dojo/_base/lang", "dojo/json"],
function(text,lang,json){
  return lang.delegate(text, {
    load: function(id, require, load){
      text.load(id, require, function(data){
        load(json.parse(data));
      });
    }
  });
});

It reuses dojo/text adding its custom load function. This is an adaptation of another example posted on this dojo-toolkit forum post. You can see their code on JSFiddle.

In my project I use the plugin like this:

define(["./json!/path/to/an/json"],
function(values){
  return values;
});

Your plugin can just return the loaded template without parsing it as JSON, and as long as you don't specify your custom plugin resolver (which would expect the file to exist physically on disk) the project will compile fine.

like image 164
Greg Avatar answered Nov 08 '22 02:11

Greg