Titanium JIRA Archive
Alloy (ALOY)

[ALOY-1734] JS files imported in "alloy.js" don't have access to Alloy globals as of Titanium 9.0.0

GitHub Issuen/a
TypeBug
PriorityHigh
StatusClosed
ResolutionFixed
Resolution Date2020-08-11T20:24:48.000+0000
Affected Version/sn/a
Fix Version/sCLI Release 8.1.0
Componentsn/a
Labelsalloy, globals, regression
ReporterJoshua Quick
AssigneeEwan Harris
Created2020-07-30T20:48:49.000+0000
Updated2020-08-11T20:24:48.000+0000

Description

*Summary:* As of Titanium 9.0.0, a JS files loaded via import in the "alloy.js" won't have access to globals Alloy, Backbone, or _ (aka: lodash). This is not an issue if JS files are loaded via the require() function. *Steps to reproduce:*

Download [kitchensink-v2](https://github.com/appcelerator/kitchensink-v2).

Open project file: ./app/lib/actionbar.js

Add the following line to the end of the JS file:

console.log("@@@ Alloy = " + (typeof Alloy));

Build and run on Android or iOS.

Notice the following gets logged as undefined.

[INFO]  @@@ Alloy = undefined
*Cause:* Look at the "app.js" that gets generated. The babel transpile is turning the JavaScript import statement into a require() function call at the top of the "app.js", above where we assign Alloy globals. Also note that "var" variables in "app.js" and "alloy.js" no longer have global scope as of Titanium 9.0.0, which is why it wasn't an issue before. The top of the generated "app.js" looks like this.
var _actionbar=_interopRequireDefault(require("actionbar"));
function _interopRequireDefault(obj){
	return obj&&obj.__esModule?obj:{default:obj}
}
"use strict";
var Alloy=require("/alloy"),
	_=Alloy._,
	Backbone=Alloy.Backbone;
global.Alloy=Alloy,
global._=_,
global.Backbone=Backbone,
*Note:* JavaScript import statements are "hoisted". This is in the ES6 specification, which means this is not a babel transpile issue. So, import statements will always be executed first within the same JS file. *Possible Fix:* Add an "alloy.bootstrap.js" to the project and assign the Alloy globals there. Bootstrap scripts are loaded before the "app.js", which works-around the problem. This also means we can remove the global Alloy assignment from the generated "app.js". *Work-Around:* Don't import JS files in the "alloy.js". Use require() function instead.

Comments

  1. Ewan Harris 2020-07-30

    Adding the bootstrap file will be the only solution here, bable is adhering to the modules spec by hoisting the import statements like they would if they were actually ran in a JS environment (as opposed to being transpiled) https://exploringjs.com/es6/ch_modules.html#_imports-are-hoisted
  2. Joshua Quick 2020-07-31

    I can think of another solution. Instead of inserting the "alloy.js" code into the "app.js" template's __MAPMARKER_ALLOY_JS__, we could keep the "alloy.js" file and require it in instead. https://github.com/appcelerator/alloy/blob/master/Alloy/template/app.js So Alloy's "app.js" code becomes the below.
       //app.js
       var Alloy = require('/alloy'),
       	_ = Alloy._,
       	Backbone = Alloy.Backbone;
       global.Alloy = Alloy;
       global._ = _;
       global.Backbone = Backbone;
       
       // Don't do this anymore.
       //__MAPMARKER_ALLOY_JS__
       
       // Require the "alloy.js" file instead.
       require('alloy');
       
    This means we're no longer generating an "app.js" and we would just copy this file and the developer's "alloy.js" as-is.
  3. Hans Knöchel 2020-08-01

    Could we also (as a workaround) move not only the Alloy.Globals but the whole alloy.js contents to the bootstrap? Does this affect boot time?
  4. Joshua Quick 2020-08-03

    bq. Could we also (as a workaround) move not only the Alloy.Globals but the whole alloy.js contents to the bootstrap? Does this affect boot time? Yes, that's exactly what I'm suggesting. And it wouldn't effect the boot time. We would simply be loading the "alloy.js" sooner than before (ie: before the "app.js"). A bootstrap script can only add a delay when using its optional async execute function, which we're not going to do in this case. Also, it looks like JS imports being "hoisted" above JS statements is part of the ES6 specification. So, this isn't a babel issue. The babel transpile is doing the correct thing.
  5. Ewan Harris 2020-08-05

    PR: https://github.com/appcelerator/alloy/pull/964 I did some small tests to see how this impacted the startup time of KS-v2 on Android and there's averaged out I'm seeing similar numbers, I'll continue to try collect data and also get some results for iOS
  6. Ewan Harris 2020-08-06

    Available in alloy 1.15.0 and appc CLI 8.1.0-master.9. Appc cli currently only preprod, so internal only
  7. Satyam Sekhri 2020-08-11

    Verified on: Mac OS: 10.15.4 SDK: 9.1.0.v20200810095016 Appc CLI: 8.1.0-master.9 JDK: 11.0.4 Node: 10.17.0

JSON Source