[ALOY-743] Alloy: Add proper dynamic loading of namespace objects
GitHub Issue | n/a |
---|---|
Type | Improvement |
Priority | Medium |
Status | Closed |
Resolution | Fixed |
Resolution Date | 2013-07-18T17:39:44.000+0000 |
Affected Version/s | n/a |
Fix Version/s | Alloy 1.2.0, 2013 Sprint 15 |
Components | Runtime, XML |
Labels | alloy, compile, namespace, qe-testadded |
Reporter | Fokke Zandbergen |
Assignee | Tony Lukasavage |
Created | 2013-07-14T17:24:07.000+0000 |
Updated | 2013-07-22T23:21:39.000+0000 |
Description
The Alloy
ns
attribute can be used in a creative manner to load a CommonJS or native module to call the createTagName
method upon, since:
<MyComponent ns="require('my.module')" id="myId" />
Will compile to:
$.__views.myId = require('my.module').createMyComponent({ .. });
This works fine, but still feels hacky. I would propose to make a change to /Alloy/commands/compile/parsers/default.js
so that whenever a namespace is given like this:
<MyComponent ns="my.module" id="myId" />
The generated code would be:
if (typeof my.module === 'undefined') var myModule = require('my.module');
$.__views.myId = myModule.createMyComponent({ .. });
Attachments
File | Date | Size |
---|---|---|
Screen Shot 2013-07-18 at 1.09.50 PM.png | 2013-07-19T13:28:53.000+0000 | 16558 |
Here is the PR: https://github.com/appcelerator/alloy/pull/178
I'm not sure I want to do that right away. For one thing, how could you possibly make a distinction between a globally accessible namespace for creating components and a require()'ed module like you are accounting for? For example, what if this existed in the "app/alloy.js"?
I mention this condition because I've heard of people wanting to wrap Titanium functions and namespaces in their own calls and still leverage them through XML. I get that it feels "hacky", but there may need to be a more explicit way to do it. Perhaps bringing the "module" attribute over from the
I thought global scope access from CommonJS modules was deprecated? Don't really get your example. The only way to get an object in the controller scope is by requiring a CommonJS module right?
BTW, first line of last code snippet needs to be:
In the PR I also added support for doing
require('dir/my.module')
.No, its not deprecated. In fact, it's now supported on all platforms. That's why you can access the
Alloy
namespace in your lib commonjs modules without explicitly requiring it. In any case, I don't like the idea of strings behaving differently based on whether or not we've defined special handling under the hood. It's not terribly intuitive. If feel like this would be much more intuitive:Well I guess if you can access the global scope, all this is at most a nice 'service', but not required. One could just add this in
alloy.js
and then usens="myNamespace"
wherever they want?But of course this pollutes the global scope (that's why I thought access to global vars was deprecated anyway).
You could do it without polluting the global scope though via Alloy.Globals, but that's not ideal either. But back to the core issue here... I don't like the idea of generating more code where the generated JS is basically guessing whether or not you are using a module. I'd prefer a clear, explicit syntax. And for the
I think you're right and
Module
can do the job. I just want to ask for a small change that doesn't alter any of the current behavior of the test. I think this PR speaks for it self: https://github.com/appcelerator/alloy/pull/186 It fixes theAlloy.Module.js
parser currently not being used at all and as a result of fixing this and just a small change in thedefault.js
parser now:Just another small note. Why do we even need the
<Module />
tag? I think we can live with just themodule
andmethod
attributes, since already:[~fokke] there's a couple reasons for
It's expressive. It's very clear ata glance that a developer is referencing a native/commonjs module.
It changes the node name to "View". In the underlying native module system, the default function for creating an instance of a module is "createView". If you leave your instance creation as the default, then you don't need to specify a "method" attribute in the tag.
So it's just shorthand for common use cases. And as you stated, after all this dialog, this is probably doable already using the "module" and "method" functions. In fact, I'm going to put an example in the 1.2.0 repo that shows exactly how to do this. Will update when it's done.No code has been changed in Alloy as a result of this ticket, but I am able to (cleanly) add arbitrary UI components from commonjs modules via XML. These modules can make full use of TSS, inline styles, and XML eventing. To make it very clear how one should do this, I've added the following example app to the repo: PR: https://github.com/appcelerator/alloy/pull/187 example: https://github.com/appcelerator/alloy/tree/master/test/apps/advanced/commonjs_xml I think that answers pretty much all concerns we had to this point. Now for the sake of keeping the whole conversation tied together, I'm going to take a look at your latest PR [~fokke] and see what contained in it still needs to be addressed, if anything. PR: https://github.com/appcelerator/alloy/pull/186
Note: this PR and test is the result of discussion and aggregation of the aforementioned PRs. PR: https://github.com/appcelerator/alloy/pull/188 example app: https://github.com/appcelerator/alloy/tree/master/test/apps/advanced/commonjs_xml Functional testing should be confirmed on all supported platforms with the following steps:
Run the example app
Assert that all views presented in the XML are present in the app. It should look roughly like the attached screenshot
Click the views with the "click me" labels and ensure that they open an alert dialog
Verified as working as expected. Environment: Titanium SDK 3.1.2.v20130718094558 Appcelerator Studio 3.1.2.201307191853 Alloy 1.2.0 LiveView 0.1.28 (from Beta stream) Android device 4.2.2 - iPhone 5 6.1.4 Closing.