mirror of
https://github.com/status-im/metro.git
synced 2025-02-09 09:43:39 +00:00
Updates from Thu 19 Mar
- [ReactNative] Add root package.json name back | Tadeu Zagallo - [react-packager] Make sure projectRoots is converted to an array | Amjad Masad - [ReactNative] Init script that bootstraps new Xcode project | Alex Kotliarskyi - [ReactNative] New SampleApp | Alex Kotliarskyi - [ReactNative] Touchable invoke press on longPress when longPress handler missing | Eric Vicenti - [ReactNative] Commit missing RCTWebSocketDebugger.xcodeproj | Alex Kotliarskyi - [ReactNative] Add Custom Components folder | Christopher Chedeau - [react-packager] Hash cache file name information to avoid long names | Amjad Masad - [ReactNative] Put all iOS-related files in a subfolder | Alex Kotliarskyi - [react-packager] Fix OOM | Amjad Masad - [ReactNative] Bring Chrome debugger to OSS. Part 2 | Alex Kotliarskyi - [ReactNative] Add search to UIExplorer | Tadeu Zagallo - [ReactNative][RFC] Bring Chrome debugger to OSS. Part 1 | Alex Kotliarskyi - [ReactNative] Return the appropriate status code from XHR | Tadeu Zagallo - [ReactNative] Make JS stack traces in Xcode prettier | Alex Kotliarskyi - [ReactNative] Remove duplicate package.json with the same name | Christopher Chedeau - [ReactNative] Remove invariant from require('react-native') | Christopher Chedeau - [ReactNative] Remove ListViewDataSource from require('react-native') | Christopher Chedeau - [react-packager] Add assetRoots option | Amjad Masad - Convert UIExplorer to ListView | Christopher Chedeau - purge rni | Basil Hosmer - [ReactNative] s/render*View/render/ in <WebView> | Christopher Chedeau
This commit is contained in:
parent
e3025bb624
commit
d11511f5dd
112
debugger.html
Normal file
112
debugger.html
Normal file
@ -0,0 +1,112 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<!-- Fake favicon, to avoid extra request to server -->
|
||||
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
|
||||
<title>React Native Debugger</title>
|
||||
<script>
|
||||
(function() {
|
||||
|
||||
var sessionID = window.localStorage.getItem('sessionID');
|
||||
window.localStorage.removeItem('sessionID');
|
||||
|
||||
window.onbeforeunload = function() {
|
||||
if (sessionID) {
|
||||
return 'If you reload this page, it is going to break the debugging session. ' +
|
||||
'You should ⌘+R in the iOS simulator to reload.';
|
||||
}
|
||||
};
|
||||
|
||||
function setStatus(status) {
|
||||
document.getElementById('status').innerHTML = status;
|
||||
}
|
||||
|
||||
var messageHandlers = {
|
||||
// This method is a bit hacky. Catalyst asks for a new clean JS runtime.
|
||||
// The easiest way to do this is to reload this page. That also means that
|
||||
// web socket connection will be lost. To send reply back we need to remember
|
||||
// message id
|
||||
'prepareJSRuntime': function(message) {
|
||||
window.onbeforeunload = undefined;
|
||||
window.localStorage.setItem('sessionID', message.id);
|
||||
window.location.reload();
|
||||
},
|
||||
'executeApplicationScript:sourceURL:onComplete:': function(message, sendReply) {
|
||||
for (var key in message.inject) {
|
||||
window[key] = JSON.parse(message.inject[key]);
|
||||
}
|
||||
loadScript(message.url, sendReply.bind(null, null));
|
||||
},
|
||||
'executeJSCall:method:arguments:callback:': function(message, sendReply) {
|
||||
var returnValue = [[], [], [], [], []];
|
||||
try {
|
||||
if (window && window.require) {
|
||||
returnValue = window.require(message.moduleName)[message.moduleMethod].apply(null, message.arguments);
|
||||
}
|
||||
} finally {
|
||||
sendReply(JSON.stringify(returnValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var ws = new WebSocket('ws://' + window.location.host + '/debugger-proxy');
|
||||
|
||||
ws.onopen = function() {
|
||||
if (sessionID) {
|
||||
setStatus('Debugger session #' + sessionID + ' active');
|
||||
ws.send(JSON.stringify({replyID: parseInt(sessionID, 10)}));
|
||||
} else {
|
||||
setStatus('Waiting for simulator');
|
||||
}
|
||||
}
|
||||
|
||||
ws.onmessage = function(message) {
|
||||
var object = JSON.parse(message.data);
|
||||
var sendReply = function(result) {
|
||||
ws.send(JSON.stringify({replyID: object.id, result: result}));
|
||||
}
|
||||
var handler = messageHandlers[object.method];
|
||||
if (handler) {
|
||||
handler(object, sendReply);
|
||||
} else {
|
||||
console.warn('Unknown method: ' + object.method);
|
||||
}
|
||||
}
|
||||
|
||||
ws.onclose = function() {
|
||||
setStatus('Disconnected from proxy. Is node server running?');
|
||||
}
|
||||
|
||||
function loadScript(src, callback) {
|
||||
var script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.src = src;
|
||||
script.onload = callback;
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
|
||||
})();
|
||||
</script>
|
||||
<style type="text/css">
|
||||
.shortcut {
|
||||
font-family: monospace;
|
||||
color: #eee;
|
||||
background-color: #333;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
letter-spacing: 3px;
|
||||
}
|
||||
body {
|
||||
font-size: large;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
React Native JS code runs inside this Chrome tab
|
||||
</p>
|
||||
<p>Press <span class="shortcut">⌘⌥J</span> to open Developer Tools. Enable <a href="http://stackoverflow.com/a/17324511/232122" target="_blank">Pause On Caught Exceptions</a> for a better debugging experience.</p>
|
||||
<p>Status: <span id="status">Loading</span></p>
|
||||
</body>
|
||||
</html>
|
44
init.sh
Executable file
44
init.sh
Executable file
@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
def cp(src, dest, app_name)
|
||||
if File.directory?(src)
|
||||
Dir.mkdir(dest) unless Dir.exists?(dest)
|
||||
else
|
||||
content = File.read(src)
|
||||
.gsub("SampleApp", app_name)
|
||||
.gsub("Examples/#{app_name}/", "")
|
||||
.gsub("../../Libraries/", "node_modules/react-native/Libraries/")
|
||||
.gsub("../../ReactKit/", "node_modules/react-native/ReactKit/")
|
||||
File.write(dest, content)
|
||||
end
|
||||
end
|
||||
|
||||
def main(dest, app_name)
|
||||
source = File.expand_path("../../Examples/SampleApp", __FILE__)
|
||||
files = Dir.chdir(source) { Dir["**/*"] }
|
||||
.reject { |file| file["project.xcworkspace"] || file["xcuserdata"] }
|
||||
.each { |file|
|
||||
new_file = file.gsub("SampleApp", app_name)
|
||||
cp File.join(source, file), File.join(dest, new_file), app_name
|
||||
}
|
||||
end
|
||||
|
||||
if ARGV.count == 0
|
||||
puts "Usage: #{__FILE__} <ProjectNameInCamelCase>"
|
||||
puts ""
|
||||
puts "This script will bootstrap new React Native app in current folder"
|
||||
else
|
||||
app_name = ARGV.first
|
||||
dest = Dir.pwd
|
||||
puts "Setting up new React Native app in #{dest}"
|
||||
puts ""
|
||||
|
||||
main(dest, app_name)
|
||||
|
||||
puts "Next steps:"
|
||||
puts ""
|
||||
puts " Open #{app_name}.xcproject in Xcode"
|
||||
puts " Hit Run button"
|
||||
puts ""
|
||||
end
|
||||
|
41
launchChromeDevTools.applescript
Executable file
41
launchChromeDevTools.applescript
Executable file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env osascript
|
||||
|
||||
|
||||
on run argv
|
||||
set theURL to item 1 of argv
|
||||
|
||||
tell application "Google Chrome"
|
||||
activate
|
||||
|
||||
if (count every window) = 0 then
|
||||
make new window
|
||||
end if
|
||||
|
||||
-- Find a tab currently running the debugger
|
||||
set found to false
|
||||
set theTabIndex to -1
|
||||
repeat with theWindow in every window
|
||||
set theTabIndex to 0
|
||||
repeat with theTab in every tab of theWindow
|
||||
set theTabIndex to theTabIndex + 1
|
||||
if theTab's URL is theURL then
|
||||
set found to true
|
||||
exit repeat
|
||||
end if
|
||||
end repeat
|
||||
|
||||
if found then
|
||||
exit repeat
|
||||
end if
|
||||
end repeat
|
||||
|
||||
if found then
|
||||
set index of theWindow to 1
|
||||
set theWindow's active tab index to theTabIndex
|
||||
else
|
||||
tell window 1
|
||||
make new tab with properties {URL:theURL}
|
||||
end tell
|
||||
end if
|
||||
end tell
|
||||
end run
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native",
|
||||
"version": "0.1.0",
|
||||
"name": "react-native-cli",
|
||||
"version": "0.1.1",
|
||||
"description": "Build native apps with React!",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
42
packager.js
42
packager.js
@ -16,12 +16,14 @@ if (!fs.existsSync(path.resolve(__dirname, '..', 'node_modules'))) {
|
||||
process.exit();
|
||||
}
|
||||
|
||||
var exec = require('child_process').exec;
|
||||
var ReactPackager = require('./react-packager');
|
||||
var blacklist = require('./blacklist.js');
|
||||
var connect = require('connect');
|
||||
var http = require('http');
|
||||
var launchEditor = require('./launchEditor.js');
|
||||
var parseCommandLine = require('./parseCommandLine.js');
|
||||
var webSocketProxy = require('./webSocketProxy.js');
|
||||
|
||||
var options = parseCommandLine([{
|
||||
command: 'port',
|
||||
@ -31,7 +33,11 @@ var options = parseCommandLine([{
|
||||
description: 'add another root(s) to be used by the packager in this project',
|
||||
}]);
|
||||
|
||||
if (!options.projectRoots) {
|
||||
if (options.projectRoots) {
|
||||
if (!Array.isArray(options.projectRoots)) {
|
||||
options.projectRoots = options.projectRoots.split(',');
|
||||
}
|
||||
} else {
|
||||
options.projectRoots = [path.resolve(__dirname, '..')];
|
||||
}
|
||||
|
||||
@ -45,6 +51,10 @@ if (options.root) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.assetRoots) {
|
||||
options.assetRoots = [path.resolve(__dirname, '..')];
|
||||
}
|
||||
|
||||
console.log('\n' +
|
||||
' ===============================================================\n' +
|
||||
' | Running packager on port ' + options.port + '. \n' +
|
||||
@ -64,10 +74,12 @@ process.on('uncaughtException', function(e) {
|
||||
'any existing instances that are already running.\n\n');
|
||||
});
|
||||
|
||||
runServer(options, function() {
|
||||
var server = runServer(options, function() {
|
||||
console.log('\nReact packager ready.\n');
|
||||
});
|
||||
|
||||
webSocketProxy.attachToServer(server, '/debugger-proxy');
|
||||
|
||||
function loadRawBody(req, res, next) {
|
||||
req.rawBody = '';
|
||||
req.setEncoding('utf8');
|
||||
@ -91,12 +103,37 @@ function openStackFrameInEditor(req, res, next) {
|
||||
}
|
||||
}
|
||||
|
||||
function getDevToolsLauncher(options) {
|
||||
return function(req, res, next) {
|
||||
if (req.url === '/debugger-ui') {
|
||||
var debuggerPath = path.join(__dirname, 'debugger.html');
|
||||
res.writeHead(200, {'Content-Type': 'text/html'});
|
||||
fs.createReadStream(debuggerPath).pipe(res);
|
||||
} else if (req.url === '/launch-chrome-devtools') {
|
||||
var debuggerURL = 'http://localhost:' + options.port + '/debugger-ui';
|
||||
var script = 'launchChromeDevTools.applescript';
|
||||
console.log('Launching Dev Tools...');
|
||||
exec(path.join(__dirname, script) + ' ' + debuggerURL, function(err, stdout, stderr) {
|
||||
if (err) {
|
||||
console.log('Failed to run ' + script, err);
|
||||
}
|
||||
console.log(stdout);
|
||||
console.warn(stderr);
|
||||
});
|
||||
res.end('OK');
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getAppMiddleware(options) {
|
||||
return ReactPackager.middleware({
|
||||
projectRoots: options.projectRoots,
|
||||
blacklistRE: blacklist(false),
|
||||
cacheVersion: '2',
|
||||
transformModulePath: require.resolve('./transformer.js'),
|
||||
assetRoots: options.assetRoots,
|
||||
});
|
||||
}
|
||||
|
||||
@ -107,6 +144,7 @@ function runServer(
|
||||
var app = connect()
|
||||
.use(loadRawBody)
|
||||
.use(openStackFrameInEditor)
|
||||
.use(getDevToolsLauncher(options))
|
||||
.use(getAppMiddleware(options));
|
||||
|
||||
options.projectRoots.forEach(function(root) {
|
||||
|
@ -134,13 +134,12 @@ DependecyGraph.prototype.resolveDependency = function(
|
||||
fromModule,
|
||||
depModuleId
|
||||
) {
|
||||
|
||||
if (this._assetMap != null) {
|
||||
// Process asset requires.
|
||||
var assetMatch = depModuleId.match(/^image!(.+)/);
|
||||
if (assetMatch && assetMatch[1]) {
|
||||
if (!this._assetMap[assetMatch[1]]) {
|
||||
console.warn('Cannot find asset: ' + assetMatch[1]);
|
||||
debug('WARINING: Cannot find asset:', assetMatch[1]);
|
||||
return null;
|
||||
}
|
||||
return this._assetMap[assetMatch[1]];
|
||||
|
29
react-packager/src/JSTransformer/Cache.js
vendored
29
react-packager/src/JSTransformer/Cache.js
vendored
@ -1,13 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
var version = require('../../../../package.json').version;
|
||||
var tmpdir = require('os').tmpDir();
|
||||
var isAbsolutePath = require('absolute-path');
|
||||
var _ = require('underscore');
|
||||
var crypto = require('crypto');
|
||||
var declareOpts = require('../lib/declareOpts');
|
||||
var fs = require('fs');
|
||||
var _ = require('underscore');
|
||||
var isAbsolutePath = require('absolute-path');
|
||||
var path = require('path');
|
||||
var q = require('q');
|
||||
var tmpdir = require('os').tmpDir();
|
||||
var version = require('../../../../package.json').version;
|
||||
|
||||
var Promise = q.Promise;
|
||||
|
||||
@ -146,15 +147,15 @@ function loadCacheSync(cachePath) {
|
||||
}
|
||||
|
||||
function cacheFilePath(options) {
|
||||
var hash = crypto.createHash('md5');
|
||||
hash.update(version);
|
||||
|
||||
var roots = options.projectRoots.join(',').split(path.sep).join('-');
|
||||
hash.update(roots);
|
||||
|
||||
var cacheVersion = options.cacheVersion || '0';
|
||||
return path.join(
|
||||
tmpdir,
|
||||
[
|
||||
'react-packager-cache',
|
||||
version,
|
||||
cacheVersion,
|
||||
roots,
|
||||
].join('-')
|
||||
);
|
||||
hash.update(cacheVersion);
|
||||
|
||||
var name = 'react-packager-cache-' + hash.digest('hex');
|
||||
return path.join(tmpdir, name);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ jest
|
||||
.dontMock('underscore')
|
||||
.dontMock('path')
|
||||
.dontMock('absolute-path')
|
||||
.dontMock('crypto')
|
||||
.dontMock('../Cache');
|
||||
|
||||
var q = require('q');
|
||||
@ -19,7 +20,7 @@ describe('JSTransformer Cache', function() {
|
||||
Cache = require('../Cache');
|
||||
});
|
||||
|
||||
describe('getting/settig', function() {
|
||||
describe('getting/setting', function() {
|
||||
it('calls loader callback for uncached file', function() {
|
||||
var cache = new Cache({projectRoots: ['/rootDir']});
|
||||
var loaderCb = jest.genMockFn().mockImpl(function() {
|
||||
|
2
react-packager/src/JSTransformer/index.js
vendored
2
react-packager/src/JSTransformer/index.js
vendored
@ -59,7 +59,7 @@ function Transformer(options) {
|
||||
this._failedToStart = q.Promise.reject(new Error('No transfrom module'));
|
||||
} else {
|
||||
this._workers = workerFarm(
|
||||
{autoStart: true},
|
||||
{autoStart: true, maxConcurrentCallsPerWorker: 1},
|
||||
options.transformModulePath
|
||||
);
|
||||
}
|
||||
|
25
react-packager/src/Server/index.js
vendored
25
react-packager/src/Server/index.js
vendored
@ -8,6 +8,7 @@ var Packager = require('../Packager');
|
||||
var Activity = require('../Activity');
|
||||
var setImmediate = require('timers').setImmediate;
|
||||
var q = require('q');
|
||||
var _ = require('underscore');
|
||||
|
||||
module.exports = Server;
|
||||
|
||||
@ -62,6 +63,12 @@ function Server(options) {
|
||||
|
||||
var onFileChange = this._onFileChange.bind(this);
|
||||
this._fileWatcher.on('all', onFileChange);
|
||||
|
||||
var self = this;
|
||||
this._debouncedFileChangeHandler = _.debounce(function(filePath) {
|
||||
self._rebuildPackages(filePath);
|
||||
self._informChangeWatchers();
|
||||
}, 50, true);
|
||||
}
|
||||
|
||||
Server.prototype._onFileChange = function(type, filepath, root) {
|
||||
@ -69,8 +76,7 @@ Server.prototype._onFileChange = function(type, filepath, root) {
|
||||
this._packager.invalidateFile(absPath);
|
||||
// Make sure the file watcher event runs through the system before
|
||||
// we rebuild the packages.
|
||||
setImmediate(this._rebuildPackages.bind(this, absPath));
|
||||
setImmediate(this._informChangeWatchers.bind(this));
|
||||
this._debouncedFileChangeHandler(absPath);
|
||||
};
|
||||
|
||||
Server.prototype._rebuildPackages = function() {
|
||||
@ -78,13 +84,16 @@ Server.prototype._rebuildPackages = function() {
|
||||
var packages = this._packages;
|
||||
Object.keys(packages).forEach(function(key) {
|
||||
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: options.dev,
|
||||
minify: options.minify,
|
||||
// Wait for a previous build (if exists) to finish.
|
||||
packages[key] = (packages[key] || q()).then(function() {
|
||||
return buildPackage(options).then(function(p) {
|
||||
// Make a throwaway call to getSource to cache the source string.
|
||||
p.getSource({
|
||||
inlineSourceMap: options.dev,
|
||||
minify: options.minify,
|
||||
});
|
||||
return p;
|
||||
});
|
||||
return p;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
41
webSocketProxy.js
Normal file
41
webSocketProxy.js
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var WebSocketServer = require('ws').Server;
|
||||
|
||||
function attachToServer(server, path) {
|
||||
var wss = new WebSocketServer({
|
||||
server: server,
|
||||
path: path
|
||||
});
|
||||
var clients = [];
|
||||
|
||||
wss.on('connection', function(ws) {
|
||||
clients.push(ws);
|
||||
|
||||
var allClientsExcept = function(ws) {
|
||||
return clients.filter(function(cn) { return cn !== ws; });
|
||||
};
|
||||
|
||||
ws.onerror = function() {
|
||||
clients = allClientsExcept(ws);
|
||||
};
|
||||
|
||||
ws.onclose = function() {
|
||||
clients = allClientsExcept(ws);
|
||||
};
|
||||
|
||||
ws.on('message', function(message) {
|
||||
allClientsExcept(ws).forEach(function(cn) {
|
||||
cn.send(message);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
attachToServer: attachToServer
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user