{ "id": "80921", "key": "TIMOB-5406", "fields": { "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [ { "id": "12086", "description": "", "name": "Sprint 2011-46", "archived": true, "released": true, "releaseDate": "2011-11-21" }, { "id": "12580", "description": "Dual Runtime 1.8.0", "name": "Release 1.8.0.1", "archived": true, "released": true, "releaseDate": "2011-12-22" } ], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2011-11-21T08:05:15.000+0000", "created": "2011-10-03T14:13:00.000+0000", "priority": { "name": "High", "id": "2" }, "labels": [ "parity" ], "versions": [ { "id": "11331", "description": "", "name": "Release 1.8.0", "archived": true, "released": true, "releaseDate": "2011-10-31" } ], "issuelinks": [ { "id": "12973", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "outwardIssue": { "id": "79688", "key": "TIMOB-5123", "fields": { "summary": "Android: CommonJS Modules not included/functional in distribution build", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "Critical", "id": "1" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } } ], "assignee": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "updated": "2014-06-19T12:46:31.000+0000", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [ { "id": "10202", "name": "Android", "description": "Android Platform" } ], "description": "Sample code:\r\n\r\n{code}\r\n// app.js\r\nvar testmodule1 = require('testmodule');\r\nTi.API.info('TEST MODULE 1 TEST: ' + testmodule1.someprop); // This will be undefined\r\n\r\n// Module\r\n// This doesn't work\r\nexports = {\r\n someprop: 'coolbeans'\r\n};\r\n{code}", "attachment": [], "flagged": false, "summary": "Android: commonjs exports object is undefined in some cases", "creator": { "name": "rblalock", "key": "rblalock", "displayName": "Rick Blalock", "active": false, "timeZone": "America/Havana" }, "subtasks": [], "reporter": { "name": "rblalock", "key": "rblalock", "displayName": "Rick Blalock", "active": false, "timeZone": "America/Havana" }, "environment": "Android 2.2 emulator", "comment": { "comments": [ { "id": "168022", "author": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "updateAuthor": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "created": "2011-10-05T09:40:52.000+0000", "updated": "2011-10-05T09:40:52.000+0000" }, { "id": "169612", "author": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "body": "I'll grant that mine was a liberal reading of the CommonJS spec, but they shouldn't have called {{exports}} a free variable in the spec if it actually wasn't one (I think I am in the right on the Math/CS definition of free variable). In practice {{module.exports = {};}} is non-standard, but it serves to address the lack of direct assignment to {{exports}}, which is either a flaw in either the spec or in many implementations of it, depending on your opinion.\r\n\r\nSo, do we suffer a flaw in the spec because that's what we think the spec dictates? Or do we provide a workable solution for users? I vote for the latter. This:\r\n\r\n{code:javascript|title=MyObject.js}\r\nfunction MyObject() {}\r\nexports.MyObject = MyObject;\r\n{code}\r\n\r\n{code:javascript|title=consumer.js}\r\nvar MyObject = require('MyObject').MyObject;\r\n{code}\r\n\r\nis a clumsy implementation. I don't think module.exports is the right answer, though, because it introduces another magical variable that has no place in the spec. A common sense approach would be to allow direct assignment to the exports object.\r\n\r\n{code:javascript|title=MyObject.js}\r\nfunction MyObject() {}\r\nexports = MyObject;\r\n{code}\r\n\r\n{code:javascript|title=consumer.js}\r\nvar MyObject = require('MyObject');\r\n{code}\r\n\r\nTo view the issue from a parity standpoint, do we want to take away a useful feature from one platform because we don't think it's standard? If it's not a maintainable solution on the Android side then maybe we do, but that's too bad.\r\n\r\nSidenote: @Bill your mother is considered homely by many.\r\n", "updateAuthor": { "name": "kwhinnery", "key": "kwhinnery", "displayName": "Kevin Whinnery", "active": true, "timeZone": "America/Chicago" }, "created": "2011-10-18T13:41:42.000+0000", "updated": "2011-10-18T13:41:42.000+0000" }, { "id": "169626", "author": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "body": "I know, she totally fooled Dad somehow. :)\r\n\r\nWe're transitioning into using node.js's commonjs implementation (via the V8 team -- though it will be available for both V8 and Rhino AFAIK). So I imagine module.exports will automatically become available, since that's a node.js thang. So we can wait and see on that. Meanwhile this can just stay open till we can test the newer implementation.", "updateAuthor": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "created": "2011-10-18T15:03:12.000+0000", "updated": "2011-10-18T15:03:12.000+0000" }, { "id": "173468", "author": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "body": "Since we're now using node.js's module implementation, we support {{module.exports = \\{ ... \\};}}, which is functionally equivalent to what is desired here.", "updateAuthor": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "created": "2011-11-21T08:05:15.000+0000", "updated": "2011-11-21T08:05:15.000+0000" }, { "id": "173469", "author": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "body": "So the test case would be:\r\n\r\n{code:title=app.js}\r\n// app.js\r\nvar testmodule1 = require('testmodule');\r\nTi.API.info('TEST MODULE 1 TEST: ' + testmodule1.someprop); // This should show 'coolbeans'\r\n{code}\r\n\r\n{code:title=testmodule.js}\r\nmodule.exports = {\r\n someprop: 'coolbeans'\r\n};\r\n{code}", "updateAuthor": { "name": "billdawson", "key": "billdawson", "displayName": "Bill Dawson", "active": true, "timeZone": "Europe/Berlin" }, "created": "2011-11-21T08:06:10.000+0000", "updated": "2011-11-21T08:07:20.000+0000" }, { "id": "174004", "author": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "body": "Hi. :)\r\n\r\n\r\nJust to add a bit more explanation to this discussion.\r\n\r\n\r\nI would like to explain why object can't be assigned directly to the \"export\" variable. The problem lies in some JS environments that can implement CommonJS (browser to be precise). In browser, scripts loaded via dynamically created script tag are evaluated in global scope. Because of that, module scope has to be improvised by creating new function scope that wraps module's source code and in which \"exports\" and \"require\" variables are injected via function parameters. Basically, after wrapping of module's source code this is created:\r\n\r\n\r\n{code}\r\nfunction(require, exports) {\r\n //loaded module's source code\r\n}\r\n{code}\r\n\r\nwhere \"require\" is a function (that loads dependencies) and \"exports\" is basically empty object - {} to which API is added. Changes to that object needs to be reflected on external object injected to that function because in module's wrapper function there is no return statement. And here the problem with assigning object (or anything else) directly to \"exports\" variable lies. If anything would be directly assigned to the \"exports\" variable, that change would not be reflected on the external object (because object are passed by the copy of reference, so \"exports\" variable contains reference copy of external object and changing what that variable points at, does not change that external object or other references to that external object). \"module.exports\" is a workaround actually.\r\n\r\n\r\nThat said, I think you should be careful with CommonJS implementation in Mobile SDK's if you want Ti-related source code to work in browsers (or Mobile Web SDK's) - code portability is basic idea of CommonJS. Also, my bug report regarding global variables in CommonJS also suffers from similar problem.\r\n\r\n\r\nAnyway ... as you may noticed, CommonJS is not perfect, but new ECMAScript spec will have module system (which I hope will fix some of CommonJS issues) so maybe it should be taken into consideration right now (I don't know the current state of module specification, but I know there was some work involved).", "updateAuthor": { "name": "ivan.skugor", "key": "ivan.skugor", "displayName": "Ivan Skugor", "active": true, "timeZone": "Europe/Amsterdam" }, "created": "2011-11-28T05:59:44.000+0000", "updated": "2011-11-28T05:59:44.000+0000" }, { "id": "176954", "author": { "name": "dhyde", "key": "dhyde", "displayName": "Dustin Hyde", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Verified as Fixed.\r\nSDK: 1.8.0.1.v20111220190134\r\nAndroid Runtimes: V8/Rhino\r\nStudio: 1.0.7.201112152014\r\nOS: OS X Lion\r\nDevices Tested: Android Emulator 2.2, iPhone Simulator 5.0", "updateAuthor": { "name": "dhyde", "key": "dhyde", "displayName": "Dustin Hyde", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2011-12-21T15:55:55.000+0000", "updated": "2011-12-21T15:55:55.000+0000" }, { "id": "177165", "author": { "name": "lspellman", "key": "lspellman", "displayName": "Lance Spellman", "active": true, "timeZone": "America/Chicago" }, "body": "Confirmed, ran test above on a 5.0 simulator with same SDK and Studio versions. Worked using:\r\n//test.js\r\nmodule.exports={someprop:'testing'};\r\n\r\n//app.js\r\nvar test1 = require('test');\r\nalert(test1.someprop); // outputs testing\r\n\r\nAlso confirmed this generates script { error on 1.7.5 SDK", "updateAuthor": { "name": "lspellman", "key": "lspellman", "displayName": "Lance Spellman", "active": true, "timeZone": "America/Chicago" }, "created": "2011-12-25T09:34:53.000+0000", "updated": "2011-12-25T09:34:53.000+0000" } ], "maxResults": 10, "total": 10, "startAt": 0 } } }