How do I make a build profile reference modules that are within a "black box" library layer? - dojo

The tutorials got me going with the Dojo build system. However I'm left with a question that'll make or break the possibility of deploying a fully built release in my case. It is possible that the tutorial explains it, but that I didn't get it. Apologies if that was the case !
I use a library that lives inside an AMD layer ; let's call it blackboxLayer.js. There are several packages inside that layer, but I suppose the question would be the same if there was only one. So let's say that blackboxLayer.js contains a single package called blackbox, with modules blackbox/A and blackbox/B. To be sure that things are fun, that layer is bootable. And of course it's closed source stuff.
My app modules reference blackbox/A or blackbox/B. How do I make my build profile go look for the blackbox package inside that blackboxLayer.js file, rather than in a directory ?
Thanks for any input. :)

If built file blackboxLayer.js is in relative path /release/blackbox/layers, there is a separate dojo layer
<script type="text/javascript" src="path to dojoLayer.js"></script>
and
var dojoConfig = {
packages: [
{ name: 'blackbox', location: 'release/blackbox' }
]
};
then code inside this function can reference modules A and B,
require(['blackbox/layers/blackboxLayer'],
function () {
require(['dojo/parser', 'dojo/ready'],
function (parser, ready) {
ready(function () {
require(['blackbox/A', 'blackbox/B'],
function (blackboxA, blackboxB) {
// call blackboxA and blackboxB
});
});
});
});
If there is no separate dojo layer, you can reference blackboxLayer.js in the script tag, and omit the package def and requiring blackboxLayer.

The interim solution I've been using since this question has been posted is NOT to use dojo's builder... Instead I use a lightweight grunt pattern that concatenates AMD sources into a layer, and then I reference the layer from dojoConfig's deps property. The concatenation process is visible here : https://github.com/gruntjs-updater/grunt-amd-concat

Related

testing existing pages with mocha-phantomjs

