diff --git a/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js b/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js index f7537669f..a75b166e2 100644 --- a/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js +++ b/Libraries/JavaScriptAppEngine/Initialization/ExceptionsManager.js @@ -11,37 +11,37 @@ */ 'use strict'; -var sourceMapPromise; - -var exceptionID = 0; +let exceptionID = 0; /** * Handles the developer-visible aspect of errors and exceptions */ function reportException(e: Error, isFatal: bool) { - var loadSourceMap = require('loadSourceMap'); - var parseErrorStack = require('parseErrorStack'); - var RCTExceptionsManager = require('NativeModules').ExceptionsManager; + const parseErrorStack = require('parseErrorStack'); + const RCTExceptionsManager = require('NativeModules').ExceptionsManager; - var currentExceptionID = ++exceptionID; + const currentExceptionID = ++exceptionID; if (RCTExceptionsManager) { - var stack = parseErrorStack(e); + const stack = parseErrorStack(e); if (isFatal) { RCTExceptionsManager.reportFatalException(e.message, stack, currentExceptionID); } else { RCTExceptionsManager.reportSoftException(e.message, stack, currentExceptionID); } if (__DEV__) { - (sourceMapPromise = sourceMapPromise || loadSourceMap()) - .then(map => { - var prettyStack = parseErrorStack(e, map); - RCTExceptionsManager.updateExceptionMessage(e.message, prettyStack, currentExceptionID); - }) - .catch(error => { - // This can happen in a variety of normal situations, such as - // Network module not being available, or when running locally - console.warn('Unable to load source map: ' + error.message); - }); + require('SourceMapsCache').getSourceMaps().then(sourceMaps => { + const prettyStack = parseErrorStack(e, sourceMaps); + RCTExceptionsManager.updateExceptionMessage( + e.message, + prettyStack, + currentExceptionID, + ); + }) + .catch(error => { + // This can happen in a variety of normal situations, such as + // Network module not being available, or when running locally + console.warn('Unable to load source map: ' + error.message); + }); } } } @@ -81,15 +81,15 @@ function installConsoleErrorReporter() { if (arguments[0] && arguments[0].stack) { reportException(arguments[0], /* isFatal */ false); } else { - var stringifySafe = require('stringifySafe'); - var str = Array.prototype.map.call(arguments, stringifySafe).join(', '); + const stringifySafe = require('stringifySafe'); + const str = Array.prototype.map.call(arguments, stringifySafe).join(', '); if (str.slice(0, 10) === '"Warning: ') { // React warnings use console.error so that a stack trace is shown, but // we don't (currently) want these to show a redbox // (Note: Logic duplicated in polyfills/console.js.) return; } - var error : any = new Error('console.error: ' + str); + const error : any = new Error('console.error: ' + str); error.framesToPop = 1; reportException(error, /* isFatal */ false); } diff --git a/Libraries/JavaScriptAppEngine/Initialization/SourceMapsCache.js b/Libraries/JavaScriptAppEngine/Initialization/SourceMapsCache.js new file mode 100644 index 000000000..63ab9c642 --- /dev/null +++ b/Libraries/JavaScriptAppEngine/Initialization/SourceMapsCache.js @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule SourceMapsCache + */ +'use strict'; + +const getObjectValues = require('getObjectValues'); +const SourceMapsUtils = require('SourceMapsUtils'); + +const sourceMapsCache = {}; + +const SourceMapsCache = { + mainSourceMapID: 'main', + + fetch({text, url, fullSourceMappingURL}) { + const sourceMappingURL = fullSourceMappingURL + ? fullSourceMappingURL + : SourceMapsUtils.extractSourceMapURL({text, url}); + + sourceMapsCache[sourceMappingURL] = SourceMapsUtils.fetchSourceMap( + sourceMappingURL + ); + }, + + getSourceMaps() { + fetchMainSourceMap(); + return Promise.all(getObjectValues(sourceMapsCache)); + }, +}; + +function fetchMainSourceMap() { + if (!sourceMapsCache[SourceMapsCache.mainSourceMapID]) { + sourceMapsCache[SourceMapsCache.mainSourceMapID] = + SourceMapsUtils.fetchMainSourceMap(); + } +} + +module.exports = SourceMapsCache; diff --git a/Libraries/JavaScriptAppEngine/Initialization/SourceMapsUtils.js b/Libraries/JavaScriptAppEngine/Initialization/SourceMapsUtils.js new file mode 100644 index 000000000..f49a107c1 --- /dev/null +++ b/Libraries/JavaScriptAppEngine/Initialization/SourceMapsUtils.js @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule SourceMapsUtils + * @flow + */ + +'use strict'; + +var HMRClient = require('../../Utilities/HMRClient'); +var Promise = require('Promise'); +var NativeModules = require('NativeModules'); +var SourceMapConsumer = require('SourceMap').SourceMapConsumer; +var SourceMapURL = require('./source-map-url'); + +var RCTSourceCode = NativeModules.SourceCode; +var RCTNetworking = NativeModules.Networking; + +var SourceMapsUtils = { + fetchMainSourceMap(): Promise { + return SourceMapsUtils._getMainSourceMapURL().then(url => + SourceMapsUtils.fetchSourceMap(url) + ); + }, + + fetchSourceMap(sourceMappingURL: string): Promise { + return fetch(sourceMappingURL) + .then(response => response.text()) + .then(map => new SourceMapConsumer(map)); + }, + + extractSourceMapURL(data: ({url:string, text:string})): ?string { + const url = data.url; + const text = data.text; + var mapURL = SourceMapURL.getFrom(text); + if (!mapURL) { + return null; + } + var baseURLs = url.match(/(.+:\/\/.*?)\//); + if (!baseURLs || baseURLs.length < 2) { + return null; + } + return baseURLs[1] + mapURL; + }, + + _getMainSourceMapURL(): Promise { + if (global.RAW_SOURCE_MAP) { + return Promise.resolve(global.RAW_SOURCE_MAP); + } + + if (!RCTSourceCode) { + return Promise.reject(new Error('RCTSourceCode module is not available')); + } + + if (!RCTNetworking) { + // Used internally by fetch + return Promise.reject(new Error('RCTNetworking module is not available')); + } + + return RCTSourceCode.getScriptText() + .then(SourceMapsUtils.extractSourceMapURL) + .then((url) => { + if (url === null) { + return Promise.reject(new Error('No source map URL found. May be running from bundled file.')); + } + return Promise.resolve(url); + }); + }, +}; + +module.exports = SourceMapsUtils; diff --git a/Libraries/JavaScriptAppEngine/Initialization/loadSourceMap.js b/Libraries/JavaScriptAppEngine/Initialization/loadSourceMap.js deleted file mode 100644 index 852579c60..000000000 --- a/Libraries/JavaScriptAppEngine/Initialization/loadSourceMap.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @providesModule loadSourceMap - * @flow - */ - -'use strict'; - -var Promise = require('Promise'); -var NativeModules = require('NativeModules'); -var SourceMapConsumer = require('SourceMap').SourceMapConsumer; -var SourceMapURL = require('./source-map-url'); - -var RCTSourceCode = NativeModules.SourceCode; -var RCTNetworking = NativeModules.Networking; - -function loadSourceMap(): Promise { - return fetchSourceMap() - .then(map => new SourceMapConsumer(map)); -} - -function fetchSourceMap(): Promise { - if (global.RAW_SOURCE_MAP) { - return Promise.resolve(global.RAW_SOURCE_MAP); - } - - if (!RCTSourceCode) { - return Promise.reject(new Error('RCTSourceCode module is not available')); - } - - if (!RCTNetworking) { - // Used internally by fetch - return Promise.reject(new Error('RCTNetworking module is not available')); - } - - return RCTSourceCode.getScriptText() - .then(extractSourceMapURL) - .then((url) => { - if (url === null) { - return Promise.reject(new Error('No source map URL found. May be running from bundled file.')); - } - return Promise.resolve(url); - }) - .then(fetch) - .then(response => response.text()); -} - -function extractSourceMapURL({url, text, fullSourceMappingURL}): ?string { - if (fullSourceMappingURL) { - return fullSourceMappingURL; - } - var mapURL = SourceMapURL.getFrom(text); - if (!mapURL) { - return null; - } - var baseURL = url.match(/(.+:\/\/.*?)\//)[1]; - return baseURL + mapURL; -} - -module.exports = loadSourceMap; diff --git a/Libraries/JavaScriptAppEngine/Initialization/parseErrorStack.js b/Libraries/JavaScriptAppEngine/Initialization/parseErrorStack.js index 63076c7b8..5fec94315 100644 --- a/Libraries/JavaScriptAppEngine/Initialization/parseErrorStack.js +++ b/Libraries/JavaScriptAppEngine/Initialization/parseErrorStack.js @@ -19,7 +19,11 @@ function resolveSourceMaps(sourceMapInstance, stackFrame) { column: stackFrame.column, }); if (orig) { - stackFrame.file = orig.source; + // remove query string if any + const queryStringStartIndex = orig.source.indexOf('?'); + stackFrame.file = queryStringStartIndex === -1 + ? orig.source + : orig.source.substring(0, queryStringStartIndex); stackFrame.lineNumber = orig.line; stackFrame.column = orig.column; } @@ -27,7 +31,7 @@ function resolveSourceMaps(sourceMapInstance, stackFrame) { } } -function parseErrorStack(e, sourceMapInstance) { +function parseErrorStack(e, sourceMaps) { if (!e || !e.stack) { return []; } @@ -39,8 +43,17 @@ function parseErrorStack(e, sourceMapInstance) { stack.shift(); } - if (sourceMapInstance) { - stack.forEach(resolveSourceMaps.bind(null, sourceMapInstance)); + if (sourceMaps) { + sourceMaps.forEach((sourceMap, index) => { + stack.forEach(frame => { + if (frame.file.indexOf(sourceMap.file) !== -1 || + frame.file.replace('.map', '.bundle').indexOf( + sourceMap.file + ) !== -1) { + resolveSourceMaps(sourceMap, frame); + } + }); + }); } return stack; diff --git a/Libraries/JavaScriptAppEngine/Initialization/source-map-url.js b/Libraries/JavaScriptAppEngine/Initialization/source-map-url.js index 8342a5a90..f44740031 100644 --- a/Libraries/JavaScriptAppEngine/Initialization/source-map-url.js +++ b/Libraries/JavaScriptAppEngine/Initialization/source-map-url.js @@ -29,7 +29,7 @@ void (function(root, factory) { } }(this, function() { - var innerRegex = /[#@] sourceMappingURL=([^\s'"]*)/ + var innerRegex = /[#@] source(?:Mapping)?URL=([^\s'"]*)/ var regex = RegExp( "(?:" + diff --git a/Libraries/Utilities/HMRClient.js b/Libraries/Utilities/HMRClient.js index f500748d5..79be2be45 100644 --- a/Libraries/Utilities/HMRClient.js +++ b/Libraries/Utilities/HMRClient.js @@ -25,7 +25,7 @@ const HMRClient = { const host = 'localhost'; const port = '8081'; - // need to require WebSocket inside of `enable` function because the + // need to require WebSocket inside of `enable` function because // this module is defined as a `polyfillGlobal`. // See `InitializeJavascriptAppEngine.js` const WebSocket = require('WebSocket'); @@ -51,7 +51,31 @@ Error: ${e.message}` activeWS.onmessage = ({data}) => { data = JSON.parse(data); if (data.type === 'update') { - eval(data.body); // eslint-disable-line no-eval + const modules = data.body.modules; + const sourceMappingURLs = data.body.sourceMappingURLs; + const sourceURLs = data.body.sourceURLs; + + const RCTRedBox = require('NativeModules').RedBox; + RCTRedBox && RCTRedBox.dismiss && RCTRedBox.dismiss(); + + modules.forEach((code, i) => { + code = code + '\n\n' + sourceMappingURLs[i]; + + require('SourceMapsCache').fetch({ + text: code, + url: sourceURLs[i], + sourceMappingURL: sourceMappingURLs[i], + }); + + // on JSC we need to inject from native for sourcemaps to work + // (Safari doesn't support `sourceMappingURL` nor any variant when + // evaluating code) but on Chrome we can simply use eval + const injectFunction = typeof __injectHMRUpdate === 'function' + ? __injectHMRUpdate + : eval; + + injectFunction(code, sourceURLs[i]); + }) return; } diff --git a/React/Executors/RCTJSCExecutor.m b/React/Executors/RCTJSCExecutor.m index 6e5736a9f..9e4c6201e 100644 --- a/React/Executors/RCTJSCExecutor.m +++ b/React/Executors/RCTJSCExecutor.m @@ -23,6 +23,8 @@ #import "RCTPerformanceLogger.h" #import "RCTUtils.h" #import "RCTJSCProfiler.h" +#import "RCTRedBox.h" +#import "RCTSourceCode.h" static NSString *const RCTJSCProfilerEnabledDefaultsKey = @"RCTJSCProfilerEnabled"; @@ -493,6 +495,22 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context) RCTAssertParam(sourceURL); __weak RCTJSCExecutor *weakSelf = self; +#if RCT_DEV + _context.context[@"__injectHMRUpdate"] = ^(NSString *sourceCode, NSString *sourceCodeURL) { + RCTJSCExecutor *strongSelf = weakSelf; + + if (!strongSelf) { + return; + } + + JSStringRef execJSString = JSStringCreateWithUTF8CString(sourceCode.UTF8String); + JSStringRef jsURL = JSStringCreateWithUTF8CString(sourceCodeURL.UTF8String); + JSEvaluateScript(strongSelf->_context.ctx, execJSString, NULL, jsURL, 0, NULL); + JSStringRelease(jsURL); + JSStringRelease(execJSString); + }; +#endif + [self executeBlockOnJavaScriptQueue:RCTProfileBlock((^{ RCTJSCExecutor *strongSelf = weakSelf; if (!strongSelf || !strongSelf.isValid) { diff --git a/React/Modules/RCTRedBox.m b/React/Modules/RCTRedBox.m index b8717b150..ec0cfb850 100644 --- a/React/Modules/RCTRedBox.m +++ b/React/Modules/RCTRedBox.m @@ -309,7 +309,7 @@ RCT_EXPORT_MODULE() }); } -- (void)dismiss +RCT_EXPORT_METHOD(dismiss) { dispatch_async(dispatch_get_main_queue(), ^{ [_window dismiss]; diff --git a/local-cli/server/util/attachHMRServer.js b/local-cli/server/util/attachHMRServer.js index 4a118d399..c3ea086ed 100644 --- a/local-cli/server/util/attachHMRServer.js +++ b/local-cli/server/util/attachHMRServer.js @@ -171,17 +171,18 @@ function attachHMRServer({httpServer, path, packagerServer}) { }) }) .then(bundle => { - if (!client || !bundle) { + if (!client || !bundle || bundle.isEmpty()) { return; } - const hmrUpdate = bundle.getSource(); - if (hmrUpdate) { - return JSON.stringify({ - type: 'update', - body: hmrUpdate, - }); - } + return JSON.stringify({ + type: 'update', + body: { + modules: bundle.getModulesCode(), + sourceURLs: bundle.getSourceURLs(), + sourceMappingURLs: bundle.getSourceMappingURLs(), + }, + }); }) .catch(error => { // send errors to the client instead of killing packager server @@ -207,7 +208,7 @@ function attachHMRServer({httpServer, path, packagerServer}) { return JSON.stringify({type: 'error', body}); }) .then(update => { - if (!client) { + if (!client || !update) { return; } diff --git a/packager/react-packager/src/Bundler/Bundle.js b/packager/react-packager/src/Bundler/Bundle.js index 2641550a0..9700af088 100644 --- a/packager/react-packager/src/Bundler/Bundle.js +++ b/packager/react-packager/src/Bundler/Bundle.js @@ -206,7 +206,7 @@ class Bundle extends BundleBase { _getCombinedSourceMaps(options) { const result = { version: 3, - file: 'bundle.js', + file: this._getSourceMapFile(), sections: [], }; @@ -246,7 +246,7 @@ class Bundle extends BundleBase { const mappings = this._getMappings(); const map = { - file: 'bundle.js', + file: this._getSourceMapFile(), sources: _.pluck(super.getModules(), 'sourcePath'), version: 3, names: [], @@ -262,6 +262,12 @@ class Bundle extends BundleBase { return eTag; } + _getSourceMapFile() { + return this._sourceMapUrl + ? this._sourceMapUrl.replace('.map', '.bundle') + : 'bundle.js'; + } + _getMappings() { const modules = super.getModules(); diff --git a/packager/react-packager/src/Bundler/BundleBase.js b/packager/react-packager/src/Bundler/BundleBase.js index b9e1cbe36..79cbfefc3 100644 --- a/packager/react-packager/src/Bundler/BundleBase.js +++ b/packager/react-packager/src/Bundler/BundleBase.js @@ -19,6 +19,10 @@ class BundleBase { this._mainModuleId = this._mainModuleName = undefined; } + isEmpty() { + return this._modules.length === 0 && this._assets.length === 0; + } + getMainModuleId() { return this._mainModuleId; } diff --git a/packager/react-packager/src/Bundler/HMRBundle.js b/packager/react-packager/src/Bundler/HMRBundle.js index fa8c95db7..49a21dfd8 100644 --- a/packager/react-packager/src/Bundler/HMRBundle.js +++ b/packager/react-packager/src/Bundler/HMRBundle.js @@ -8,12 +8,17 @@ */ 'use strict'; +const _ = require('underscore'); const BundleBase = require('./BundleBase'); const ModuleTransport = require('../lib/ModuleTransport'); class HMRBundle extends BundleBase { - constructor() { + constructor({sourceURLFn, sourceMappingURLFn}) { super(); + this._sourceURLFn = sourceURLFn + this._sourceMappingURLFn = sourceMappingURLFn; + this._sourceURLs = []; + this._sourceMappingURLs = []; } addModule(resolver, response, module, transformed) { @@ -21,14 +26,8 @@ class HMRBundle extends BundleBase { module, transformed.code, ).then(({name, code}) => { - code = ` - __accept( - '${name}', - function(global, require, module, exports) { - ${code} - } - ); - `; + // need to be in single line so that lines match on sourcemaps + code = `__accept(${JSON.stringify(name)}, function(global, require, module, exports) { ${code} });`; const moduleTransport = new ModuleTransport({ code, @@ -40,8 +39,22 @@ class HMRBundle extends BundleBase { }); super.addModule(moduleTransport); + this._sourceMappingURLs.push(this._sourceMappingURLFn(moduleTransport.sourcePath)); + this._sourceURLs.push(this._sourceURLFn(moduleTransport.sourcePath)); }); } + + getModulesCode() { + return this._modules.map(module => module.code); + } + + getSourceURLs() { + return this._sourceURLs; + } + + getSourceMappingURLs() { + return this._sourceMappingURLs; + } } module.exports = HMRBundle; diff --git a/packager/react-packager/src/Bundler/__tests__/Bundle-test.js b/packager/react-packager/src/Bundler/__tests__/Bundle-test.js index 5e5fca226..b4152a7b2 100644 --- a/packager/react-packager/src/Bundler/__tests__/Bundle-test.js +++ b/packager/react-packager/src/Bundler/__tests__/Bundle-test.js @@ -214,7 +214,7 @@ describe('Bundle', () => { const sourceMap = otherBundle.getSourceMap({dev: true}); expect(sourceMap).toEqual({ - file: 'bundle.js', + file: 'test_url', version: 3, sections: [ { offset: { line: 0, column: 0 }, map: { name: 'sourcemap foo' } }, @@ -340,7 +340,7 @@ describe('Bundle', () => { function genSourceMap(modules) { - var sourceMapGen = new SourceMapGenerator({file: 'bundle.js', version: 3}); + var sourceMapGen = new SourceMapGenerator({file: 'test_url', version: 3}); var bundleLineNo = 0; for (var i = 0; i < modules.length; i++) { var module = modules[i]; diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js index b6ff91333..d2852d447 100644 --- a/packager/react-packager/src/Bundler/index.js +++ b/packager/react-packager/src/Bundler/index.js @@ -166,9 +166,58 @@ class Bundler { }); } + _sourceHMRURL(platform, path) { + return this._hmrURL( + 'http://localhost:8081', // TODO: (martinb) avoid hardcoding + platform, + 'bundle', + path, + ); + } + + _sourceMappingHMRURL(platform, path) { + // Chrome expects `sourceURL` when eval'ing code + return this._hmrURL( + '\/\/# sourceURL=', + platform, + 'map', + path, + ); + } + + _hmrURL(prefix, platform, extensionOverride, path) { + const matchingRoot = this._projectRoots.find(root => path.startsWith(root)); + + if (!matchingRoot) { + throw new Error('No matching project root for ', path); + } + + const extensionStart = path.lastIndexOf('.'); + let resource = path.substring( + matchingRoot.length, + extensionStart !== -1 ? extensionStart : undefined, + ); + + const extension = extensionStart !== -1 + ? path.substring(extensionStart + 1) + : null; + + return ( + prefix + resource + + '.' + extensionOverride + '?' + + 'platform=' + platform + '&runModule=false&entryModuleOnly=true&hot=true' + ); + } + bundleForHMR(options) { return this._bundle({ - bundle: new HMRBundle(), + bundle: new HMRBundle({ + sourceURLFn: this._sourceHMRURL.bind(this, options.platform), + sourceMappingURLFn: this._sourceMappingHMRURL.bind( + this, + options.platform, + ), + }), hot: true, ...options, }); @@ -185,6 +234,7 @@ class Bundler { platform, unbundle: isUnbundle, hot: hot, + entryModuleOnly, }) { const findEventId = Activity.startEvent('find dependencies'); let transformEventId; @@ -195,18 +245,25 @@ class Bundler { bundle.setMainModuleName(response.mainModuleId); transformEventId = Activity.startEvent('transform'); - const moduleSystemDeps = includeSystemDependencies - ? this._resolver.getModuleSystemDependencies( - { dev: isDev, platform, isUnbundle } - ) - : []; + let dependencies; + if (entryModuleOnly) { + dependencies = response.dependencies.filter(module => + module.path.endsWith(entryFile) + ); + } else { + const moduleSystemDeps = includeSystemDependencies + ? this._resolver.getModuleSystemDependencies( + { dev: isDev, platform, isUnbundle } + ) + : []; - const modulesToProcess = modules || response.dependencies; - const dependencies = moduleSystemDeps.concat(modulesToProcess); + const modulesToProcess = modules || response.dependencies; + const dependencies = moduleSystemDeps.concat(modulesToProcess); - bundle.setNumPrependedModules && bundle.setNumPrependedModules( - response.numPrependedDependencies + moduleSystemDeps.length - ); + bundle.setNumPrependedModules && bundle.setNumPrependedModules( + response.numPrependedDependencies + moduleSystemDeps.length + ); + } let bar; if (process.stdout.isTTY) { diff --git a/packager/react-packager/src/Server/__tests__/Server-test.js b/packager/react-packager/src/Server/__tests__/Server-test.js index 123134f84..668e162f0 100644 --- a/packager/react-packager/src/Server/__tests__/Server-test.js +++ b/packager/react-packager/src/Server/__tests__/Server-test.js @@ -144,6 +144,7 @@ describe('processRequest', () => { platform: undefined, runBeforeMainModule: ['InitializeJavaScriptAppEngine'], unbundle: false, + entryModuleOnly: false, }); }); }); @@ -165,6 +166,7 @@ describe('processRequest', () => { platform: 'ios', runBeforeMainModule: ['InitializeJavaScriptAppEngine'], unbundle: false, + entryModuleOnly: false, }); }); }); @@ -321,6 +323,7 @@ describe('processRequest', () => { platform: undefined, runBeforeMainModule: ['InitializeJavaScriptAppEngine'], unbundle: false, + entryModuleOnly: false, }) ); }); @@ -341,6 +344,7 @@ describe('processRequest', () => { platform: undefined, runBeforeMainModule: ['InitializeJavaScriptAppEngine'], unbundle: false, + entryModuleOnly: false, }) ); }); diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js index 99a3472d6..559fb3022 100644 --- a/packager/react-packager/src/Server/index.js +++ b/packager/react-packager/src/Server/index.js @@ -118,6 +118,10 @@ const bundleOpts = declareOpts({ type: 'boolean', default: false, }, + entryModuleOnly: { + type: 'boolean', + default: false, + }, }); const dependencyOpts = declareOpts({ @@ -527,6 +531,11 @@ class Server { false ), platform: platform, + entryModuleOnly: this._getBoolOptionFromQuery( + urlObj.query, + 'entryModuleOnly', + false, + ), }; }