diff --git a/Examples/Movies/SearchScreen.js b/Examples/Movies/SearchScreen.js
index 06fed2e2c09..2cd67aa192f 100644
--- a/Examples/Movies/SearchScreen.js
+++ b/Examples/Movies/SearchScreen.js
@@ -9,7 +9,7 @@ var {
ListView,
ListViewDataSource,
ScrollView,
- SpinnerIOS,
+ ActivityIndicatorIOS,
StyleSheet,
Text,
TextInput,
@@ -215,7 +215,7 @@ var SearchScreen = React.createClass({
if (!this.hasMore() || !this.state.isLoadingTail) {
return ;
}
- return ;
+ return ;
},
renderRow: function(movie: Object) {
@@ -290,7 +290,7 @@ var SearchBar = React.createClass({
onFocus={this.props.onFocus}
style={styles.searchBarInput}
/>
-
diff --git a/Examples/UIExplorer/SpinnerExample.js b/Examples/UIExplorer/ActivityIndicatorExample.js
similarity index 69%
rename from Examples/UIExplorer/SpinnerExample.js
rename to Examples/UIExplorer/ActivityIndicatorExample.js
index 3d6dcbe3279..4f068254dee 100644
--- a/Examples/UIExplorer/SpinnerExample.js
+++ b/Examples/UIExplorer/ActivityIndicatorExample.js
@@ -1,19 +1,19 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
- * @providesModule SpinnerExample
+ * @providesModule ActivityIndicatorExample
*/
'use strict';
var React = require('react-native');
var {
- SpinnerIOS,
+ ActivityIndicatorIOS,
StyleSheet,
TimerMixin,
View,
} = React;
-var ToggleAnimatingSpinner = React.createClass({
+var ToggleAnimatingActivityIndicator = React.createClass({
mixins: [TimerMixin],
getInitialState: function() {
@@ -38,17 +38,17 @@ var ToggleAnimatingSpinner = React.createClass({
render: function() {
return (
-
);
}
});
exports.framework = 'React';
-exports.title = '';
+exports.title = '';
exports.description = 'Animated loading indicators.';
exports.examples = [
@@ -56,7 +56,7 @@ exports.examples = [
title: 'Default (small, white)',
render: function() {
return (
-
@@ -68,10 +68,10 @@ exports.examples = [
render: function() {
return (
-
-
@@ -83,10 +83,10 @@ exports.examples = [
render: function() {
return (
-
-
-
-
+
+
+
+
);
}
@@ -95,10 +95,10 @@ exports.examples = [
title: 'Large',
render: function() {
return (
-
);
}
@@ -108,20 +108,20 @@ exports.examples = [
render: function() {
return (
-
-
-
-
@@ -131,7 +131,7 @@ exports.examples = [
{
title: 'Start/stop',
render: function() {
- return ;
+ return ;
}
},
];
diff --git a/Examples/UIExplorer/UIExplorerList.js b/Examples/UIExplorer/UIExplorerList.js
index 581f34b36db..56734c70fa7 100644
--- a/Examples/UIExplorer/UIExplorerList.js
+++ b/Examples/UIExplorer/UIExplorerList.js
@@ -29,7 +29,7 @@ var EXAMPLES = [
require('./StatusBarIOSExample'),
require('./PointerEventsExample'),
require('./TouchableExample'),
- require('./SpinnerExample'),
+ require('./ActivityIndicatorExample'),
require('./ScrollViewExample'),
];
diff --git a/Libraries/Components/SpinnerIOS/SpinnerIOS.ios.js b/Libraries/Components/ActivityIndicatorIOS/ActivityIndicatorIOS.ios.js
similarity index 91%
rename from Libraries/Components/SpinnerIOS/SpinnerIOS.ios.js
rename to Libraries/Components/ActivityIndicatorIOS/ActivityIndicatorIOS.ios.js
index 6aadabad557..a281cf97aa9 100644
--- a/Libraries/Components/SpinnerIOS/SpinnerIOS.ios.js
+++ b/Libraries/Components/ActivityIndicatorIOS/ActivityIndicatorIOS.ios.js
@@ -1,7 +1,7 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
- * @providesModule SpinnerIOS
+ * @providesModule ActivityIndicatorIOS
*/
'use strict';
@@ -25,7 +25,7 @@ var SpinnerSize = keyMirror({
var GRAY = '#999999';
-var SpinnerIOS = React.createClass({
+var ActivityIndicatorIOS = React.createClass({
mixins: [NativeMethodsMixin],
propTypes: {
@@ -39,8 +39,8 @@ var SpinnerIOS = React.createClass({
color: PropTypes.string,
/**
* The size of the spinner, must be one of:
- * - SpinnerIOS.size.large
- * - SpinnerIOS.size.small (default)
+ * - ActivityIndicatorIOS.size.large
+ * - ActivityIndicatorIOS.size.small (default)
*/
size: PropTypes.oneOf([SpinnerSize.large, SpinnerSize.small]),
},
@@ -101,4 +101,4 @@ var UIActivityIndicatorView = createReactIOSNativeComponentClass({
uiViewClassName: 'UIActivityIndicatorView',
});
-module.exports = SpinnerIOS;
+module.exports = ActivityIndicatorIOS;
diff --git a/Libraries/react-native/react-native-interface.js b/Libraries/react-native/react-native-interface.js
index 419da184da1..8a99d1188c9 100644
--- a/Libraries/react-native/react-native-interface.js
+++ b/Libraries/react-native/react-native-interface.js
@@ -11,7 +11,7 @@ declare module "react-native" {
declare var NavigatorItemIOS: ReactClass;
declare var PixelRatio: ReactClass;
declare var ScrollView: ReactClass;
- declare var SpinnerIOS: ReactClass;
+ declare var ActivityIndicatorIOS: ReactClass;
declare var StyleSheet: ReactClass;
declare var Text: ReactClass;
declare var TextInput: ReactClass;
diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js
index 7b4765c9742..55b0d95d292 100644
--- a/Libraries/react-native/react-native.js
+++ b/Libraries/react-native/react-native.js
@@ -16,7 +16,7 @@ var ReactNative = {
NavigatorIOS: require('NavigatorIOS'),
PixelRatio: require('PixelRatio'),
ScrollView: require('ScrollView'),
- SpinnerIOS: require('SpinnerIOS'),
+ ActivityIndicatorIOS: require('ActivityIndicatorIOS'),
StatusBarIOS: require('StatusBarIOS'),
StyleSheet: require('StyleSheet'),
Text: require('Text'),
diff --git a/ReactKit/Base/RCTBridge.m b/ReactKit/Base/RCTBridge.m
index 9bd0dae35bf..cdd6af842b9 100644
--- a/ReactKit/Base/RCTBridge.m
+++ b/ReactKit/Base/RCTBridge.m
@@ -235,8 +235,9 @@ static NSDictionary *RCTRemoteModulesConfig()
RCTRemoteModulesByID = [[NSMutableDictionary alloc] init];
remoteModules = [[NSMutableDictionary alloc] init];
- [RCTExportedMethodsByModule() enumerateKeysAndObjectsUsingBlock:^(NSString *moduleName, NSArray *rawMethods, BOOL *stop) {
-
+ [RCTBridgeModuleClasses() enumerateKeysAndObjectsUsingBlock:^(NSString *moduleName, Class moduleClass, BOOL *stop) {
+
+ NSArray *rawMethods = RCTExportedMethodsByModule()[moduleName];
NSMutableDictionary *methods = [NSMutableDictionary dictionaryWithCapacity:rawMethods.count];
[rawMethods enumerateObjectsUsingBlock:^(RCTModuleMethod *method, NSUInteger methodID, BOOL *stop) {
methods[method.JSMethodName] = @{
@@ -249,13 +250,15 @@ static NSDictionary *RCTRemoteModulesConfig()
@"moduleID": @(remoteModules.count),
@"methods": methods
};
-
- Class cls = RCTBridgeModuleClasses()[moduleName];
- if (RCTClassOverridesClassMethod(cls, @selector(constantsToExport))) {
- module = [module mutableCopy];
- ((NSMutableDictionary *)module)[@"constants"] = [cls constantsToExport];
+
+ if (RCTClassOverridesClassMethod(moduleClass, @selector(constantsToExport))) {
+ NSDictionary *constants = [moduleClass constantsToExport];
+ if (constants.count) {
+ module = [module mutableCopy];
+ ((NSMutableDictionary *)module)[@"constants"] = constants;
+ }
}
- remoteModules[moduleName] = module;
+ remoteModules[moduleName] = [module copy];
// Add module lookup
RCTRemoteModulesByID[module[@"moduleID"]] = moduleName;
@@ -303,13 +306,13 @@ static NSDictionary *RCTLocalModulesConfig()
// Add globally used methods
[JSMethods addObjectsFromArray:@[
@"Bundler.runApplication",
+ @"RCTDeviceEventEmitter.emit",
@"RCTEventEmitter.receiveEvent",
@"RCTEventEmitter.receiveTouches",
]];
// NOTE: these methods are currently unused in the OSS project
// @"Dimensions.set",
- // @"RCTDeviceEventEmitter.emit",
// @"RCTNativeAppEventEmitter.emit",
// @"ReactIOS.unmountComponentAtNodeAndRemoveContainer",
@@ -376,10 +379,15 @@ static id _latestJSExecutor;
_moduleInstances = [[NSMutableDictionary alloc] init];
[RCTBridgeModuleClasses() enumerateKeysAndObjectsUsingBlock:^(NSString *moduleName, Class moduleClass, BOOL *stop) {
if (_moduleInstances[moduleName] == nil) {
+ id moduleInstance;
if ([moduleClass instancesRespondToSelector:@selector(initWithBridge:)]) {
- _moduleInstances[moduleName] = [[moduleClass alloc] initWithBridge:self];
+ moduleInstance = [[moduleClass alloc] initWithBridge:self];
} else {
- _moduleInstances[moduleName] = [[moduleClass alloc] init];
+ moduleInstance = [[moduleClass alloc] init];
+ }
+ if (moduleInstance) {
+ // If nil, the module doesn't support auto-instantiation
+ _moduleInstances[moduleName] = moduleInstance;
}
}
}];
@@ -522,7 +530,7 @@ static id _latestJSExecutor;
}
if (![buffer isKindOfClass:[NSArray class]]) {
- RCTLogMustFix(@"Buffer must be an instance of NSArray, got %@", NSStringFromClass([buffer class]));
+ RCTLogError(@"Buffer must be an instance of NSArray, got %@", NSStringFromClass([buffer class]));
return;
}
@@ -530,14 +538,14 @@ static id _latestJSExecutor;
NSUInteger bufferRowCount = [requestsArray count];
NSUInteger expectedFieldsCount = RCTBridgeFieldResponseReturnValues + 1;
if (bufferRowCount != expectedFieldsCount) {
- RCTLogMustFix(@"Must pass all fields to buffer - expected %zd, saw %zd", expectedFieldsCount, bufferRowCount);
+ RCTLogError(@"Must pass all fields to buffer - expected %zd, saw %zd", expectedFieldsCount, bufferRowCount);
return;
}
for (NSUInteger fieldIndex = RCTBridgeFieldRequestModuleIDs; fieldIndex <= RCTBridgeFieldParamss; fieldIndex++) {
id field = [requestsArray objectAtIndex:fieldIndex];
if (![field isKindOfClass:[NSArray class]]) {
- RCTLogMustFix(@"Field at index %zd in buffer must be an instance of NSArray, got %@", fieldIndex, NSStringFromClass([field class]));
+ RCTLogError(@"Field at index %zd in buffer must be an instance of NSArray, got %@", fieldIndex, NSStringFromClass([field class]));
return;
}
}
@@ -549,7 +557,7 @@ static id _latestJSExecutor;
NSUInteger numRequests = [moduleIDs count];
BOOL allSame = numRequests == [methodIDs count] && numRequests == [paramsArrays count];
if (!allSame) {
- RCTLogMustFix(@"Invalid data message - all must be length: %zd", numRequests);
+ RCTLogError(@"Invalid data message - all must be length: %zd", numRequests);
return;
}
@@ -578,30 +586,30 @@ static id _latestJSExecutor;
params:(NSArray *)params
{
if (![params isKindOfClass:[NSArray class]]) {
- RCTLogMustFix(@"Invalid module/method/params tuple for request #%zd", i);
+ RCTLogError(@"Invalid module/method/params tuple for request #%zd", i);
return NO;
}
NSString *moduleName = RCTRemoteModulesByID[moduleID];
if (!moduleName) {
- RCTLogMustFix(@"Unknown moduleID: %@", moduleID);
+ RCTLogError(@"Unknown moduleID: %@", moduleID);
return NO;
}
NSArray *methods = RCTExportedMethodsByModule()[moduleName];
if (methodID >= methods.count) {
- RCTLogMustFix(@"Unknown methodID: %zd for module: %@", methodID, moduleName);
+ RCTLogError(@"Unknown methodID: %zd for module: %@", methodID, moduleName);
return NO;
}
RCTModuleMethod *method = methods[methodID];
NSUInteger methodArity = method.arity;
if (params.count != methodArity) {
- RCTLogMustFix(@"Expected %tu arguments but got %tu invoking %@.%@",
- methodArity,
- params.count,
- moduleName,
- method.JSMethodName);
+ RCTLogError(@"Expected %tu arguments but got %tu invoking %@.%@",
+ methodArity,
+ params.count,
+ moduleName,
+ method.JSMethodName);
return NO;
}
@@ -663,13 +671,13 @@ static id _latestJSExecutor;
// TODO: it seems like an error if the param doesn't respond
// so we should probably surface that error rather than failing silently
#define CASE(_value, _type, _selector) \
-case _value: \
-if ([param respondsToSelector:@selector(_selector)]) { \
-_type value = [param _selector]; \
-[invocation setArgument:&value atIndex:argIdx]; \
-shouldSet = NO; \
-} \
-break;
+ case _value: \
+ if ([param respondsToSelector:@selector(_selector)]) { \
+ _type value = [param _selector]; \
+ [invocation setArgument:&value atIndex:argIdx]; \
+ shouldSet = NO; \
+ } \
+ break;
CASE('c', char, charValue)
CASE('C', unsigned char, unsignedCharValue)
@@ -698,7 +706,7 @@ break;
[invocation invoke];
}
@catch (NSException *exception) {
- RCTLogMustFix(@"Exception thrown while invoking %@ on target %@ with params %@: %@", method.JSMethodName, target, params, exception);
+ RCTLogError(@"Exception thrown while invoking %@ on target %@ with params %@: %@", method.JSMethodName, target, params, exception);
}
});
diff --git a/ReactKit/Base/RCTCache.m b/ReactKit/Base/RCTCache.m
index 40edaa557f8..498db2cd05e 100644
--- a/ReactKit/Base/RCTCache.m
+++ b/ReactKit/Base/RCTCache.m
@@ -5,21 +5,90 @@
#import
#import
-static NSString *const CacheSubdirectoryName = @"ReactKit";
-static NSString *const KeyExtendedAttributeName = @"com.facebook.ReactKit.RCTCacheManager.Key";
-static dispatch_queue_t Queue;
+static NSString *const RCTCacheSubdirectoryName = @"ReactKit";
+static NSString *const RCTKeyExtendedAttributeName = @"com.facebook.ReactKit.RCTCacheManager.Key";
+static NSMapTable *RCTLivingCachesByName;
+
+static NSError *RCTPOSIXError(int errorNumber)
+{
+ NSDictionary *userInfo = @{
+ NSLocalizedDescriptionKey: @(strerror(errorNumber))
+ };
+ return [NSError errorWithDomain:NSPOSIXErrorDomain code:errorNumber userInfo:userInfo];
+}
+
+static NSString *RCTGetExtendedAttribute(NSURL *fileURL, NSString *key, NSError **error)
+{
+ const char *path = fileURL.fileSystemRepresentation;
+ ssize_t length = getxattr(path, key.UTF8String, NULL, 0, 0, 0);
+ if (length <= 0) {
+ if (error) *error = RCTPOSIXError(errno);
+ return nil;
+ }
+
+ char *buffer = malloc(length);
+ length = getxattr(path, key.UTF8String, buffer, length, 0, 0);
+ if (length > 0) {
+ return [[NSString alloc] initWithBytesNoCopy:buffer length:length encoding:NSUTF8StringEncoding freeWhenDone:YES];
+ }
+
+ free(buffer);
+ if (error) *error = RCTPOSIXError(errno);
+ return nil;
+}
+
+static BOOL RCTSetExtendedAttribute(NSURL *fileURL, NSString *key, NSString *value, NSError **error)
+{
+ const char *path = fileURL.fileSystemRepresentation;
+
+ int result;
+ if (value) {
+ const char *valueUTF8String = value.UTF8String;
+ result = setxattr(path, key.UTF8String, valueUTF8String, strlen(valueUTF8String), 0, 0);
+ } else {
+ result = removexattr(path, key.UTF8String, 0);
+ }
+
+ if (result) {
+ if (error) *error = RCTPOSIXError(errno);
+ return NO;
+ }
+
+ return YES;
+}
#pragma mark - Cache Record -
@interface RCTCacheRecord : NSObject
-@property (nonatomic, copy) NSUUID *UUID;
+@property (readonly) NSUUID *UUID;
+@property (readonly, weak) dispatch_queue_t queue;
@property (nonatomic, copy) NSData *data;
@end
@implementation RCTCacheRecord
+- (instancetype)initWithUUID:(NSUUID *)UUID
+{
+ if ((self = [super init])) {
+ _UUID = [UUID copy];
+ }
+ return self;
+}
+
+- (void)enqueueBlock:(dispatch_block_t)block
+{
+ dispatch_queue_t queue = _queue;
+ if (!queue) {
+ NSString *queueName = [NSString stringWithFormat:@"com.facebook.ReactKit.RCTCache.%@", _UUID.UUIDString];
+ queue = dispatch_queue_create(queueName.UTF8String, DISPATCH_QUEUE_SERIAL);
+ _queue = queue;
+ }
+
+ dispatch_async(queue, block);
+}
+
@end
#pragma mark - Cache
@@ -35,9 +104,10 @@ static dispatch_queue_t Queue;
+ (void)initialize
{
if (self == [RCTCache class]) {
- Queue = dispatch_queue_create("com.facebook.ReactKit.RCTCache", DISPATCH_QUEUE_SERIAL);
+ RCTLivingCachesByName = [NSMapTable strongToWeakObjectsMapTable];
}
}
+
- (instancetype)init
{
return [self initWithName:@"default"];
@@ -46,46 +116,39 @@ static dispatch_queue_t Queue;
- (instancetype)initWithName:(NSString *)name
{
NSParameterAssert(name.length < NAME_MAX);
+ RCTCache *cachedCache = [RCTLivingCachesByName objectForKey:name];
+ if (cachedCache) {
+ self = cachedCache;
+ return self;
+ }
+
if ((self = [super init])) {
_name = [name copy];
_fileManager = [[NSFileManager alloc] init];
_storage = [NSMutableDictionary dictionary];
NSURL *cacheDirectoryURL = [[_fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];
- cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent:CacheSubdirectoryName isDirectory:YES];
+ cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent:RCTCacheSubdirectoryName isDirectory:YES];
_cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent:name isDirectory:YES];
[_fileManager createDirectoryAtURL:_cacheDirectoryURL withIntermediateDirectories:YES attributes:nil error:NULL];
NSArray *fileURLs = [_fileManager contentsOfDirectoryAtURL:_cacheDirectoryURL includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsHiddenFiles error:NULL];
for (NSURL *fileURL in fileURLs) {
- NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:fileURL.lastPathComponent];
- if (!uuid) continue;
+ NSUUID *UUID = [[NSUUID alloc] initWithUUIDString:fileURL.lastPathComponent];
+ if (!UUID) continue;
- NSString *key = [self keyOfItemAtURL:fileURL error:NULL];
+ NSString *key = RCTGetExtendedAttribute(fileURL, RCTKeyExtendedAttributeName, NULL);
if (!key) {
[_fileManager removeItemAtURL:fileURL error:NULL];
continue;
}
- RCTCacheRecord *record = [[RCTCacheRecord alloc] init];
- record.UUID = uuid;
- _storage[key] = record;
+ _storage[key] = [[RCTCacheRecord alloc] initWithUUID:UUID];
}
}
return self;
}
-- (void)runOnQueue:(dispatch_block_t)block
-{
- UIBackgroundTaskIdentifier identifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
- dispatch_async(Queue, ^{
- if (block) block();
- if (identifier != UIBackgroundTaskInvalid) {
- [[UIApplication sharedApplication] endBackgroundTask:identifier];
- }
- });
-}
-
- (BOOL)hasDataForKey:(NSString *)key
{
return _storage[key] != nil;
@@ -95,115 +158,67 @@ static dispatch_queue_t Queue;
{
NSParameterAssert(key.length > 0);
NSParameterAssert(completionHandler != nil);
- [self runOnQueue:^{
- RCTCacheRecord *record = _storage[key];
- if (record && !record.data) {
+ RCTCacheRecord *record = _storage[key];
+ if (!record) {
+ completionHandler(nil);
+ return;
+ }
+
+ [record enqueueBlock:^{
+ if (!record.data) {
record.data = [NSData dataWithContentsOfURL:[_cacheDirectoryURL URLByAppendingPathComponent:record.UUID.UUIDString]];
}
-
- dispatch_async(dispatch_get_main_queue(), ^{
- completionHandler(record.data);
- });
+ completionHandler(record.data);
}];
}
- (void)setData:(NSData *)data forKey:(NSString *)key
{
NSParameterAssert(key.length > 0);
- [self runOnQueue:^{
- RCTCacheRecord *record = _storage[key];
+ RCTCacheRecord *record = _storage[key];
+ if (!record) {
+ if (!data) return;
+
+ record = [[RCTCacheRecord alloc] initWithUUID:[NSUUID UUID]];
+ _storage[key] = record;
+ }
+
+ NSURL *fileURL = [_cacheDirectoryURL URLByAppendingPathComponent:record.UUID.UUIDString];
+
+ UIBackgroundTaskIdentifier identifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
+ [record enqueueBlock:^{
if (data) {
- if (!record) {
- record = [[RCTCacheRecord alloc] init];
- record.UUID = [NSUUID UUID];
- _storage[key] = record;
- }
-
- record.data = data;
-
- NSURL *fileURL = [_cacheDirectoryURL URLByAppendingPathComponent:record.UUID.UUIDString];
[data writeToURL:fileURL options:NSDataWritingAtomic error:NULL];
- } else if (record) {
- [_storage removeObjectForKey:key];
-
- NSURL *fileURL = [_cacheDirectoryURL URLByAppendingPathComponent:record.UUID.UUIDString];
+ RCTSetExtendedAttribute(fileURL, RCTKeyExtendedAttributeName, key, NULL);
+ } else {
[_fileManager removeItemAtURL:fileURL error:NULL];
}
+
+ if (identifier != UIBackgroundTaskInvalid) {
+ [[UIApplication sharedApplication] endBackgroundTask:identifier];
+ }
}];
}
- (void)removeAllData
{
- [self runOnQueue:^{
- [_storage removeAllObjects];
+ UIBackgroundTaskIdentifier identifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
+ dispatch_group_t group = dispatch_group_create();
- NSDirectoryEnumerator *enumerator = [_fileManager enumeratorAtURL:_cacheDirectoryURL includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsHiddenFiles errorHandler:nil];
- for (NSURL *fileURL in enumerator) {
+ [_storage enumerateKeysAndObjectsUsingBlock:^(NSString *key, RCTCacheRecord *record, BOOL *stop) {
+ NSURL *fileURL = [_cacheDirectoryURL URLByAppendingPathComponent:record.UUID.UUIDString];
+ dispatch_group_async(group, record.queue, ^{
[_fileManager removeItemAtURL:fileURL error:NULL];
- }
+ });
}];
-}
-#pragma mark - Extended Attributes
-
-- (NSError *)errorWithPOSIXErrorNumber:(int)errorNumber
-{
- NSDictionary *userInfo = @{
- NSLocalizedDescriptionKey: @(strerror(errorNumber))
- };
- return [NSError errorWithDomain:NSPOSIXErrorDomain code:errorNumber userInfo:userInfo];
-}
-
-- (BOOL)setAttribute:(NSString *)key value:(NSString *)value ofItemAtURL:(NSURL *)fileURL error:(NSError **)error
-{
- const char *path = fileURL.fileSystemRepresentation;
-
- int result;
- if (value) {
- const char *valueUTF8String = value.UTF8String;
- result = setxattr(path, key.UTF8String, valueUTF8String, strlen(valueUTF8String), 0, 0);
- } else {
- result = removexattr(path, key.UTF8String, 0);
+ if (identifier != UIBackgroundTaskInvalid) {
+ dispatch_group_notify(group, dispatch_get_main_queue(), ^{
+ [[UIApplication sharedApplication] endBackgroundTask:identifier];
+ });
}
- if (result) {
- if (error) *error = [self errorWithPOSIXErrorNumber:errno];
- return NO;
- }
-
- return YES;
-}
-
-- (NSString *)attribute:(NSString *)key ofItemAtURL:(NSURL *)fileURL error:(NSError **)error
-{
- const char *path = fileURL.fileSystemRepresentation;
- const ssize_t length = getxattr(path, key.UTF8String, NULL, 0, 0, 0);
- if (length <= 0) {
- if (error) *error = [self errorWithPOSIXErrorNumber:errno];
- return nil;
- }
-
- char *buffer = malloc(length);
- ssize_t result = getxattr(path, key.UTF8String, buffer, length, 0, 0);
- if (result == 0) {
- return [[NSString alloc] initWithBytesNoCopy:buffer length:length encoding:NSUTF8StringEncoding freeWhenDone:YES];
- }
-
- free(buffer);
- if (error) *error = [self errorWithPOSIXErrorNumber:errno];
- return nil;
-}
-
-#pragma mark - Extended Attributes - Key
-
-- (NSString *)keyOfItemAtURL:(NSURL *)fileURL error:(NSError **)error
-{
- return [self attribute:KeyExtendedAttributeName ofItemAtURL:fileURL error:error];
-}
-
-- (BOOL)setKey:(NSString *)key ofItemAtURL:(NSURL *)fileURL error:(NSError **)error
-{
- return [self setAttribute:KeyExtendedAttributeName value:key ofItemAtURL:fileURL error:error];
+ [_storage removeAllObjects];
}
@end
diff --git a/ReactKit/Base/RCTEventDispatcher.h b/ReactKit/Base/RCTEventDispatcher.h
index 4cfc0d94a99..fba5e7668e0 100644
--- a/ReactKit/Base/RCTEventDispatcher.h
+++ b/ReactKit/Base/RCTEventDispatcher.h
@@ -21,27 +21,36 @@ typedef NS_ENUM(NSInteger, RCTScrollEventType) {
RCTScrollEventTypeEndAnimation,
};
+/**
+ * This class wraps the -[RCTBridge enqueueJSCall:args:] method, and
+ * provides some convenience methods for generating event calls.
+ */
@interface RCTEventDispatcher : NSObject
- (instancetype)initWithBridge:(RCTBridge *)bridge;
/**
- * Send a named event. For most purposes, use the an
- * event type of RCTEventTypeDefault, the other types
- * are used internally by the React framework.
+ * Send a device or application event that does not relate to a specific
+ * view, e.g. rotation, location, keyboard show/hide, background/awake, etc.
*/
-- (void)sendEventWithName:(NSString *)name body:(NSDictionary *)body;
+- (void)sendDeviceEventWithName:(NSString *)name body:(NSDictionary *)body;
/**
- * Send text events
+ * Send a user input event. The body dictionary must contain a "target"
+ * parameter, representing the react tag of the view sending the event
+ */
+- (void)sendInputEventWithName:(NSString *)name body:(NSDictionary *)body;
+
+/**
+ * Send a text input/focus event.
*/
- (void)sendTextEventWithType:(RCTTextEventType)type
reactTag:(NSNumber *)reactTag
text:(NSString *)text;
/**
- * Send scroll events
- * (You can send a fake scroll event by passing nil for scrollView)
+ * Send a scroll event.
+ * (You can send a fake scroll event by passing nil for scrollView).
*/
- (void)sendScrollEventWithType:(RCTScrollEventType)type
reactTag:(NSNumber *)reactTag
diff --git a/ReactKit/Base/RCTEventDispatcher.m b/ReactKit/Base/RCTEventDispatcher.m
index 339873358e7..2805cf6e5fb 100644
--- a/ReactKit/Base/RCTEventDispatcher.m
+++ b/ReactKit/Base/RCTEventDispatcher.m
@@ -4,7 +4,6 @@
#import "RCTAssert.h"
#import "RCTBridge.h"
-#import "UIView+ReactKit.h"
@implementation RCTEventDispatcher
{
@@ -19,7 +18,14 @@
return self;
}
-- (void)sendEventWithName:(NSString *)name body:(NSDictionary *)body
+- (void)sendDeviceEventWithName:(NSString *)name body:(NSDictionary *)body
+{
+ [_bridge enqueueJSCall:@"RCTDeviceEventEmitter.emit"
+ args:body ? @[name, body] : @[name]];
+}
+
+
+- (void)sendInputEventWithName:(NSString *)name body:(NSDictionary *)body
{
RCTAssert([body[@"target"] isKindOfClass:[NSNumber class]],
@"Event body dictionary must include a 'target' property containing a react tag");
@@ -40,7 +46,7 @@
@"topEndEditing",
};
- [self sendEventWithName:events[type] body:@{
+ [self sendInputEventWithName:events[type] body:@{
@"text": text,
@"target": reactTag
}];
@@ -91,7 +97,7 @@
body = mutableBody;
}
- [self sendEventWithName:events[type] body:body];
+ [self sendInputEventWithName:events[type] body:body];
}
@end
diff --git a/ReactKit/Base/RCTImageDownloader.m b/ReactKit/Base/RCTImageDownloader.m
index 8efbe3b50bf..9f065aaa332 100644
--- a/ReactKit/Base/RCTImageDownloader.m
+++ b/ReactKit/Base/RCTImageDownloader.m
@@ -7,9 +7,12 @@
// TODO: something a bit more sophisticated
+typedef void (^RCTCachedDataDownloadBlock)(BOOL cached, NSData *data, NSError *error);
+
@implementation RCTImageDownloader
{
RCTCache *_cache;
+ NSMutableDictionary *_pendingBlocks;
}
+ (instancetype)sharedInstance
@@ -27,6 +30,7 @@
{
if ((self = [super init])) {
_cache = [[RCTCache alloc] initWithName:@"RCTImageDownloader"];
+ _pendingBlocks = [NSMutableDictionary dictionary];
}
return self;
}
@@ -36,8 +40,7 @@
return url.absoluteString;
}
-- (id)_downloadDataForURL:(NSURL *)url
- block:(RCTDataDownloadBlock)block
+- (id)_downloadDataForURL:(NSURL *)url block:(RCTCachedDataDownloadBlock)block
{
NSString *cacheKey = [self cacheKeyForURL:url];
@@ -45,36 +48,58 @@
__block NSURLSessionDataTask *task = nil;
dispatch_block_t cancel = ^{
cancelled = YES;
+
+ NSMutableArray *pendingBlocks = _pendingBlocks[cacheKey];
+ [pendingBlocks removeObject:block];
+
if (task) {
[task cancel];
task = nil;
}
};
- if ([_cache hasDataForKey:cacheKey]) {
- [_cache fetchDataForKey:cacheKey completionHandler:^(NSData *data) {
- if (cancelled) return;
- block(data, nil);
- }];
+ NSMutableArray *pendingBlocks = _pendingBlocks[cacheKey];
+ if (pendingBlocks) {
+ [pendingBlocks addObject:block];
} else {
- task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
- block(data, error);
- }];
+ _pendingBlocks[cacheKey] = [NSMutableArray arrayWithObject:block];
- [task resume];
+ __weak RCTImageDownloader *weakSelf = self;
+ RCTCachedDataDownloadBlock runBlocks = ^(BOOL cached, NSData *data, NSError *error) {
+ RCTImageDownloader *strongSelf = weakSelf;
+ NSArray *blocks = strongSelf->_pendingBlocks[cacheKey];
+ [strongSelf->_pendingBlocks removeObjectForKey:cacheKey];
+
+ for (RCTCachedDataDownloadBlock block in blocks) {
+ block(cached, data, error);
+ }
+ };
+
+ if ([_cache hasDataForKey:cacheKey]) {
+ [_cache fetchDataForKey:cacheKey completionHandler:^(NSData *data) {
+ if (!cancelled) runBlocks(YES, data, nil);
+ }];
+ } else {
+ task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
+ if (!cancelled) runBlocks(NO, data, error);
+ }];
+
+ [task resume];
+ }
}
return [cancel copy];
}
-- (id)downloadDataForURL:(NSURL *)url
- block:(RCTDataDownloadBlock)block
+- (id)downloadDataForURL:(NSURL *)url block:(RCTDataDownloadBlock)block
{
NSString *cacheKey = [self cacheKeyForURL:url];
__weak RCTImageDownloader *weakSelf = self;
- return [self _downloadDataForURL:url block:^(NSData *data, NSError *error) {
- RCTImageDownloader *strongSelf = weakSelf;
- [strongSelf->_cache setData:data forKey:cacheKey];
+ return [self _downloadDataForURL:url block:^(BOOL cached, NSData *data, NSError *error) {
+ if (!cached) {
+ RCTImageDownloader *strongSelf = weakSelf;
+ [strongSelf->_cache setData:data forKey:cacheKey];
+ }
dispatch_async(dispatch_get_main_queue(), ^{
block(data, error);
@@ -82,52 +107,51 @@
}];
}
-- (id)downloadImageForURL:(NSURL *)url
- size:(CGSize)size
- scale:(CGFloat)scale
- block:(RCTImageDownloadBlock)block
+- (id)downloadImageForURL:(NSURL *)url size:(CGSize)size scale:(CGFloat)scale block:(RCTImageDownloadBlock)block
{
NSString *cacheKey = [self cacheKeyForURL:url];
__weak RCTImageDownloader *weakSelf = self;
- return [self _downloadDataForURL:url block:^(NSData *data, NSError *error) {
- if (data) {
- UIImage *image = [UIImage imageWithData:data scale:scale];
-
- if (image) {
- CGSize imageSize = size;
- if (CGSizeEqualToSize(imageSize, CGSizeZero)) {
- imageSize = image.size;
- }
-
- CGFloat imageScale = scale;
- if (imageScale == 0 || imageScale > image.scale) {
- imageScale = image.scale;
- }
-
- UIGraphicsBeginImageContextWithOptions(imageSize, NO, imageScale);
- [image drawInRect:(CGRect){{0, 0}, imageSize}];
- image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- RCTImageDownloader *strongSelf = weakSelf;
- [strongSelf->_cache setData:UIImagePNGRepresentation(image) forKey:cacheKey];
- }
-
- dispatch_async(dispatch_get_main_queue(), ^{
- block(image, nil);
- });
- } else {
- dispatch_async(dispatch_get_main_queue(), ^{
+ return [self _downloadDataForURL:url block:^(BOOL cached, NSData *data, NSError *error) {
+ if (!data) {
+ return dispatch_async(dispatch_get_main_queue(), ^{
block(nil, error);
});
}
+
+ UIImage *image = [UIImage imageWithData:data scale:scale];
+
+ if (image) {
+ CGSize imageSize = size;
+ if (CGSizeEqualToSize(imageSize, CGSizeZero)) {
+ imageSize = image.size;
+ }
+
+ CGFloat imageScale = scale;
+ if (imageScale == 0 || imageScale > image.scale) {
+ imageScale = image.scale;
+ }
+
+ UIGraphicsBeginImageContextWithOptions(imageSize, NO, imageScale);
+ [image drawInRect:(CGRect){{0, 0}, imageSize}];
+ image = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+
+ if (!cached) {
+ RCTImageDownloader *strongSelf = weakSelf;
+ [strongSelf->_cache setData:UIImagePNGRepresentation(image) forKey:cacheKey];
+ }
+ }
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ block(image, nil);
+ });
}];
}
- (void)cancelDownload:(id)downloadToken
{
if (downloadToken) {
- dispatch_block_t block = downloadToken;
+ dispatch_block_t block = (id)downloadToken;
block();
}
}
diff --git a/ReactKit/Modules/RCTUIManager.m b/ReactKit/Modules/RCTUIManager.m
index 27a23c43f0d..3b1b5643288 100644
--- a/ReactKit/Modules/RCTUIManager.m
+++ b/ReactKit/Modules/RCTUIManager.m
@@ -677,7 +677,10 @@ static void RCTSetShadowViewProps(NSDictionary *props, RCTShadowView *shadowView
RCTLogWarn(@"No manager class found for view with module name \"%@\"", moduleName);
manager = [[RCTViewManager alloc] init];
}
-
+
+ // Register manager
+ _viewManagerRegistry[reactTag] = manager;
+
// Generate default view, used for resetting default props
if (!_defaultShadowViews[moduleName]) {
_defaultShadowViews[moduleName] = [manager shadowView];
@@ -691,10 +694,7 @@ static void RCTSetShadowViewProps(NSDictionary *props, RCTShadowView *shadowView
[self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){
RCTCAssertMainThread();
-
- // Register manager
- uiManager->_viewManagerRegistry[reactTag] = manager;
-
+
// Generate default view, used for resetting default props
if (!uiManager->_defaultViews[moduleName]) {
// Note the default is setup after the props are read for the first time ever
diff --git a/ReactKit/Views/RCTNavigator.m b/ReactKit/Views/RCTNavigator.m
index d03ff7874fe..74e1621c25b 100644
--- a/ReactKit/Views/RCTNavigator.m
+++ b/ReactKit/Views/RCTNavigator.m
@@ -324,7 +324,7 @@ NSInteger kNeverProgressed = -10000;
return;
}
_mostRecentProgress = nextProgress;
- [_eventDispatcher sendEventWithName:@"topNavigationProgress" body:@{
+ [_eventDispatcher sendInputEventWithName:@"topNavigationProgress" body:@{
@"fromIndex": @(_currentlyTransitioningFrom),
@"toIndex": @(_currentlyTransitioningTo),
@"progress": @(nextProgress),
@@ -447,7 +447,7 @@ NSInteger kNeverProgressed = -10000;
- (void)handleTopOfStackChanged
{
- [_eventDispatcher sendEventWithName:@"topNavigateBack" body:@{
+ [_eventDispatcher sendInputEventWithName:@"topNavigateBack" body:@{
@"target":self.reactTag,
@"stackLength":@(_navigationController.viewControllers.count)
}];
diff --git a/ReactKit/Views/RCTWrapperViewController.m b/ReactKit/Views/RCTWrapperViewController.m
index b5425fbcdd0..d027dc2f294 100644
--- a/ReactKit/Views/RCTWrapperViewController.m
+++ b/ReactKit/Views/RCTWrapperViewController.m
@@ -96,7 +96,7 @@
- (void)rightButtonTapped
{
- [_eventDispatcher sendEventWithName:@"topNavRightButtonTap" body:@{@"target":_navItem.reactTag}];
+ [_eventDispatcher sendInputEventWithName:@"topNavRightButtonTap" body:@{@"target":_navItem.reactTag}];
}
- (void)didMoveToParentViewController:(UIViewController *)parent
diff --git a/packager/react-packager/index.js b/packager/react-packager/index.js
index 59a22d6e9e5..65ae88d8d5e 100644
--- a/packager/react-packager/index.js
+++ b/packager/react-packager/index.js
@@ -10,10 +10,30 @@ exports.middleware = function(options) {
exports.buildPackageFromUrl = function(options, reqUrl) {
Activity.disable();
+ // Don't start the filewatcher or the cache.
+ if (options.nonPersistent == null) {
+ options.nonPersistent = true;
+ }
+
var server = new Server(options);
return server.buildPackageFromUrl(reqUrl)
.then(function(p) {
- server.kill();
+ server.end();
return p;
});
};
+
+exports.getDependencies = function(options, main) {
+ Activity.disable();
+ // Don't start the filewatcher or the cache.
+ if (options.nonPersistent == null) {
+ options.nonPersistent = true;
+ }
+
+ var server = new Server(options);
+ return server.getDependencies(main)
+ .then(function(r) {
+ server.end();
+ return r.dependencies;
+ });
+};
diff --git a/packager/react-packager/src/DependencyResolver/haste/__tests__/HasteDependencyResolver-test.js b/packager/react-packager/src/DependencyResolver/haste/__tests__/HasteDependencyResolver-test.js
index ca180929da5..9b43f97ee32 100644
--- a/packager/react-packager/src/DependencyResolver/haste/__tests__/HasteDependencyResolver-test.js
+++ b/packager/react-packager/src/DependencyResolver/haste/__tests__/HasteDependencyResolver-test.js
@@ -55,6 +55,25 @@ describe('HasteDependencyResolver', function() {
isPolyfill: true,
dependencies: ['polyfills/prelude.js', 'polyfills/require.js']
},
+ { id: 'polyfills/console.js',
+ isPolyfill: true,
+ path: 'polyfills/console.js',
+ dependencies: [
+ 'polyfills/prelude.js',
+ 'polyfills/require.js',
+ 'polyfills/polyfills.js'
+ ],
+ },
+ { id: 'polyfills/error-guard.js',
+ isPolyfill: true,
+ path: 'polyfills/error-guard.js',
+ dependencies: [
+ 'polyfills/prelude.js',
+ 'polyfills/require.js',
+ 'polyfills/polyfills.js',
+ 'polyfills/console.js'
+ ],
+ },
module
]);
});
@@ -97,11 +116,35 @@ describe('HasteDependencyResolver', function() {
isPolyfill: true,
dependencies: ['polyfills/prelude.js', 'polyfills/require.js']
},
+ { id: 'polyfills/console.js',
+ isPolyfill: true,
+ path: 'polyfills/console.js',
+ dependencies: [
+ 'polyfills/prelude.js',
+ 'polyfills/require.js',
+ 'polyfills/polyfills.js'
+ ],
+ },
+ { id: 'polyfills/error-guard.js',
+ isPolyfill: true,
+ path: 'polyfills/error-guard.js',
+ dependencies: [
+ 'polyfills/prelude.js',
+ 'polyfills/require.js',
+ 'polyfills/polyfills.js',
+ 'polyfills/console.js'
+ ],
+ },
{ path: 'some module',
id: 'some module',
isPolyfill: true,
- dependencies: [ 'polyfills/prelude.js', 'polyfills/require.js',
- 'polyfills/polyfills.js']
+ dependencies: [
+ 'polyfills/prelude.js',
+ 'polyfills/require.js',
+ 'polyfills/polyfills.js',
+ 'polyfills/console.js',
+ 'polyfills/error-guard.js',
+ ]
},
module
]);
diff --git a/packager/react-packager/src/DependencyResolver/haste/index.js b/packager/react-packager/src/DependencyResolver/haste/index.js
index 13525bdabdc..6e2cd6fcac9 100644
--- a/packager/react-packager/src/DependencyResolver/haste/index.js
+++ b/packager/react-packager/src/DependencyResolver/haste/index.js
@@ -19,7 +19,10 @@ var DEFINE_MODULE_REPLACE_RE = /_moduleName_|_code_|_deps_/g;
var REL_REQUIRE_STMT = /require\(['"]([\.\/0-9A-Z_$\-]*)['"]\)/gi;
function HasteDependencyResolver(config) {
- this._fileWatcher = new FileWatcher(config.projectRoots);
+ this._fileWatcher = config.nonPersistent
+ ? FileWatcher.createDummyWatcher()
+ : new FileWatcher(config.projectRoots);
+
this._depGraph = new DependencyGraph({
roots: config.projectRoots,
ignoreFilePath: function(filepath) {
@@ -97,7 +100,6 @@ HasteDependencyResolver.prototype.wrapModule = function(module, code) {
}
}
-
var relativizedCode =
code.replace(REL_REQUIRE_STMT, function(codeMatch, depName) {
var dep = resolvedDeps[depName];
@@ -117,7 +119,6 @@ HasteDependencyResolver.prototype.wrapModule = function(module, code) {
});
};
-
HasteDependencyResolver.prototype.end = function() {
return this._fileWatcher.end();
};
diff --git a/packager/react-packager/src/FileWatcher/index.js b/packager/react-packager/src/FileWatcher/index.js
index c9a48058225..f2721d8cfb9 100644
--- a/packager/react-packager/src/FileWatcher/index.js
+++ b/packager/react-packager/src/FileWatcher/index.js
@@ -76,3 +76,11 @@ function createWatcher(root) {
});
});
}
+
+FileWatcher.createDummyWatcher = function() {
+ var ev = new EventEmitter();
+ ev.end = function() {
+ return q();
+ };
+ return ev;
+};
diff --git a/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js b/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js
index fb33a83470f..6c9c66446f2 100644
--- a/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js
+++ b/packager/react-packager/src/JSTransformer/__tests__/Transformer-test.js
@@ -6,6 +6,10 @@ jest
.dontMock('os')
.dontMock('../index');
+var OPTIONS = {
+ transformModulePath: '/foo/bar'
+};
+
describe('Transformer', function() {
var Transformer;
var workers;
@@ -32,7 +36,7 @@ describe('Transformer', function() {
callback(null, 'content');
});
- return new Transformer({}).loadFileAndTransform([], 'file', {})
+ return new Transformer(OPTIONS).loadFileAndTransform([], 'file', {})
.then(function(data) {
expect(data).toEqual({
code: 'transformed',
@@ -55,7 +59,7 @@ describe('Transformer', function() {
callback(null, {error: esprimaError});
});
- return new Transformer({}).loadFileAndTransform([], 'foo-file.js', {})
+ return new Transformer(OPTIONS).loadFileAndTransform([], 'foo-file.js', {})
.catch(function(error) {
expect(error.type).toEqual('TransformError');
expect(error.snippet).toEqual([
diff --git a/packager/react-packager/src/JSTransformer/index.js b/packager/react-packager/src/JSTransformer/index.js
index ce7de143bc3..7b01d9617d2 100644
--- a/packager/react-packager/src/JSTransformer/index.js
+++ b/packager/react-packager/src/JSTransformer/index.js
@@ -14,15 +14,21 @@ module.exports = Transformer;
Transformer.TransformError = TransformError;
function Transformer(projectConfig) {
- this._cache = new Cache(projectConfig);
- this._workers = workerFarm(
- {autoStart: true},
- projectConfig.transformModulePath
- );
+ this._cache = projectConfig.nonPersistent
+ ? new DummyCache() : new Cache(projectConfig);
+
+ if (projectConfig.transformModulePath == null) {
+ this._failedToStart = q.Promise.reject(new Error('No transfrom module'));
+ } else {
+ this._workers = workerFarm(
+ {autoStart: true},
+ projectConfig.transformModulePath
+ );
+ }
}
Transformer.prototype.kill = function() {
- workerFarm.end(this._workers);
+ this._workers && workerFarm.end(this._workers);
return this._cache.end();
};
@@ -37,6 +43,10 @@ Transformer.prototype.loadFileAndTransform = function(
filePath,
options
) {
+ if (this._failedToStart) {
+ return this._failedToStart;
+ }
+
var workers = this._workers;
return this._cache.get(filePath, function() {
return readFile(filePath)
@@ -93,3 +103,10 @@ function formatEsprimaError(err, filename, source) {
error.description = err.description;
return error;
}
+
+function DummyCache() {}
+DummyCache.prototype.get = function(filePath, loaderCb) {
+ return loaderCb();
+};
+DummyCache.prototype.end =
+DummyCache.prototype.invalidate = function(){};
diff --git a/packager/react-packager/src/Packager/index.js b/packager/react-packager/src/Packager/index.js
index 3aef649d898..3ec4e378c0f 100644
--- a/packager/react-packager/src/Packager/index.js
+++ b/packager/react-packager/src/Packager/index.js
@@ -34,15 +34,7 @@ var DEFAULT_CONFIG = {
*/
polyfillModuleNames: [],
- /**
- * DEPRECATED
- *
- * A string of code to be appended to the top of a package.
- *
- * TODO: THIS RUINS SOURCE MAPS. THIS OPTION SHOULD BE REMOVED ONCE WE GET
- * config.polyfillModuleNames WORKING!
- */
- runtimeCode: ''
+ nonPersistent: false,
};
function Packager(projectConfig) {
@@ -72,7 +64,7 @@ Packager.prototype.package = function(main, runModule, sourceMapUrl) {
var findEventId = Activity.startEvent('find dependencies');
var transformEventId;
- return this._resolver.getDependencies(main)
+ return this.getDependencies(main)
.then(function(result) {
Activity.endEvent(findEventId);
transformEventId = Activity.startEvent('transform');
@@ -98,10 +90,14 @@ Packager.prototype.package = function(main, runModule, sourceMapUrl) {
});
};
-Packager.prototype.invalidateFile = function(filePath){
+Packager.prototype.invalidateFile = function(filePath) {
this._transformer.invalidateFile(filePath);
}
+Packager.prototype.getDependencies = function(main) {
+ return this._resolver.getDependencies(main);
+};
+
Packager.prototype._transformModule = function(module) {
var resolver = this._resolver;
return this._transformer.loadFileAndTransform(
diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js
index 5545b349faf..26929ebb575 100644
--- a/packager/react-packager/src/Server/index.js
+++ b/packager/react-packager/src/Server/index.js
@@ -18,10 +18,13 @@ function Server(options) {
cacheVersion: options.cacheVersion,
resetCache: options.resetCache,
dev: options.dev,
- transformModulePath: options.transformModulePath
+ transformModulePath: options.transformModulePath,
+ nonPersistent: options.nonPersistent,
});
- this._fileWatcher = new FileWatcher(options.projectRoots);
+ this._fileWatcher = options.nonPersistent
+ ? FileWatcher.createDummyWatcher()
+ : new FileWatcher(options.projectRoots);
var onFileChange = this._onFileChange.bind(this);
this._fileWatcher.on('all', onFileChange);
@@ -48,7 +51,7 @@ Server.prototype._rebuildPackages = function(filepath) {
});
};
-Server.prototype.kill = function() {
+Server.prototype.end = function() {
q.all([
this._fileWatcher.end(),
this._packager.kill(),
@@ -68,6 +71,10 @@ Server.prototype.buildPackageFromUrl = function(reqUrl) {
return this._buildPackage(options);
};
+Server.prototype.getDependencies = function(main) {
+ return this._packager.getDependencies(main);
+};
+
Server.prototype._processDebugRequest = function(reqUrl, res) {
var ret = '';
var pathname = url.parse(reqUrl).pathname;