I'm not quite getting how to use PhantomJS and Mocha together, specifically through mocha-phantomjs.
I've read some tutorials (the one at tutsplus is quite helpful) and am not seeing how I can test external pages using Phantom and Mocha. I'm sure I just need a nudge.
In the tutorial the author creates a tests.js file with some DOM setup/manipulation, as well as some mocha assertions. Then, he creates a separate HTML file that loads the tests.js file and uses mocha-phantomjs to fire up phantom and run the tests.
That's where I'm a little confused, how the mochaPhantomJS.run() method actually does things behind the scenes, whether it knows to search the js file for a describe block and run all tests within, that sort of thing. I don't need chapter and verse, but a high-level summary would be ideal.
Also, if I want to test an outside page, how can I best do that? In the tutorial all the DOM investigation and testing is done on the test page. If I want to test a different page, do I change or setup my assertions differently? Should I call the PhantomJS API from those tests and point to an external site?
Mocha will run tests that have been specified in javascript that has been included in the html page that is launched. If you look at the example html page on mocha-phantomjs it expects the test definitions using describe/it calls to be in the test/mycode.js file. If you put something like
These tests are only testing what is in the main file and associated javascript, there isn't anything special that mocha-phantomjs provides to test external html files. If you want to test your own html files I think you can head in a couple of directions, I came up with these:
first option: Create a way to load the parts of you app that you want to test into the main testing html file. How to do this depends a lot on your application setup. It is probably well-suited for a modular system. Just include the javascript from your application and test it. Not so good for full-page-html tests.
second option: Open new windows with the pages to test from the main testing html file (from within phantom that is). You can open a page using window.open() just like a normal browser. I created a proof of concept like this:
describe('hello web', function () {
it('world', function (done) {
var windowReference = window.open("fileundertest.html");
// windowReference.onload didn't work for me, so I resorted to this solution
var intervalId = window.setInterval(function () {
if (windowReference.document && windowReference.document.readyState === 'complete') {
window.clearInterval(intervalId);
expect(windowReference.document.title).to.equal("File Under Test");
done();
} else {
console.log('not ready yet');
}
}, 10);
});
}
)
This solution is relatively simple, but has the same drawbacks as any page-loading solution: you never know when the page is fully initialized and have to resort to some sort of timeout/wait system to wait for the page to get into the correct state. If you want to test a lot of separate html files these delays start to add up. Additionally waiting for 'onload' on the page that I opened wouldn't work so I created my own function based on setInterval and a (non-perfect) test on the document that was being loaded. I found out there are differences in behavior between loading an html page from the filesystem and loading the same page via a web-server.
third option: Create a mocha test that you run nodejs-style from the command line, and launch phantomjs with a specific page as part of your mocha tests. This is what I'd say you need if your system really depends on html pages that are quite different from each other.
I quickly tested the third option, here is my test based on the example I found on the phantom page (which is an alternative solution to phantomjs that is used by mocha-phantomjs -- I've used neither for more than brief experiments so I cannot recommend which one to use)
'use strict';
var chai = require('chai'),
phantom = require('phantom');
var expect = chai.expect;
describe('hello node', function () {
it('world', function (done) {
phantom.create(function (ph) {
ph.createPage(function (page) {
page.open("http://www.google.com", function (status) {
console.log("opened google? ", status);
page.evaluate(function () { return document.title; }, function (result) {
console.log('Page title is ' + result);
ph.exit();
expect(result).to.equal("Google");
done();
});
});
});
});
});
}
)
While it is possible to test this way I'd say that maybe the overhead of the communication between the code in the phantom-world and the testing code in the nodejs world isn't worth it. You can of course move a lot of general functionality to a couple of helper functions, but you are still stuck with having to call page.evaluate() to perform specific tests on the page. The same issues with timeouts/waits as above apply.
As an aside: do already know CasperJS? Maybe it can be helpful for your setup should you choose to build something on 'plain' phantomjs.

Setting class when calling createLabel

I'm using Titanium Studio and Titanium SDK. In this case I'm developing for Android but I have an installation on OSX too.
When using Alloy, I can specify
<Label class="header" id="someId">Week 50</Label>
and then specify the colors,fonts etc in the TSS file like this
".header": {
color: "blue"
}
However when I use the SDK version:
var l = Ti.UI.createLabel({class:"header", text:"sometext"});
The color from the TSS file isnt picked up???
What am I doing wrong. Isn't 'class' a valid property? (I cant seem to find it in the docs).
Alloy style are applied automatically to views created through xml. If you want to keep that effect while you are creating objects inside controller you have to use $.UI.create() method instead of Titanium API. In your case your code will look like this:
var l = $.UI.create('Label', {
title: "sometext",
classes: ["header"],
});
For more read Dynamic Styles guide. It's not very well documented and some parts of it were unclear for me when I read it but it's good starting point to experiment with the code and learn Alloy behaviour.
Encountered you question while I was searching for something similar. The chosen answer was unfortunately not the solution I was looking for, since I was writing a commonJS and needed the same this. If you are writing a commonJS (but still under an Alloy project) you can use the following solution:
var l = Alloy.UI.create("index", "Label", {
title: "sometext",
classes: ["header"],
});
Where "index" is what being generated by Alloy from you app.tss file.

How to include legacy module in Dojo AMD

I'm trying to migrate an application from dojo 1.6 to version 1.9.1, and I've a legacy module that I didn't want to migrate yet (it's pretty complex and will take me some time to understand). The Dojo docs indicate you can load legacy modules along with AMD modules, but when I try, I'm getting a "dojo.provide is not a function" when the loader tries to load the legacy module.
My script:
require([..., "agsjs/dijit/TOC","dojo/domReady!"],
function(..., TOC) {
on(map,'layers-add-result',function(results){
//Add Legend
var toc = new TOC({
map: map,
layerInfos:legendLayers
}, 'legendDiv');
toc.startup();
});
});
The first line of code of the module:
dojo.provide('agsjs.dijit.TOC');
Everything works until the loader tries to load the agsjs/dijit/TOC module, where I get a "dojo.provide is not a function" error. How do I solve this without having to refactor the entire module to AMD? Thanks
In order for legacy modules to load, you need to run the loader in legacy mode, which means you cannot set async: true. As long as you are running with async: false (the default), you will be able to load and use legacy modules from AMD modules, and vice-versa.
A good point of AMD is that you don't have to use "dojo" and "dijit" global variables now. If you don't want change all those dojo.xxx calls in your old modules, you may try to wrap you old module in a
define([
"dojo/_base/declare",
"dojo", "dijit",
...
], function(declare, dojo, dijit) {
return declare([/*your parent widgets*/], {
//your old module content at here, maybe you need make little modifications of your old module
});
});
So that those dojo.xxx functions may still works.
This link may provide everything you need:
http://dojotoolkit.org/reference-guide/1.9/releasenotes/migration-17.html

