Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-24811] LiveView causes multiple instances of same module when requiring using different paths

GitHub Issuen/a
TypeBug
PriorityCritical
StatusResolved
ResolutionFixed
Resolution Date2017-09-18T22:54:43.000+0000
Affected Version/sRelease 6.1.0
Fix Version/sn/a
Componentsn/a
Labelsliveview, titanium
ReporterBrenton House
AssigneeFeon Sua Xin Miao
Created2017-06-06T22:33:08.000+0000
Updated2017-09-21T06:42:59.000+0000

Description

When requiring a module nodejs style, using index as default, requiring the same file using different paths results in different modules. _i.e. require('/test') vs require('/test/index')_ *Steps to recreate:* 1. Create a new Titanium app using the CLI 2. Create a new file: /lib/test/index.js
var test = {};
module.exports = test;
test.x = 1;
3. Open the file controllers/index.js 4. Add the following lines:
var test = require('/test');
console.error('test.x: ' + test.x);
5. Run app: appc ti build --platform ios --target simulator --log-level trace --liveview 6. App should start successfully. 7. The following should show in console log: test.x: 1 8. Change the file: /lib/test/index.js
var test = {};
module.exports = test;
test.x = 2;
9. The following should show in console log: test.x: 2 but instead the output is the same as before: test.x: 1 If you use the following in /controllers/index.js, it works as expected:
var test = require('/test/index');
console.error('test.x: ' + test.x);
*Another test that fails (and doesn't require a recompile or restart) is this:*
var test1 = require('/test');
console.log('test1.x: ' + test1.x);
test1.x = 2;
var test2 = require('/test/index');
console.log('test2.x: ' + test2.x);
The output of this with LiveView off is: test.x: 1 test.x: 2 But with LiveView on, the output is this: test.x: 1 test.x: 1

Comments

  1. Sergey Nosenko 2017-06-14

    This issue should be resolved using cached version of required module. In SDK 5.X.X the second call of require to the same module returns cached module. I'm sure that this will fix it:
       - (TiModule *)loadAsFile:(NSString *)path withContext:(KrollContext *)kroll
       {
       	// 1. If X is a file, load X as JavaScript text.  STOP
           TiModule *module = nil;
       	NSString *filename = path;
           module = [modules objectForKey:filename];
           if (module != nil) {
               return module;
           }
       	NSString *data = [self loadFile:filename];
       	if (data != nil) {
       		// If the file extension is .json, load as JavascriptObject!
       		NSString *ext = [filename pathExtension];
       		if (ext != nil && [ext isEqual:@"json"]) {
       			module = [self loadJavascriptObject:data fromFile:filename withContext:context];
       		}
       		module = [self loadJavascriptText:data fromFile:filename withContext:context];
       	}
           if (module != nil) {
               [modules setObject:module forKey:filename];
               return module;
           }
       	// 2. If X.js is a file, load X.js as JavaScript text.  STOP
       	filename = [path stringByAppendingString:@".js"];
           module = [modules objectForKey:filename];
           if (module != nil) {
               return module;
           }
       	data = [self loadFile:filename];
       	if (data != nil) {
       		module = [self loadJavascriptText:data fromFile:filename withContext:context];
       	}
           if (module != nil) {
               [modules setObject:module forKey:filename];
               return module;
           }
       	// 3. If X.json is a file, parse X.json to a JavaScript Object.  STOP
       	filename = [path stringByAppendingString:@".json"];
           module = [modules objectForKey:filename];
           if (module != nil) {
               return module;
           }
       	data = [self loadFile:filename];
       	if (data != nil) {
       		module = [self loadJavascriptObject:data fromFile:filename withContext:context];
       	}
           if (module != nil) {
               [modules setObject:module forKey:filename];
               return module;
           }
       	// failed to load anything!
       	return nil;
       }
       
       - (TiModule *)loadAsDirectory:(NSString *)path withContext:(KrollContext *)kroll
       {
       	// 1. If X/package.json is a file,
           TiModule *module = nil;
       	NSString *filename = [path stringByAppendingPathComponent:@"package.json"];
       	NSString *data = [self loadFile:filename];
       	if (data != nil) {
       		// a. Parse X/package.json, and look for "main" field.
       		// Just cheat and use TiUtils.jsonParse here, rather than loading the package.json as a JS object...
       		NSDictionary *json = [TiUtils jsonParse:data];
       		if (json != nil) {
       			id main = [json objectForKey:@"main"];
       			NSString *mainString = nil;
       			if ([main isKindOfClass:[NSString class]]) {
       				mainString = (NSString *)main;
       				// b. let M = X + (json main field)
       				NSString *m = [[path stringByAppendingPathComponent:mainString] stringByStandardizingPath];
       				// c. LOAD_AS_FILE(M)
       				return [self loadAsFile:m withContext:context];
       			}
       		}
       	}
       
       	// 2. If X/index.js is a file, load X/index.js as JavaScript text.  STOP
       	filename = [path stringByAppendingPathComponent:@"index.js"];
           module = [modules objectForKey:filename];
           if (module != nil) {
               return module;
           }
       	data = [self loadFile:filename];
       	if (data != nil) {
       		module = [self loadJavascriptText:data fromFile:filename withContext:context];
       	}
           if (module != nil) {
               [modules setObject:module forKey:filename];
               return module;
           }    
       	// 3. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
       	filename = [path stringByAppendingPathComponent:@"index.json"];
           module = [modules objectForKey:filename];
           if (module != nil) {
               return module;
           }
       	data = [self loadFile:filename];
       	if (data != nil) {
       		module = [self loadJavascriptObject:data fromFile:filename withContext:context];
       	}
           if (module != nil) {
               [modules setObject:module forKey:filename];
               return module;
           }
       	return nil;
       }
       
  2. Feon Sua Xin Miao 2017-08-09

    PR: https://github.com/appcelerator/liveview/pull/105
  3. Feon Sua Xin Miao 2017-09-06

    Fixed in liveview@1.2.1.
  4. Feon Sua Xin Miao 2017-09-06

    Update PR: https://github.com/appcelerator/liveview/pull/108
  5. Victor Vazquez Montero 2017-09-18

    [~fmiao]Hey Feon do we know when live view 1.2.1 will be released?
  6. Feon Sua Xin Miao 2017-09-18

    PR merged.
  7. Feon Sua Xin Miao 2017-09-18

    [~vvazquezmontero], it'll be shipped with Studio 4.10.0
  8. Victor Vazquez Montero 2017-09-18

    Thank you [~fmiao] do we have an expected ship that for that?
  9. Feon Sua Xin Miao 2017-09-18

    [~kkolipaka] ^^
  10. Kondal Kolipaka 2017-09-21

    [~vvazquezmontero] Studio 4.10.0 RC would be next week.

JSON Source