- [react-packager] Start converting options to query params | Amjad Masad
- [ReactNative] Replace js long constants with strings | Tadeu Zagallo
- React Native: Remove Unnecessary `document.body` Shim | Tim Yung
- [ReactNative] Use spread operator and .propTypes for ScrollView/ListView | Christopher Chedeau
This commit is contained in:
Christopher Chedeau 2015-03-04 21:06:49 -08:00
Родитель b9ab607197
Коммит b87ba87e47
15 изменённых файлов: 212 добавлений и 221 удалений

Просмотреть файл

@ -282,7 +282,7 @@ var SearchBar = React.createClass({
return (
<View style={styles.searchBar}>
<TextInput
autoCapitalize={TextInput.autoCapitalizeMode.none}
autoCapitalize="none"
autoCorrect={false}
onChange={this.props.onSearchChange}
placeholder="Search a movie..."

Просмотреть файл

@ -41,7 +41,7 @@ var ToggleAnimatingActivityIndicator = React.createClass({
<ActivityIndicatorIOS
animating={this.state.animating}
style={[styles.centering, {height: 80}]}
size={ActivityIndicatorIOS.size.large}
size="large"
/>
);
}
@ -98,7 +98,7 @@ exports.examples = [
<ActivityIndicatorIOS
style={[styles.centering, styles.gray, {height: 80}]}
color="white"
size={ActivityIndicatorIOS.size.large}
size="large"
/>
);
}
@ -109,19 +109,19 @@ exports.examples = [
return (
<View style={styles.horizontal}>
<ActivityIndicatorIOS
size={ActivityIndicatorIOS.size.large}
size="large"
color="#0000ff"
/>
<ActivityIndicatorIOS
size={ActivityIndicatorIOS.size.large}
size="large"
color="#aa00aa"
/>
<ActivityIndicatorIOS
size={ActivityIndicatorIOS.size.large}
size="large"
color="#aa3300"
/>
<ActivityIndicatorIOS
size={ActivityIndicatorIOS.size.large}
size="large"
color="#00aa00"
/>
</View>

Просмотреть файл

@ -61,7 +61,7 @@ var NoneExample = React.createClass({
A: unspecified
</DemoText>
<View
pointerEvents={View.pointerEvents.none}
pointerEvents="none"
onTouchStart={() => this.props.onLog('B none touched')}
style={[styles.box, styles.boxPassedThrough]}>
<DemoText style={[styles.text, styles.textPassedThrough]}>
@ -87,7 +87,7 @@ var NoneExample = React.createClass({
var DemoText = React.createClass({
render: function() {
return (
<View pointerEvents={View.pointerEvents.none}>
<View pointerEvents="none">
<Text
style={this.props.style}>
{this.props.children}
@ -107,11 +107,11 @@ var BoxNoneExample = React.createClass({
A: unspecified
</DemoText>
<View
pointerEvents={View.pointerEvents.boxNone}
onTouchStart={() => this.props.onLog('B boxNone touched')}
pointerEvents="box-none"
onTouchStart={() => this.props.onLog('B box-none touched')}
style={[styles.box, styles.boxPassedThrough]}>
<DemoText style={[styles.text, styles.textPassedThrough]}>
B: boxNone
B: box-none
</DemoText>
<View
onTouchStart={() => this.props.onLog('C unspecified touched')}
@ -121,7 +121,7 @@ var BoxNoneExample = React.createClass({
</DemoText>
</View>
<View
pointerEvents={View.pointerEvents.unspecified}
pointerEvents="auto"
onTouchStart={() => this.props.onLog('C explicitly unspecified touched')}
style={[styles.box]}>
<DemoText style={[styles.text]}>
@ -144,11 +144,11 @@ var BoxOnlyExample = React.createClass({
A: unspecified
</DemoText>
<View
pointerEvents={View.pointerEvents.boxOnly}
onTouchStart={() => this.props.onLog('B boxOnly touched')}
pointerEvents="box-only"
onTouchStart={() => this.props.onLog('B box-only touched')}
style={styles.box}>
<DemoText style={styles.text}>
B: boxOnly
B: box-only
</DemoText>
<View
onTouchStart={() => this.props.onLog('C unspecified touched')}
@ -158,7 +158,7 @@ var BoxOnlyExample = React.createClass({
</DemoText>
</View>
<View
pointerEvents={View.pointerEvents.unspecified}
pointerEvents="auto"
onTouchStart={() => this.props.onLog('C explicitly unspecified touched')}
style={[styles.box, styles.boxPassedThrough]}>
<DemoText style={[styles.text, styles.textPassedThrough]}>
@ -179,13 +179,13 @@ var exampleClasses = [
},
{
Component: BoxNoneExample,
title: '`boxNone`',
description: '`boxNone` causes touch events on the container to pass through and will only detect touch events on its child components.',
title: '`box-none`',
description: '`box-none` causes touch events on the container to pass through and will only detect touch events on its child components.',
},
{
Component: BoxOnlyExample,
title: '`boxOnly`',
description: '`boxOnly` causes touch events on the container\'s child components to pass through and will only detect touch events on the container itself.',
title: '`box-only`',
description: '`box-only` causes touch events on the container\'s child components to pass through and will only detect touch events on the container itself.',
}
];

Просмотреть файл

@ -45,7 +45,7 @@ var TextEventsExample = React.createClass({
return (
<View>
<TextInput
autoCapitalize={TextInput.autoCapitalizeMode.none}
autoCapitalize="none"
placeholder="Enter text to see events"
autoCorrect={false}
onFocus={() => this.updateText('onFocus')}
@ -123,25 +123,25 @@ exports.examples = [
<View>
<WithLabel label="none">
<TextInput
autoCapitalize={TextInput.autoCapitalizeMode.none}
autoCapitalize="none"
style={styles.default}
/>
</WithLabel>
<WithLabel label="sentences">
<TextInput
autoCapitalize={TextInput.autoCapitalizeMode.sentences}
autoCapitalize="sentences"
style={styles.default}
/>
</WithLabel>
<WithLabel label="words">
<TextInput
autoCapitalize={TextInput.autoCapitalizeMode.words}
autoCapitalize="words"
style={styles.default}
/>
</WithLabel>
<WithLabel label="characters">
<TextInput
autoCapitalize={TextInput.autoCapitalizeMode.characters}
autoCapitalize="characters"
style={styles.default}
/>
</WithLabel>
@ -193,25 +193,25 @@ exports.examples = [
<WithLabel label="never">
<TextInput
style={styles.default}
clearButtonMode={TextInput.clearButtonModeTypes.never}
clearButtonMode="never"
/>
</WithLabel>
<WithLabel label="while editing">
<TextInput
style={styles.default}
clearButtonMode={TextInput.clearButtonModeTypes.whileEditing}
clearButtonMode="while-editing"
/>
</WithLabel>
<WithLabel label="unless editing">
<TextInput
style={styles.default}
clearButtonMode={TextInput.clearButtonModeTypes.unlessEditing}
clearButtonMode="unless-editing"
/>
</WithLabel>
<WithLabel label="always">
<TextInput
style={styles.default}
clearButtonMode={TextInput.clearButtonModeTypes.always}
clearButtonMode="always"
/>
</WithLabel>
</View>

Просмотреть файл

@ -6,7 +6,7 @@
'use strict';
var NativeMethodsMixin = require('NativeMethodsMixin');
var NativeModulesDeprecated = require('NativeModulesDeprecated');
var NativeModules = require('NativeModules');
var PropTypes = require('ReactPropTypes');
var React = require('React');
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
@ -37,12 +37,11 @@ var ActivityIndicatorIOS = React.createClass({
* The foreground color of the spinner (default is gray).
*/
color: PropTypes.string,
/**
* The size of the spinner, must be one of:
* - ActivityIndicatorIOS.size.large
* - ActivityIndicatorIOS.size.small (default)
*/
size: PropTypes.oneOf([SpinnerSize.large, SpinnerSize.small]),
size: PropTypes.oneOf([
'small', // default
'large',
]),
},
getDefaultProps: function() {
@ -53,15 +52,11 @@ var ActivityIndicatorIOS = React.createClass({
};
},
statics: {
size: SpinnerSize,
},
render: function() {
var style = styles.sizeSmall;
var NativeConstants = NativeModulesDeprecated.RKUIManager.UIActivityIndicatorView.Constants;
var NativeConstants = NativeModules.RKUIManager.UIActivityIndicatorView.Constants;
var activityIndicatorViewStyle = NativeConstants.StyleWhite;
if (this.props.size == SpinnerSize.large) {
if (this.props.size === 'large') {
style = styles.sizeLarge;
activityIndicatorViewStyle = NativeConstants.StyleWhiteLarge;
}

Просмотреть файл

@ -88,80 +88,80 @@ var ListView = React.createClass({
* - renderRow(rowData, sectionID, rowID);
* - renderSectionHeader(sectionData, sectionID);
*/
propTypes:
merge(
ScrollView.PropTypes, {
dataSource: PropTypes.instanceOf(ListViewDataSource).isRequired,
/**
* (rowData, sectionID, rowID) => renderable
* Takes a data entry from the data source and its ids and should return
* a renderable component to be rendered as the row. By default the data
* is exactly what was put into the data source, but it's also possible to
* provide custom extractors.
*/
renderRow: PropTypes.func.isRequired,
/**
* How many rows to render on initial component mount. Use this to make
* it so that the first screen worth of data apears at one time instead of
* over the course of multiple frames.
*/
initialListSize: PropTypes.number,
/**
* Called when all rows have been rendered and the list has been scrolled
* to within onEndReachedThreshold of the bottom. The native scroll
* event is provided.
*/
onEndReached: PropTypes.func,
/**
* Threshold in pixels for onEndReached.
*/
onEndReachedThreshold: PropTypes.number,
/**
* Number of rows to render per event loop.
*/
pageSize: PropTypes.number,
/**
* () => renderable
*
* The header and footer are always rendered (if these props are provided)
* on every render pass. If they are expensive to re-render, wrap them
* in StaticContainer or other mechanism as appropriate. Footer is always
* at the bottom of the list, and header at the top, on every render pass.
*/
renderFooter: PropTypes.func,
renderHeader: PropTypes.func,
/**
* (sectionData, sectionID) => renderable
*
* If provided, a sticky header is rendered for this section. The sticky
* behavior means that it will scroll with the content at the top of the
* section until it reaches the top of the screen, at which point it will
* stick to the top until it is pushed off the screen by the next section
* header.
*/
renderSectionHeader: PropTypes.func,
/**
* How early to start rendering rows before they come on screen, in
* pixels.
*/
scrollRenderAheadDistance: React.PropTypes.number,
/**
* (visibleRows, changedRows) => void
*
* Called when the set of visible rows changes. `visibleRows` maps
* { sectionID: { rowID: true }} for all the visible rows, and
* `changedRows` maps { sectionID: { rowID: true | false }} for the rows
* that have changed their visibility, with true indicating visible, and
* false indicating the view has moved out of view.
*/
onChangeVisibleRows: React.PropTypes.func,
/**
* An experimental performance optimization for improving scroll perf of
* large lists, used in conjunction with overflow: 'hidden' on the row
* containers. Use at your own risk.
*/
removeClippedSubviews: React.PropTypes.bool,
}),
propTypes: {
...ScrollView.propTypes,
dataSource: PropTypes.instanceOf(ListViewDataSource).isRequired,
/**
* (rowData, sectionID, rowID) => renderable
* Takes a data entry from the data source and its ids and should return
* a renderable component to be rendered as the row. By default the data
* is exactly what was put into the data source, but it's also possible to
* provide custom extractors.
*/
renderRow: PropTypes.func.isRequired,
/**
* How many rows to render on initial component mount. Use this to make
* it so that the first screen worth of data apears at one time instead of
* over the course of multiple frames.
*/
initialListSize: PropTypes.number,
/**
* Called when all rows have been rendered and the list has been scrolled
* to within onEndReachedThreshold of the bottom. The native scroll
* event is provided.
*/
onEndReached: PropTypes.func,
/**
* Threshold in pixels for onEndReached.
*/
onEndReachedThreshold: PropTypes.number,
/**
* Number of rows to render per event loop.
*/
pageSize: PropTypes.number,
/**
* () => renderable
*
* The header and footer are always rendered (if these props are provided)
* on every render pass. If they are expensive to re-render, wrap them
* in StaticContainer or other mechanism as appropriate. Footer is always
* at the bottom of the list, and header at the top, on every render pass.
*/
renderFooter: PropTypes.func,
renderHeader: PropTypes.func,
/**
* (sectionData, sectionID) => renderable
*
* If provided, a sticky header is rendered for this section. The sticky
* behavior means that it will scroll with the content at the top of the
* section until it reaches the top of the screen, at which point it will
* stick to the top until it is pushed off the screen by the next section
* header.
*/
renderSectionHeader: PropTypes.func,
/**
* How early to start rendering rows before they come on screen, in
* pixels.
*/
scrollRenderAheadDistance: React.PropTypes.number,
/**
* (visibleRows, changedRows) => void
*
* Called when the set of visible rows changes. `visibleRows` maps
* { sectionID: { rowID: true }} for all the visible rows, and
* `changedRows` maps { sectionID: { rowID: true | false }} for the rows
* that have changed their visibility, with true indicating visible, and
* false indicating the view has moved out of view.
*/
onChangeVisibleRows: React.PropTypes.func,
/**
* An experimental performance optimization for improving scroll perf of
* large lists, used in conjunction with overflow: 'hidden' on the row
* containers. Use at your own risk.
*/
removeClippedSubviews: React.PropTypes.bool,
},
/**
* Exports some data, e.g. for perf investigations or analytics.

Просмотреть файл

@ -45,9 +45,10 @@ var keyboardDismissModeConstants = {
* view from becoming the responder.
*/
var RKScrollViewPropTypes = merge(
ScrollViewPropTypes,
{
var ScrollView = React.createClass({
propTypes: {
...ScrollViewPropTypes,
/**
* When true, the scroll view bounces horizontally when it reaches the end
* even if the content is smaller than the scroll view itself. The default
@ -153,16 +154,8 @@ var keyboardDismissModeConstants = {
* The current scale of the scroll view content. The default value is 1.0.
*/
zoomScale: nativePropType(PropTypes.number),
}
);
var ScrollView = React.createClass({
statics: {
PropTypes: RKScrollViewPropTypes,
},
propTypes: RKScrollViewPropTypes,
mixins: [ScrollResponder.Mixin],
getInitialState: function() {

Просмотреть файл

@ -8,7 +8,7 @@
var DocumentSelectionState = require('DocumentSelectionState');
var EventEmitter = require('EventEmitter');
var NativeMethodsMixin = require('NativeMethodsMixin');
var NativeModulesDeprecated = require('NativeModulesDeprecated');
var RKUIManager = require('NativeModules').RKUIManager;
var PropTypes = require('ReactPropTypes');
var React = require('React');
var ReactChildren = require('ReactChildren');
@ -59,28 +59,8 @@ var merge = require('merge');
* More example code in `TextInputExample.js`.
*/
var nativeConstants = NativeModulesDeprecated.RKUIManager.UIText.AutocapitalizationType;
var autoCapitalizeMode = {
none: nativeConstants.None,
sentences: nativeConstants.Sentences,
words: nativeConstants.Words,
characters: nativeConstants.AllCharacters
};
var clearButtonModeConstants = NativeModulesDeprecated.RKUIManager.UITextField.clearButtonMode;
var clearButtonModeTypes = {
never: clearButtonModeConstants.Never,
whileEditing: clearButtonModeConstants.WhileEditing,
unlessEditing: clearButtonModeConstants.UnlessEditing,
always: clearButtonModeConstants.Always,
};
var keyboardType = {
default: 'default',
numeric: 'numeric',
};
var autoCapitalizeConsts = RKUIManager.UIText.AutocapitalizationType;
var clearButtonModeConsts = RKUIManager.UITextField.clearButtonMode;
var RKTextViewAttributes = merge(ReactIOSViewAttributes.UIView, {
autoCorrect: true,
@ -113,12 +93,6 @@ var notMultiline = {
};
var TextInput = React.createClass({
statics: {
autoCapitalizeMode: autoCapitalizeMode,
clearButtonModeTypes: clearButtonModeTypes,
keyboardType: keyboardType,
},
propTypes: {
/**
* Can tell TextInput to automatically capitalize certain characters.
@ -127,11 +101,13 @@ var TextInput = React.createClass({
* - words: first letter of each word
* - sentences: first letter of each sentence (default)
* - none: don't auto capitalize anything
*
* example:
* autoCapitalize={TextInput.autoCapitalizeMode.words}
*/
autoCapitalize: PropTypes.oneOf(getObjectValues(autoCapitalizeMode)),
autoCapitalize: PropTypes.oneOf([
'none',
'sentences',
'words',
'characters',
]),
/**
* If false, disables auto-correct. Default value is true.
*/
@ -145,9 +121,12 @@ var TextInput = React.createClass({
*/
editable: PropTypes.bool,
/**
* Determines which keyboard to open, e.g.`TextInput.keyboardType.numeric`.
* Determines which keyboard to open, e.g.`numeric`.
*/
keyboardType: PropTypes.oneOf(getObjectValues(keyboardType)),
keyboardType: PropTypes.oneOf([
'default',
'numeric',
]),
/**
* If true, the text input can be multiple lines. Default value is false.
*/
@ -202,7 +181,12 @@ var TextInput = React.createClass({
/**
* When the clear button should appear on the right side of the text view
*/
clearButtonMode: PropTypes.oneOf(getObjectValues(clearButtonModeTypes)),
clearButtonMode: PropTypes.oneOf([
'never',
'while-editing',
'unless-editing',
'always',
]),
style: Text.stylePropType,
},
@ -307,6 +291,9 @@ var TextInput = React.createClass({
render: function() {
var textContainer;
var autoCapitalize = autoCapitalizeConsts[this.props.autoCapitalize];
var clearButtonMode = clearButtonModeConsts[this.props.clearButtonMode];
if (!this.props.multiline) {
for (var propKey in onlyMultiline) {
if (this.props[propKey]) {
@ -329,9 +316,9 @@ var TextInput = React.createClass({
onSelectionChangeShouldSetResponder={() => true}
placeholder={this.props.placeholder}
text={this.state.bufferedValue}
autoCapitalize={this.props.autoCapitalize}
autoCapitalize={autoCapitalize}
autoCorrect={this.props.autoCorrect}
clearButtonMode={this.props.clearButtonMode}
clearButtonMode={clearButtonMode}
/>;
} else {
for (var propKey in notMultiline) {
@ -372,8 +359,9 @@ var TextInput = React.createClass({
placeholder={this.props.placeholder}
placeholderTextColor={this.props.placeholderTextColor}
text={this.state.bufferedValue}
autoCapitalize={this.props.autoCapitalize}
autoCapitalize={autoCapitalize}
autoCorrect={this.props.autoCorrect}
clearButtonMode={clearButtonMode}
/>;
}

Просмотреть файл

@ -6,7 +6,6 @@
'use strict';
var NativeMethodsMixin = require('NativeMethodsMixin');
var NativeModules = require('NativeModules');
var PropTypes = require('ReactPropTypes');
var React = require('React');
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
@ -45,15 +44,12 @@ var ViewStylePropTypes = require('ViewStylePropTypes');
* examples.
*/
var StyleConstants = NativeModules.RKUIManager.StyleConstants;
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
var stylePropType = StyleSheetPropType(ViewStylePropTypes);
var View = React.createClass({
statics: {
pointerEvents: StyleConstants.PointerEventsValues,
stylePropType,
},
@ -96,7 +92,7 @@ var View = React.createClass({
/**
* In the absence of `auto` property, `none` is much like `CSS`'s `none`
* value. `boxNone` is as if you had applied the `CSS` class:
* value. `box-none` is as if you had applied the `CSS` class:
*
* .cantTouchThis * {
* pointer-events: auto;
@ -112,10 +108,10 @@ var View = React.createClass({
* implementation detail of the platform.
*/
pointerEvents: PropTypes.oneOf([
StyleConstants.PointerEventsValues.boxNone,
StyleConstants.PointerEventsValues.none,
StyleConstants.PointerEventsValues.boxOnly,
StyleConstants.PointerEventsValues.unspecified
'box-none',
'none',
'box-only',
'auto',
]),
/**
@ -151,7 +147,6 @@ if (__DEV__) {
ViewToExport = View;
}
ViewToExport.pointerEvents = View.pointerEvents;
ViewToExport.stylePropType = stylePropType;
module.exports = ViewToExport;

Просмотреть файл

@ -51,13 +51,10 @@ function setupDocumentShim() {
throw getInvalidGlobalUseError('Image');
}
};
if (!GLOBAL.document) {
// This shouldn't be needed but scroller library fails without it. If
// we fixed the scroller, we wouldn't need this.
GLOBAL.document = {body: {}};
}
// Force `ExecutionEnvironment.canUseDOM` to be false.
GLOBAL.document.createElement = null;
if (GLOBAL.document) {
GLOBAL.document.createElement = null;
}
}
function handleErrorWithRedBox(e) {

Просмотреть файл

@ -33,7 +33,6 @@
+ (NSTextAlignment)NSTextAlignment:(id)json;
+ (NSWritingDirection)NSWritingDirection:(id)json;
+ (UITextAutocapitalizationType)UITextAutocapitalizationType:(id)json;
+ (UIKeyboardType)UIKeyboardType:(id)json;
+ (CGFloat)CGFloat:(id)json;

Просмотреть файл

@ -161,7 +161,7 @@ RCT_ENUM_CONVERTER(UITextAutocapitalizationType, (@{
@"none": @(UITextAutocapitalizationTypeNone),
@"words": @(UITextAutocapitalizationTypeWords),
@"sentences": @(UITextAutocapitalizationTypeSentences),
@"all": @(UITextAutocapitalizationTypeAllCharacters)
@"characters": @(UITextAutocapitalizationTypeAllCharacters)
}), UITextAutocapitalizationTypeSentences, integerValue)
RCT_ENUM_CONVERTER(UIKeyboardType, (@{
@ -658,8 +658,9 @@ RCT_ENUM_CONVERTER(css_wrap_type_t, (@{
RCT_ENUM_CONVERTER(RCTPointerEvents, (@{
@"none": @(RCTPointerEventsNone),
@"boxonly": @(RCTPointerEventsBoxOnly),
@"boxnone": @(RCTPointerEventsBoxNone)
@"box-only": @(RCTPointerEventsBoxOnly),
@"box-none": @(RCTPointerEventsBoxNone),
@"auto": @(RCTPointerEventsUnspecified)
}), RCTPointerEventsUnspecified, integerValue)
RCT_ENUM_CONVERTER(RCTAnimationType, (@{

Просмотреть файл

@ -1282,25 +1282,25 @@ static void RCTSetShadowViewProps(NSDictionary *props, RCTShadowView *shadowView
@"StyleConstants": @{
@"PointerEventsValues": @{
@"none": @(RCTPointerEventsNone),
@"boxNone": @(RCTPointerEventsBoxNone),
@"boxOnly": @(RCTPointerEventsBoxOnly),
@"unspecified": @(RCTPointerEventsUnspecified),
@"box-none": @(RCTPointerEventsBoxNone),
@"box-only": @(RCTPointerEventsBoxOnly),
@"auto": @(RCTPointerEventsUnspecified),
},
},
@"UIText": @{
@"AutocapitalizationType": @{
@"AllCharacters": @(UITextAutocapitalizationTypeAllCharacters),
@"Sentences": @(UITextAutocapitalizationTypeSentences),
@"Words": @(UITextAutocapitalizationTypeWords),
@"None": @(UITextAutocapitalizationTypeNone),
@"characters": @(UITextAutocapitalizationTypeAllCharacters),
@"sentences": @(UITextAutocapitalizationTypeSentences),
@"words": @(UITextAutocapitalizationTypeWords),
@"none": @(UITextAutocapitalizationTypeNone),
},
},
@"UITextField": @{
@"clearButtonMode": @{
@"Never": @(UITextFieldViewModeNever),
@"WhileEditing": @(UITextFieldViewModeWhileEditing),
@"UnlessEditing": @(UITextFieldViewModeUnlessEditing),
@"Always": @(UITextFieldViewModeAlways),
@"never": @(UITextFieldViewModeNever),
@"while-editing": @(UITextFieldViewModeWhileEditing),
@"unless-editing": @(UITextFieldViewModeUnlessEditing),
@"always": @(UITextFieldViewModeAlways),
},
},
@"UIView": @{

Просмотреть файл

@ -73,7 +73,16 @@ describe('processRequest', function() {
pit('returns JS bundle source on request of *.bundle',function() {
return makeRequest(
requestHandler,
'mybundle.includeRequire.runModule.bundle'
'mybundle.bundle?runModule=true'
).then(function(response) {
expect(response).toEqual('this is the source');
});
});
pit('returns JS bundle source on request of *.bundle (compat)',function() {
return makeRequest(
requestHandler,
'mybundle.runModule.bundle'
).then(function(response) {
expect(response).toEqual('this is the source');
});
@ -82,7 +91,7 @@ describe('processRequest', function() {
pit('returns sourcemap on request of *.map', function() {
return makeRequest(
requestHandler,
'mybundle.includeRequire.runModule.bundle.map'
'mybundle.map?runModule=true'
).then(function(response) {
expect(response).toEqual('"this is the source map"');
});
@ -91,8 +100,8 @@ describe('processRequest', function() {
pit('watches all files in projectRoot', function() {
return makeRequest(
requestHandler,
'mybundle.includeRequire.runModule.bundle'
).then(function(response) {
'mybundle.bundle?runModule=true'
).then(function() {
expect(watcherFunc.mock.calls[0][0]).toEqual('all');
expect(watcherFunc.mock.calls[0][1]).not.toBe(null);
});
@ -114,8 +123,8 @@ describe('processRequest', function() {
pit('invalides files in package when file is updated', function() {
return makeRequest(
requestHandler,
'mybundle.includeRequire.runModule.bundle'
).then(function(response) {
'mybundle.bundle?runModule=true'
).then(function() {
var onFileChange = watcherFunc.mock.calls[0][1];
onFileChange('all','path/file.js', options.projectRoots[0]);
expect(invalidatorFunc.mock.calls[0][0]).toEqual('root/path/file.js');
@ -150,7 +159,7 @@ describe('processRequest', function() {
requestHandler = server.processRequest.bind(server);
return makeRequest(requestHandler,'mybundle.includeRequire.runModule.bundle')
return makeRequest(requestHandler, 'mybundle.bundle?runModule=true')
.then(function(response) {
expect(response).toEqual('this is the first source');
expect(packageFunc.mock.calls.length).toBe(1);
@ -159,7 +168,7 @@ describe('processRequest', function() {
})
.then(function() {
expect(packageFunc.mock.calls.length).toBe(2);
return makeRequest(requestHandler,'mybundle.includeRequire.runModule.bundle')
return makeRequest(requestHandler, 'mybundle.bundle?runModule=true')
.then(function(response) {
expect(response).toEqual('this is the rebuilt source');
});

44
packager/react-packager/src/Server/index.js поставляемый
Просмотреть файл

@ -77,7 +77,7 @@ Server.prototype._rebuildPackages = function() {
var buildPackage = this._buildPackage.bind(this);
var packages = this._packages;
Object.keys(packages).forEach(function(key) {
var options = getOptionsFromPath(url.parse(key).pathname);
var options = getOptionsFromUrl(key);
packages[key] = buildPackage(options).then(function(p) {
// Make a throwaway call to getSource to cache the source string.
p.getSource({inlineSourceMap: dev});
@ -102,7 +102,7 @@ Server.prototype._buildPackage = function(options) {
};
Server.prototype.buildPackageFromUrl = function(reqUrl) {
var options = getOptionsFromPath(url.parse(reqUrl).pathname);
var options = getOptionsFromUrl(reqUrl);
return this._buildPackage(options);
};
@ -145,21 +145,26 @@ Server.prototype._processDebugRequest = function(reqUrl, res) {
};
Server.prototype.processRequest = function(req, res, next) {
var urlObj = url.parse(req.url, true);
var pathname = urlObj.pathname;
var requestType;
if (req.url.match(/\.bundle$/)) {
if (pathname.match(/\.bundle$/)) {
requestType = 'bundle';
} else if (req.url.match(/\.map$/)) {
} else if (pathname.match(/\.map$/)) {
requestType = 'map';
} else if (req.url.match(/^\/debug/)) {
} else if (pathname.match(/^\/debug/)) {
this._processDebugRequest(req.url, res);
return;
} else {
return next();
next();
return;
}
var startReqEventId = Activity.startEvent('request:' + req.url);
var options = getOptionsFromPath(url.parse(req.url).pathname);
var options = getOptionsFromUrl(req.url);
var building = this._packages[req.url] || this._buildPackage(options);
this._packages[req.url] = building;
var dev = this._dev;
building.then(
@ -178,16 +183,25 @@ Server.prototype.processRequest = function(req, res, next) {
).done();
};
function getOptionsFromPath(pathname) {
var parts = pathname.split('.');
// Remove the leading slash.
var main = parts[0].slice(1) + '.js';
function getOptionsFromUrl(reqUrl) {
// `true` to parse the query param as an object.
var urlObj = url.parse(reqUrl, true);
var match = urlObj.pathname.match(/^\/?([^\.]+)\..*(bundle|map)$/);
if (!(match && match[1])) {
throw new Error('Invalid url format, expected "/path/to/file.bundle"');
}
var main = match[1] + '.js';
return {
runModule: parts.slice(1).some(function(part) {
return part === 'runModule';
}),
sourceMapUrl: urlObj.pathname.replace(/\.bundle$/, '.map'),
main: main,
sourceMapUrl: parts.slice(0, -1).join('.') + '.map'
runModule: urlObj.query.runModule === 'true' ||
urlObj.query.runModule === '1' ||
// Backwards compatibility.
urlObj.pathname.split('.').some(function(part) {
return part === 'runModule';
}),
};
}