Dojo 1.9 build 'multipleDefine' error while loading locale

My dojo application breaks after building, during loading the app, throwing 'multipleDefine' and giving this error:
Error {src: "dojoLoader", info: Object}
Message: multipleDefine
info: Object {pid: "dojo", mid: "dojo/nls/dojo_en-us", pack: Object,
url: "dojo/nls/dojo_en-us.js", executed: 5…}
Here is my profile:
var profile = {
// `basePath` is relative to the directory containing this profile file; in this case, it is being set to the
// src/ directory, which is the same place as the `baseUrl` directory in the loader configuration. (If you change
// this, you will also need to update run.js.)
basePath: '../src/',
// This is the directory within the release directory where built packages will be placed. The release directory
// itself is defined by `build.sh`. You should probably not use this; it is a legacy option dating back to Dojo
// 0.4.
// If you do use this, you will need to update build.sh, too.
// releaseName: '',
// Builds a new release.
action: 'release',
// Strips all comments and whitespace from CSS files and inlines #imports where possible.
//cssOptimize: 'comments',
// Excludes tests, demos, and original template files from being included in the built version.
mini: true,
// Uses Closure Compiler as the JavaScript minifier. This can also be set to "shrinksafe" to use ShrinkSafe,
// though ShrinkSafe is deprecated and not recommended.
// This option defaults to "" (no compression) if not provided.
optimize: '',
// We're building layers, so we need to set the minifier to use for those, too.
// This defaults to "shrinksafe" if not provided.
//layerOptimize: 'closure',
layerOptimize: '',
// Strips all calls to console functions within the code. You can also set this to "warn" to strip everything
// but console.error, and any other truthy value to strip everything but console.warn and console.error.
// This defaults to "normal" (strip all but warn and error) if not provided.
stripConsole: 'all',
// The default selector engine is not included by default in a dojo.js build in order to make mobile builds
// smaller. We add it back here to avoid that extra HTTP request. There is also a "lite" selector available; if
// you use that, you will need to set the `selectorEngine` property in `app/run.js`, too. (The "lite" engine is
// only suitable if you are not supporting IE7 and earlier.)
selectorEngine: 'acme',
//localeList:"en-gb,en-us,de-de,es-es,fr-fr,it-it,pt-br,ko-kr,zh-tw,zh-cn,ja-jp",
// Builds can be split into multiple different JavaScript files called "layers". This allows applications to
// defer loading large sections of code until they are actually required while still allowing multiple modules to
// be compiled into a single file.
layers: {
// This is the main loader module. It is a little special because it is treated like an AMD module even though
// it is actually just plain JavaScript. There is some extra magic in the build system specifically for this
// module ID.
'dojo/dojo': {
// In addition to the loader `dojo/dojo` and the loader configuration file `app/run`, we are also including
// the main application `app/main` and the `dojo/i18n` and `dojo/domReady` modules because, while they are
// all conditional dependencies in `app/main`, we do not want to have to make extra HTTP requests for such
// tiny files.
include: [ 'dojo/i18n', 'dojo/domReady', 'app/main', 'app/run' ],
// By default, the build system will try to include `dojo/main` in the built `dojo/dojo` layer, which adds
// a bunch of stuff we do not want or need. We want the initial script load to be as small and quick to
// load as possible, so we configure it as a custom, bootable base.
boot: true,
customBase: true
},
},
// Providing hints to the build system allows code to be conditionally removed on a more granular level than
// simple module dependencies can allow. This is especially useful for creating tiny mobile builds.
// Keep in mind that dead code removal only happens in minifiers that support it! Currently, only Closure Compiler
// to the Dojo build system with dead code removal.
// A documented list of has-flags in use within the toolkit can be found at
// <http://dojotoolkit.org/reference-guide/dojo/has.html>.
staticHasFeatures: {
// The trace & log APIs are used for debugging the loader, so we do not need them in the build.
'dojo-trace-api': 0,
'dojo-log-api': 0,
// This causes normally private loader data to be exposed for debugging. In a release build, we do not need
// that either.
'dojo-publish-privates': 0,
// This application is pure AMD, so get rid of the legacy loader.
'dojo-sync-loader': 0,
// `dojo-xhr-factory` relies on `dojo-sync-loader`, which we have removed.
'dojo-xhr-factory': 0,
// We are not loading tests in production, so we can get rid of some test sniffing code.
'dojo-test-sniff': 0
}
}
and here is the index.html inside src/
NOTE: build.sh is responsible for removing the "isDebug" flag when
deploying to production. If you modify this flag at all, you will
break the build!
<script data-dojo-config="async: 1, tlmSiblingOfDojo: 0, locale:'en_US', isDebug: 1" src="dojo/dojo.js"></script>
<!-- Load the loader configuration script. Note that this module ID is hard-coded in build.sh in order to provide
an optimised build that loads as few as one script for the entire application. If you change the name or
location of this module, you will need to update build.sh too. -->
<script src="app/run.js"></script>
this is the generated index.html in dist/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="app/resources/app.css">
</head>
<body class="claro">
<script data-dojo-config=
"async: 1, tlmSiblingOfDojo: 0, locale:'en_US', deps:['app/run']"
src="dojo/dojo.js"></script>
</body>
</html>
I checked to make sure that dojo/nls/dojo_en-us.js exists and it is fine. I am stuck at this point, having no clue!
Any help to fix this problem is appreciated.
Can you post your requires in run.js ?
Did you require "dojo/_base/config" there ?
[ just noticed the same error because I forgot it ;) ]
from the docs:
It is important to note the distinction between dojoConfig and dojo/_base/config. dojoConfig is purely for input purposes—this is how we communicate configuration parameters to the loader and modules. During the bootstrap process, dojo/_base/config is populated from these parameters for later lookup by module code.
I had a similar issue with error
multipleDefine
when trying to include greensock library to my dojo project.
The issue appears when another library outside dojo declared its own define function (in my case was TweenMax) as they clash with dojo loader.
A solution is to make sure dojo loader is called after your library or script which use a define function have loaded.
So dojo should be the latest in your script to load in the html head:
<head>
<script src="yourLibrary.js"></script>
<script src="dojo/dojo.js"></script>
</head>
This problem is also visible using jQuery UI and other libraries.
There is a note about this in the loader documentation (at the time of this response anyway).
multipleDefine
AMD define was called referencing a module that has
already been defined. The most common cause of this problem is loading
modules via elements in the HTML document. Use the loader;
don't use elements. The second most common cause is passing
explicit module identifiers to define; don't do this either.
https://dojotoolkit.org/reference-guide/1.10/loader/amd.html
Many libraries now implement UMD which will basically try to auto-detect the existence of an AMD loader. For example, Bootstrap - the popular front-end framework - implements UMD.
So the following example will work (note that bootstrap will load globally):
<script src="path/to/bootstrap.js"></script><!--UMD packaged library-->
<script src="path/to/dojo/dojo.js"></script><!--then dojo loader-->
but the second example below will not work, since the UMD code will detect the AMD loader and use that to register itself. This will trigger the multipleDefine error as per the documentation.
<script src="path/to/dojo/dojo.js"></script><!--dojo loader first-->
<script src="path/to/bootstrap.js"></script><!--then UMD library-->
If you want to load the library globally use the first example above and load it bofore the dojo loader. If you want to load the library as an AMD module, use the loader.

dojo require different js files

recently I have a problem about including other js files using dojo. e.g. :
In my 1.js file, I wrote:
require(["dijit/form/Button"], function(Button){
addButton(someWidget);});
and in my 1a.js file, I wrote the function addButton:
function addButton(target){
var b1=new Button({
style: "border: 1px solid green",
label: "xxxxx"
});
target.addChild(b1);
return b1;
}
for 1a.js there must be an error, because I did not require that module, but i add require, the biggest
problem is that returned value, I can not get the return value, because of nested funciton.
how can i wrote a js file, which i wrote all my functions, and in another js file, i just call these functions with dojo require("xxxx", function(x){})
Thanks for help!
dojo.require is the legacy (<=1.6) loader for the toolkit. Using dojo.require in one file, made the code available to all files.
Dojo has moved to using the AMD API for loading modules. In 1a.js, you will also need to add the require statement.
My answers to the following questions will provide a better understanding of the AMD API and the require statement:
What is the main difference between require() and define() function in dojo and when would we use either?
Dojo Builds...? What now?
What is the purpose of function in the dojo require?