Initial support for v15+ via new legaacy renderer

This commit is contained in:
Brian Vaughn
2019-04-17 14:36:15 -07:00
parent 0d932d770b
commit 7ab93402a8
33 changed files with 2371 additions and 24 deletions
+1 -2
View File
@@ -12,5 +12,4 @@ yarn-error.log
.vscode
.idea
.watchmanconfig
key.pem
key.pem
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 14.9</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@0.14.9/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@0.14.9/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/14.9.html">http://localhost:9000/fixtures/regression/14.9.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 15.0</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@15.0/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.0/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/15.0.html">http://localhost:9000/fixtures/regression/15.0.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 15.1</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@15.1/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.1/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/15.1.html">http://localhost:9000/fixtures/regression/15.1.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 15.2</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@15.2/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.2/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/15.2.html">http://localhost:9000/fixtures/regression/15.2.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 15.3</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@15.3/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.3/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/15.3.html">http://localhost:9000/fixtures/regression/15.3.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 15.4</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@15.4/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.4/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/15.4.html">http://localhost:9000/fixtures/regression/15.4.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 15.5</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@15.5/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.5/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/15.5.html">http://localhost:9000/fixtures/regression/15.5.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 15.6</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@15.6/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15.6/dist/react-dom.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/15.6.html">http://localhost:9000/fixtures/regression/15.6.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.0</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@16.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.0/umd/react-dom.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/16.0.html">http://localhost:9000/fixtures/regression/16.0.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.1</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@16.1/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.1/umd/react-dom.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/16.1.html">http://localhost:9000/fixtures/regression/16.1.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.2</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@16.2/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.2/umd/react-dom.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/16.2.html">http://localhost:9000/fixtures/regression/16.2.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.3</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@16.3/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.3/umd/react-dom.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/16.3.html">http://localhost:9000/fixtures/regression/16.3.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.4</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/react@16.4/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.4/umd/react-dom.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/16.4.html">http://localhost:9000/fixtures/regression/16.4.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+41
View File
@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.5</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/schedule@0.5.0/umd/schedule.development.js"></script>
<script src="https://unpkg.com/schedule@0.5.0/umd/schedule-tracing.development.js"></script>
<script src="https://unpkg.com/react@16.5/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.5/umd/react-dom.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/16.5.html">http://localhost:9000/fixtures/regression/16.5.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+42
View File
@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.6</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/scheduler@0.10.0/umd/scheduler.development.js"></script>
<script src="https://unpkg.com/scheduler@0.10.0/umd/scheduler-tracing.development.js"></script>
<script src="https://unpkg.com/react@16.6/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.6/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/react-cache@2.0.0-alpha.1/umd/react-cache.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/16.6.html">http://localhost:9000/fixtures/regression/16.6.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+42
View File
@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 16.7</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/scheduler@0.12.0/umd/scheduler.development.js"></script>
<script src="https://unpkg.com/scheduler@0.12.0/umd/scheduler-tracing.development.js"></script>
<script src="https://unpkg.com/react@16.7/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/react-cache@2.0.0-alpha.1/umd/react-cache.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/16.7.html">http://localhost:9000/fixtures/regression/16.7.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+42
View File
@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React canary</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/scheduler@canary/umd/scheduler.development.js"></script>
<script src="https://unpkg.com/scheduler@canary/umd/scheduler-tracing.development.js"></script>
<script src="https://unpkg.com/react@canary/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@canary/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/react-cache@next/umd/react-cache.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/canary.html">http://localhost:9000/fixtures/regression/canary.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+28
View File
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React DevTools regression test</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<iframe src="canary.html"></iframe>
<iframe src="next.html"></iframe>
<iframe src="16.7.html"></iframe>
<iframe src="16.6.html"></iframe>
<iframe src="16.5.html"></iframe>
<iframe src="16.4.html"></iframe>
<iframe src="16.3.html"></iframe>
<iframe src="16.2.html"></iframe>
<iframe src="16.1.html"></iframe>
<iframe src="16.0.html"></iframe>
<iframe src="15.6.html"></iframe>
<iframe src="15.5.html"></iframe>
<iframe src="15.4.html"></iframe>
<iframe src="15.3.html"></iframe>
<iframe src="15.2.html"></iframe>
<iframe src="15.1.html"></iframe>
<iframe src="15.0.html"></iframe>
<iframe src="14.9.html"></iframe>
</body>
</html>
+42
View File
@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React next</title>
<link rel="stylesheet" href="styles.css" />
<script type="text/javascript">
// Enable DevTools to inspect React inside of an <iframe>
// This must run before React is loaded
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;
</script>
<script src="https://unpkg.com/scheduler@next/umd/scheduler.development.js"></script>
<script src="https://unpkg.com/scheduler@next/umd/scheduler-tracing.development.js"></script>
<script src="https://unpkg.com/react@next/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@next/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/react-cache@next/umd/react-cache.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root">
If you are seeing this message, you are likely viewing this file using the <code>file</code> protocol which does not support cross origin requests.
<br/><br/>
Use a web server like <code>serve</code> instead:
<br/><br/>
<code>npm install -g pushstate-server</code><br/>
<code>pushstate-server .</code><br/>
<code>open <a href="http://localhost:9000/fixtures/regression/next.html">http://localhost:9000/fixtures/regression/next.html</a></code>
</div>
<script src="shared.js" type="text/babel"></script>
<!--
This is a great way to try React but it's not suitable for production.
It slowly compiles JSX with Babel in the browser and uses a large development build of React.
Learn more at https://reactjs.org/docs/getting-started.html
-->
</body>
</html>
+330
View File
@@ -0,0 +1,330 @@
/* eslint-disable no-fallthrough, react/react-in-jsx-scope, react/jsx-no-undef */
/* global React ReactCache ReactDOM SchedulerTracing ScheduleTracing */
const apps = [];
const pieces = React.version.split('.');
const major =
pieces[0] === '0' ? parseInt(pieces[1], 10) : parseInt(pieces[0], 10);
const minor =
pieces[0] === '0' ? parseInt(pieces[2], 10) : parseInt(pieces[1], 10);
// Convenience wrapper to organize API features in DevTools.
function Feature({ children, label, version }) {
return (
<div className="Feature">
<div className="FeatureHeader">
<code className="FeatureCode">{label}</code>
<small>{version}</small>
</div>
{children}
</div>
);
}
// Simplify interaction tracing for tests below.
let trace = null;
if (typeof SchedulerTracing !== 'undefined') {
trace = SchedulerTracing.unstable_trace;
} else if (typeof ScheduleTracing !== 'undefined') {
trace = ScheduleTracing.unstable_trace;
} else {
trace = (_, __, callback) => callback();
}
// https://github.com/facebook/react/blob/master/CHANGELOG.md
switch (major) {
case 16:
switch (minor) {
case 7:
if (typeof React.useState === 'function') {
// Hooks
function Hooks() {
const [count, setCount] = React.useState(0);
const incrementCount = React.useCallback(
() => setCount(count + 1),
[count]
);
return (
<div>
count: {count}{' '}
<button onClick={incrementCount}>increment</button>
</div>
);
}
apps.push(
<Feature key="Hooks" label="Hooks" version="16.7+">
<Hooks />
</Feature>
);
}
case 6:
// memo
function LabelComponent({ label }) {
return <label>{label}</label>;
}
const AnonymousMemoized = React.memo(({ label }) => (
<label>{label}</label>
));
const Memoized = React.memo(LabelComponent);
const CustomMemoized = React.memo(LabelComponent);
CustomMemoized.displayName = 'MemoizedLabelFunction';
apps.push(
<Feature key="memo" label="memo" version="16.6+">
<AnonymousMemoized label="AnonymousMemoized" />
<Memoized label="Memoized" />
<CustomMemoized label="CustomMemoized" />
</Feature>
);
// Suspense
const loadResource = ([text, ms]) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(text);
}, ms);
});
};
const getResourceKey = ([text, ms]) => text;
const Resource = ReactCache.unstable_createResource(
loadResource,
getResourceKey
);
class Suspending extends React.Component {
state = { useSuspense: false };
useSuspense = () => this.setState({ useSuspense: true });
render() {
if (this.state.useSuspense) {
const text = Resource.read(['loaded', 2000]);
return text;
} else {
return <button onClick={this.useSuspense}>load data</button>;
}
}
}
apps.push(
<Feature key="Suspense" label="Suspense" version="16.6+">
<React.Suspense fallback={<div>loading...</div>}>
<Suspending />
</React.Suspense>
</Feature>
);
// lazy
const LazyWithDefaultProps = React.lazy(
() =>
new Promise(resolve => {
function FooWithDefaultProps(props) {
return (
<h1>
{props.greeting}, {props.name}
</h1>
);
}
FooWithDefaultProps.defaultProps = {
name: 'World',
greeting: 'Bonjour',
};
resolve({
default: FooWithDefaultProps,
});
})
);
apps.push(
<Feature key="lazy" label="lazy" version="16.6+">
<React.Suspense fallback={<div>loading...</div>}>
<LazyWithDefaultProps greeting="Hello" />
</React.Suspense>
</Feature>
);
case 5:
case 4:
// unstable_Profiler
class ProfilerChild extends React.Component {
state = { count: 0 };
incrementCount = () =>
this.setState(prevState => ({ count: prevState.count + 1 }));
render() {
return (
<div>
count: {this.state.count}{' '}
<button onClick={this.incrementCount}>increment</button>
</div>
);
}
}
const onRender = (...args) => console.log('onRender()', ...args);
const Profiler = React.unstable_Profiler || React.Profiler;
apps.push(
<Feature
key="unstable_Profiler"
label="unstable_Profiler"
version="16.4+"
>
<Profiler id="count" onRender={onRender}>
<div>
<ProfilerChild />
</div>
</Profiler>
</Feature>
);
case 3:
// createContext()
const LocaleContext = React.createContext();
LocaleContext.displayName = 'LocaleContext';
const ThemeContext = React.createContext();
apps.push(
<Feature key="createContext" label="createContext" version="16.3+">
<ThemeContext.Provider value="blue">
<ThemeContext.Consumer>
{theme => <div>theme: {theme}</div>}
</ThemeContext.Consumer>
</ThemeContext.Provider>
<LocaleContext.Provider value="en-US">
<LocaleContext.Consumer>
{locale => <div>locale: {locale}</div>}
</LocaleContext.Consumer>
</LocaleContext.Provider>
</Feature>
);
// forwardRef()
const AnonymousFunction = React.forwardRef((props, ref) => (
<div ref={ref}>{props.children}</div>
));
const NamedFunction = React.forwardRef(function named(props, ref) {
return <div ref={ref}>{props.children}</div>;
});
const CustomName = React.forwardRef((props, ref) => (
<div ref={ref}>{props.children}</div>
));
CustomName.displayName = 'CustomNameForwardRef';
apps.push(
<Feature key="forwardRef" label="forwardRef" version="16.3+">
<AnonymousFunction>AnonymousFunction</AnonymousFunction>
<NamedFunction>NamedFunction</NamedFunction>
<CustomName>CustomName</CustomName>
</Feature>
);
// StrictMode
class StrictModeChild extends React.Component {
render() {
return 'StrictModeChild';
}
}
apps.push(
<Feature key="StrictMode" label="StrictMode" version="16.3+">
<React.StrictMode>
<StrictModeChild />
</React.StrictMode>
</Feature>
);
// unstable_AsyncMode (later renamed to unstable_ConcurrentMode, then ConcurrentMode)
const ConcurrentMode =
React.ConcurrentMode ||
React.unstable_ConcurrentMode ||
React.unstable_AsyncMode;
apps.push(
<Feature
key="AsyncMode/ConcurrentMode"
label="AsyncMode/ConcurrentMode"
version="16.3+"
>
<ConcurrentMode>
<div>
unstable_AsyncMode was added in 16.3, renamed to
unstable_ConcurrentMode in 16.5, and then renamed to
ConcurrentMode in 16.7
</div>
</ConcurrentMode>
</Feature>
);
case 2:
// Fragment
apps.push(
<Feature key="Fragment" label="Fragment" version="16.4+">
<React.Fragment>
<div>one</div>
<div>two</div>
</React.Fragment>
</Feature>
);
case 1:
case 0:
default:
break;
}
break;
case 15:
break;
case 14:
break;
default:
break;
}
function Even() {
return <small>(even)</small>;
}
// Simple stateful app shared by all React versions
class SimpleApp extends React.Component {
state = { count: 0 };
incrementCount = () => {
const updaterFn = prevState => ({ count: prevState.count + 1 });
trace('Updating count', performance.now(), () => this.setState(updaterFn));
};
render() {
const { count } = this.state;
return (
<div>
{count % 2 === 0 ? (
<span>
count: {count} <Even />
</span>
) : (
<span>count: {count}</span>
)}{' '}
<button onClick={this.incrementCount}>increment</button>
</div>
);
}
}
apps.push(
<Feature key="Simple stateful app" label="Simple stateful app" version="any">
<SimpleApp />
</Feature>
);
// This component, with the version prop, helps organize DevTools at a glance.
function TopLevelWrapperForDevTools({ version }) {
let header = <h1>React {version}</h1>;
if (version.includes('canary')) {
const commitSha = version.match(/.+canary-(.+)/)[1];
header = (
<h1>
React canary{' '}
<a href={`https://github.com/facebook/react/commit/${commitSha}`}>
{commitSha}
</a>
</h1>
);
} else if (version.includes('alpha')) {
header = <h1>React next</h1>;
}
return (
<div>
{header}
{apps}
</div>
);
}
TopLevelWrapperForDevTools.displayName = 'React';
ReactDOM.render(
<TopLevelWrapperForDevTools version={React.version} />,
document.getElementById('root')
);
+37
View File
@@ -0,0 +1,37 @@
body {
font-family: sans-serif;
font-size: 12px;
}
h1 {
margin: 0;
font-size: 20px;
}
h2 {
margin: 1rem 0 0;
}
iframe {
border: 1px solid #ddd;
border-radius: 0.5rem;
}
code {
white-space: nowrap;
}
.Feature {
margin: 1rem 0;
border-bottom: 1px solid #eee;
padding-bottom: 1rem;
}
.FeatureHeader {
font-size: 16px;
margin-bottom: 0.5rem;
}
.FeatureCode {
background-color: #eee;
padding: 0.25rem;
border-radius: 0.25rem;
}
+2 -2
View File
@@ -113,7 +113,7 @@ export default class Agent extends EventEmitter {
const renderer = ((this._rendererInterfaces[
(rendererID: any)
]: any): RendererInterface);
return renderer.getFiberIDFromNative(node, true);
return renderer.getInternalIDFromNative(node, true);
} catch (e) {}
}
return null;
@@ -253,7 +253,7 @@ export default class Agent extends EventEmitter {
let node: HTMLElement | null = null;
if (renderer !== null) {
node = ((renderer.findNativeByFiberID(id): any): HTMLElement);
node = ((renderer.getNativeFromInternal(id): any): HTMLElement);
}
if (node != null) {
+6 -1
View File
@@ -4,6 +4,7 @@ import type { DevToolsHook, ReactRenderer, RendererInterface } from './types';
import Agent from './agent';
import { attach } from './renderer';
import { attach as attachLegacy } from './legacy/renderer';
export function initBackend(
hook: DevToolsHook,
@@ -40,7 +41,11 @@ export function initBackend(
// Inject any not-yet-injected renderers (if we didn't reload-and-profile)
if (!rendererInterface) {
rendererInterface = attach(hook, id, renderer, global);
if (typeof renderer.findFiberByHostInstance === 'function') {
rendererInterface = attach(hook, id, renderer, global);
} else {
rendererInterface = attachLegacy(hook, id, renderer, global);
}
hook.rendererInterfaces.set(id, rendererInterface);
}
+63
View File
@@ -0,0 +1,63 @@
// @flow
export default function getChildren(internalInstance: Object): Array<any> {
// If the parent is a native node without rendered children, but with
// multiple string children, then the `element` that gets passed in here is
// a plain value -- a string or number.
if (internalInstance._renderedComponent) {
return [internalInstance._renderedComponent];
} else if (internalInstance._renderedChildren) {
return childrenToArray(internalInstance._renderedChildren);
} else if (
internalInstance._currentElement &&
internalInstance._currentElement.props
) {
// DevTools doesn't need to display primative child types,
// So we can filter them out early.
/*
const children = [];
// This is a native node without rendered children -- meaning the children
// prop is the unfiltered list of children.
// This may include 'null' or even other invalid values, so we need to
// filter it the same way that ReactDOM does.
// Instead of pulling in the whole React library, we just copied over the
// 'traverseAllChildrenImpl' method.
// https://github.com/facebook/react/blob/240b84ed8e1db715d759afaae85033718a0b24e1/src/isomorphic/children/ReactChildren.js#L112-L158
const unfilteredChildren = internalInstance._currentElement.props.children;
traverseAllChildrenImpl(
unfilteredChildren,
'', // nameSoFar
(_traverseContext, child) => {
const childType = typeof child;
if (childType === 'string' || childType === 'number') {
children.push(child);
}
}
// traverseContext
);
return children;
*/
}
if (internalInstance._instance) {
var inst = internalInstance._instance;
// TODO: React ART currently falls in this bucket, but this doesn't
// actually make sense and we should clean this up after stabilizing our
// API for backends
if (inst._renderedChildren) {
return childrenToArray(inst._renderedChildren);
}
}
return [];
}
function childrenToArray(children) {
const array = [];
for (var name in children) {
array.push(children[name]);
}
return array;
}
+46
View File
@@ -0,0 +1,46 @@
// @flow
import {
ElementTypeClass,
ElementTypeOtherOrUnknown,
} from 'src/devtools/types';
import { getDisplayName } from 'src/utils';
import type { InternalInstance } from './renderer';
import type { FiberData } from '../types';
export default function getData(internalInstance: InternalInstance): FiberData {
let displayName = null;
let key = null;
let type = ElementTypeOtherOrUnknown;
// != used deliberately here to catch undefined and null
if (internalInstance._currentElement != null) {
if (internalInstance._currentElement.key) {
key = String(internalInstance._currentElement.key);
}
const elementType = internalInstance._currentElement.type;
if (typeof elementType === 'string') {
// ...
} else if (typeof elementType === 'function') {
// TODO Can we differentiate between function and class component types?
// Dan said _compositeType tells you PureClass, ImpureClass, StatelessFunctional but it was only added in v14
// getPublicInstance() returns null for function components
type = ElementTypeClass;
displayName = getDisplayName(elementType);
} else if (typeof internalInstance._stringText === 'string') {
// ...
} else {
// TODO What kind of case does this cover?
console.log('what is this type?');
displayName = getDisplayName(elementType);
}
}
return {
displayName,
key,
type,
};
}
+22
View File
@@ -0,0 +1,22 @@
// @flow
import {
ElementTypeClass,
ElementTypeOtherOrUnknown,
} from 'src/devtools/types';
import type { InternalInstance } from './renderer';
import type { ElementType } from 'src/devtools/types';
export default function getElementType(
internalInstance: InternalInstance
): ElementType {
// != used deliberately here to catch undefined and null
if (internalInstance._currentElement != null) {
const elementType = internalInstance._currentElement.type;
if (typeof elementType === 'function') {
return ElementTypeClass;
}
}
return ElementTypeOtherOrUnknown;
}
+787
View File
@@ -0,0 +1,787 @@
// @flow
import {
ElementTypeClass,
ElementTypeFunction,
ElementTypeRoot,
ElementTypeOtherOrUnknown,
} from 'src/devtools/types';
import { getUID, utfEncodeString, operationsArrayToString } from '../../utils';
import { cleanForBridge, copyWithSet } from '../utils';
import {
__DEBUG__,
TREE_OPERATION_ADD,
TREE_OPERATION_REMOVE,
} from '../../constants';
import getChildren from './getChildren';
import getData from './getData';
import getElementType from './getElementType';
import {
decorateResult,
decorateMany,
forceUpdate,
restoreMany,
} from './utils';
import type {
DevToolsHook,
GetInternalIDFromNative,
GetNativeFromInternal,
NativeType,
RendererInterface,
} from '../types';
import type { InspectedElement } from 'src/devtools/views/Components/types';
export type InternalInstance = Object;
type LegacyRenderer = Object;
export function attach(
hook: DevToolsHook,
rendererID: number,
renderer: LegacyRenderer,
global: Object
): RendererInterface {
const idToInternalInstanceMap: Map<number, InternalInstance> = new Map();
const idToParentIDMap: Map<number, number> = new Map();
const internalInstanceToIDMap: Map<InternalInstance, number> = new Map();
const mountedIDs: Set<number> = new Set();
const pendingMountIDs: Set<number> = new Set();
const pendingUnmountIDs: Set<number> = new Set();
const rootIDs: Set<number> = new Set();
function getID(internalInstance: InternalInstance): number {
if (!internalInstanceToIDMap.has(internalInstance)) {
const id = getUID();
internalInstanceToIDMap.set(internalInstance, id);
idToInternalInstanceMap.set(id, internalInstance);
}
return ((internalInstanceToIDMap.get(internalInstance): any): number);
}
function getChildIDs(internalInstance: InternalInstance): Array<number> {
return getChildren(internalInstance).map(getID);
}
//function getParentID(internalInstance: InternalInstance): number {
// return getID(internalInstance._hostParent);
//}
function findNearestAncestorInTree(
internalInstance: InternalInstance
): number | null {
let current = internalInstance;
while (current != null) {
const id = getID(current);
if (
rootIDs.has(id) ||
getElementType(current) !== ElementTypeOtherOrUnknown
) {
return id;
}
const parentID = idToParentIDMap.get(id);
current = parentID != null ? idToInternalInstanceMap.get(parentID) : null;
}
return null;
}
let getInternalIDFromNative: GetInternalIDFromNative = ((null: any): GetInternalIDFromNative);
let getNativeFromInternal: (
id: number
) => ?NativeType = ((null: any): GetNativeFromInternal);
// React Native
if (renderer.Mount.findNodeHandle && renderer.Mount.nativeTagToRootNodeID) {
getInternalIDFromNative = (nativeTag, findNearestUnfilteredAncestor) => {
const internalInstance = renderer.Mount.nativeTagToRootNodeID(nativeTag);
return findNearestAncestorInTree(internalInstance);
};
getNativeFromInternal = (id: number) => {
const internalInstance = idToInternalInstanceMap.get(id);
return renderer.Mount.findNodeHandle(internalInstance);
};
// React DOM 15+
} else if (renderer.ComponentTree) {
getInternalIDFromNative = (node, findNearestUnfilteredAncestor) => {
const internalInstance = renderer.ComponentTree.getClosestInstanceFromNode(
node
);
return findNearestAncestorInTree(internalInstance);
};
getNativeFromInternal = (id: number) => {
const internalInstance = idToInternalInstanceMap.get(id);
return renderer.ComponentTree.getNodeFromInstance(internalInstance);
};
// React DOM
} else if (renderer.Mount.getID && renderer.Mount.getNode) {
getInternalIDFromNative = (node, findNearestUnfilteredAncestor) => {
let id = renderer.Mount.getID(node);
while (node && node.parentNode && !id) {
node = node.parentNode;
id = renderer.Mount.getID(node);
}
return id;
};
getNativeFromInternal = (id: number) => {
try {
const internalInstance = idToInternalInstanceMap.get(id);
if (internalInstance != null) {
return renderer.Mount.getNode(internalInstance._rootNodeID);
}
} catch (e) {}
return null;
};
} else {
console.warn(
'Unknown React version (does not have getID), probably an unshimmed React Native'
);
}
let oldReconcilerMethods = null;
let oldRenderComponent = null;
let oldRenderRoot = null;
// React DOM
if (renderer.Mount._renderNewRootComponent) {
oldRenderRoot = decorateResult(
renderer.Mount,
'_renderNewRootComponent',
internalInstance => {
const id = getID(internalInstance);
rootIDs.add(id);
if (__DEBUG__) {
console.log('renderer.Mount._renderNewRootComponent()', id);
}
recordPendingMount(internalInstance);
// If we're mounting a root, we've just finished a batch of work,
// so it's safe to synchronously flush.
flushPendingEvents(id);
}
);
// React Native
} else if (renderer.Mount.renderComponent) {
oldRenderComponent = decorateResult(
renderer.Mount,
'renderComponent',
internalInstance => {
const id = getID(internalInstance);
rootIDs.add(id);
if (__DEBUG__) {
console.log('renderer.Mount.renderComponent()', id);
}
recordPendingMount(internalInstance);
// If we're mounting a root, we've just finished a batch of work,
// so it's safe to synchronously flush.
flushPendingEvents(id);
}
);
}
if (renderer.Reconciler) {
oldReconcilerMethods = decorateMany(renderer.Reconciler, {
mountComponent(internalInstance, rootID, transaction, context) {
recordPendingMount(internalInstance);
},
performUpdateIfNecessary(
internalInstance,
nextChild,
transaction,
context
) {
// TODO Check for change in order of children
},
receiveComponent(internalInstance, nextChild, transaction, context) {
// TODO Check for change in order of children
},
unmountComponent(internalInstance) {
recordPendingUnmount(internalInstance);
},
});
}
function cleanup() {
if (oldReconcilerMethods !== null) {
if (renderer.Component) {
restoreMany(renderer.Component.Mixin, oldReconcilerMethods);
} else {
restoreMany(renderer.Reconciler, oldReconcilerMethods);
}
}
if (oldRenderRoot !== null) {
renderer.Mount._renderNewRootComponent = oldRenderRoot;
}
if (oldRenderComponent !== null) {
renderer.Mount.renderComponent = oldRenderComponent;
}
oldReconcilerMethods = null;
oldRenderRoot = null;
oldRenderComponent = null;
}
let pendingOperations: Uint32Array = new Uint32Array(0);
function addOperation(
newAction: Uint32Array,
addToStartOfQueue: boolean = false
): void {
const oldActions = pendingOperations;
pendingOperations = new Uint32Array(oldActions.length + newAction.length);
if (addToStartOfQueue) {
pendingOperations.set(newAction);
pendingOperations.set(oldActions, newAction.length);
} else {
pendingOperations.set(oldActions);
pendingOperations.set(newAction, oldActions.length);
}
}
// TODO Rethink the below queueing mechanism.
// Every mount is some parent's update (except for the root mount which we can explicitly handle)
// So maybe we only need to call queueFlushPendingEvents() for updates,
// and maybe we can rely on an id-to-root Map for this case, to limit the scope of what we crawl.
// Older React renderers did not have the concept of a commit.
// The data structure was just ad-hoc mutated in place.
// So except for the case of the root mounting the first time,
// there is no event we can observe to signal that a render is finished.
// However since older renderers were always synchronous,
// we can use setTimeout to batch operations together.
// In the case of a cascading update, we might batch multiple "commits"-
// but that should be okay, since the batching is not strictly necessary.
let flushPendingEventsTimeoutID: TimeoutID | null = null;
function queueFlushPendingEvents() {
if (flushPendingEventsTimeoutID === null) {
flushPendingEventsTimeoutID = setTimeout(() => {
flushPendingEventsTimeoutID = null;
// If there are pending operations, walk the tree and find them.
// Ideally we wouldjust pluck the pending operations out of the sets directly,
// but without doing a full traversal, it would be hard for us to determine the filtered parent.
// It should be possible to improve this though, by maintaining a map of id-to-parent,
// and crawling upward to the first non-filtered node.
// TODO Revisit this and think about it more...
if (pendingMountIDs.size > 0 || pendingUnmountIDs.size > 0) {
rootIDs.forEach(flushPendingEvents);
}
}, 0);
}
}
function flushInitialOperations() {
// Older versions of React do not support profiling mode, so there's nothing to flush.
// Crawl roots though and register any nodes that mounted before we were injected.
const roots =
renderer.Mount._instancesByReactRootID ||
renderer.Mount._instancesByContainerID;
for (let key in roots) {
const internalInstance = roots[key];
const id = getID(internalInstance);
rootIDs.add(id);
crawlAndRecordMounts(id, 0, true);
// It's safe to synchronously flush for the root we just crawled.
flushPendingEvents(id);
}
}
function crawlAndRecordMounts(
id: number,
parentID: number,
isInitialMount: boolean
) {
const internalInstance = idToInternalInstanceMap.get(id);
const shouldIncludeInTree =
parentID === 0 ||
getElementType(internalInstance) !== ElementTypeOtherOrUnknown;
// Not all nodes are mounted in the frontend DevTools tree,
// but it's important to track parent info even for the unmounted ones.
idToParentIDMap.set(id, parentID);
if (__DEBUG__) {
console.group(
'crawlAndRecordMounts() id:',
id,
'shouldIncludeInTree?',
shouldIncludeInTree
);
}
if (shouldIncludeInTree) {
const didMount = isInitialMount || pendingMountIDs.has(id);
const didUnmount = pendingUnmountIDs.has(id);
// If this node was both mounted and unmounted in the same batch,
// just skip it and don't send any update.
if (didMount && didUnmount) {
pendingUnmountIDs.delete(id);
return;
} else if (didMount) {
recordMount(id, parentID);
}
}
getChildIDs(internalInstance).forEach(childID =>
crawlAndRecordMounts(
childID,
shouldIncludeInTree ? id : parentID,
isInitialMount
)
);
if (__DEBUG__) {
console.groupEnd();
}
}
function flushPendingEvents(rootID: number): void {
// Crawl tree and queue mounts/updates.
crawlAndRecordMounts(rootID, 0, false);
// Send pending deletions.
pendingUnmountIDs.forEach(id => {
if (mountedIDs.has(id)) {
recordUnmount(id);
}
});
// Identify which renderer this update is coming from.
// This enables roots to be mapped to renderers,
// Which in turn enables fiber props, states, and hooks to be inspected.
const idArray = new Uint32Array(2);
idArray[0] = rendererID;
idArray[1] = rootID;
addOperation(idArray, true);
if (__DEBUG__) {
operationsArrayToString(pendingOperations);
}
// If we've already connected to the frontend, just pass the operations through.
hook.emit('operations', pendingOperations);
pendingMountIDs.clear();
pendingUnmountIDs.clear();
pendingOperations = new Uint32Array(0);
}
function inspectElement(id: number): InspectedElement | null {
let result = inspectElementRaw(id);
if (result === null) {
return null;
}
// TODO Review sanitization approach for the below inspectable values.
result.context = cleanForBridge(result.context);
result.props = cleanForBridge(result.props);
result.state = cleanForBridge(result.state);
return result;
}
function inspectElementRaw(id: number): InspectedElement | null {
const internalInstance = idToInternalInstanceMap.get(id);
const data = getData(internalInstance);
let context = null;
let owners = null;
let props = null;
let state = null;
let source = null;
if (internalInstance != null) {
const element = internalInstance._currentElement;
if (element !== null) {
props = element.props;
source = element._source != null ? element._source : null;
let owner = element._owner;
if (owner) {
owners = [];
while (owner != null) {
owners.push({
displayName: getData(owner).displayName || 'Unknown',
id: getID(owner),
});
owner = owner.owner;
}
}
}
context = internalInstance.context || null;
state = internalInstance.state || null;
}
return {
id,
// Hooks did not exist in legacy versions
canEditHooks: false,
// Does the current renderer support editable function props?
canEditFunctionProps: true,
// Suspense did not exist in legacy versions
canToggleSuspense: false,
// Can view component source location.
canViewSource:
data.type === ElementTypeClass || data.type === ElementTypeFunction,
displayName: data.displayName,
// Inspectable properties.
context,
hooks: null,
props,
state,
// List of owners
owners,
// Location of component in source coude.
source,
};
}
function logElementToConsole(id: number): void {
const result = inspectElementRaw(id);
if (result === null) {
console.warn(`Could not find element with id "${id}"`);
return;
}
const supportsGroup = typeof console.groupCollapsed === 'function';
if (supportsGroup) {
console.groupCollapsed(
`[Click to expand] %c<${result.displayName || 'Component'} />`,
// --dom-tag-name-color is the CSS variable Chrome styles HTML elements with in the console.
'color: var(--dom-tag-name-color); font-weight: normal;'
);
}
if (result.props !== null) {
console.log('Props:', result.props);
}
if (result.state !== null) {
console.log('State:', result.state);
}
if (result.context !== null) {
console.log('State:', result.context);
}
const nativeNode = getNativeFromInternal(id);
if (nativeNode !== null) {
console.log('Node:', nativeNode);
}
if (window.chrome || /firefox/i.test(navigator.userAgent)) {
console.log(
'Right-click any value to save it as a global variable for further inspection.'
);
}
if (supportsGroup) {
console.groupEnd();
}
}
function prepareViewElementSource(id: number): void {
const internalInstance = idToInternalInstanceMap.get(id);
if (internalInstance == null) {
console.warn(`Could not find instance with id "${id}"`);
return;
}
const element = internalInstance._currentElement;
if (element == null) {
console.warn(`Could not find element with id "${id}"`);
return;
}
global.$type = element.type;
}
function selectElement(id: number): void {
const internalInstance = idToInternalInstanceMap.get(id);
if (internalInstance == null) {
console.warn(`Could not find instance with id "${id}"`);
return;
}
switch (getElementType(internalInstance)) {
case ElementTypeClass:
case ElementTypeFunction:
const element = internalInstance._currentElement;
if (element == null) {
console.warn(`Could not find element with id "${id}"`);
return;
}
global.$r = {
props: element.props,
type: element.type,
};
break;
default:
break;
}
}
function recordPendingMount(internalInstance: InternalInstance) {
pendingMountIDs.add(getID(internalInstance));
if (__DEBUG__) {
console.log(
'%crecordPendingMount()',
'color: green',
getID(internalInstance)
);
}
queueFlushPendingEvents();
}
function recordPendingUnmount(internalInstance: InternalInstance) {
const id = getID(internalInstance);
pendingUnmountIDs.add(id);
// Not all nodes are mounted (or unmounted) in the frontend DevTools tree,
// so it's important to remove entries from this map on pending unmount.
idToParentIDMap.delete(id);
if (__DEBUG__) {
console.log(
'%crecordPendingUnmount()',
'color: red',
getID(internalInstance)
);
}
queueFlushPendingEvents();
}
function recordMount(id: number, parentID: number) {
const internalInstance = ((idToInternalInstanceMap.get(
id
): any): InternalInstance);
const isRoot = rootIDs.has(id);
if (__DEBUG__) {
console.log(
'%crecordMount()',
'color: green; font-weight: bold;',
id,
getData(internalInstance).displayName
);
}
mountedIDs.add(id);
if (isRoot) {
// TODO Is this right? For all versions?
const hasOwnerMetadata =
internalInstance._currentElement != null &&
internalInstance._currentElement._owner != null;
const operation = new Uint32Array(5);
operation[0] = TREE_OPERATION_ADD;
operation[1] = id;
operation[2] = ElementTypeRoot;
operation[3] = 0; // isProfilingSupported?
operation[4] = hasOwnerMetadata ? 1 : 0;
addOperation(operation);
} else {
const { displayName, key, type } = getData(internalInstance);
const ownerID =
internalInstance._currentElement != null &&
internalInstance._currentElement._owner != null
? getID(internalInstance._currentElement._owner)
: 0;
let encodedDisplayName = ((null: any): Uint8Array);
let encodedKey = ((null: any): Uint8Array);
if (displayName !== null) {
encodedDisplayName = utfEncodeString(displayName);
}
if (key !== null) {
// React$Key supports string and number types as inputs,
// But React converts numeric keys to strings, so we only have to handle that type here.
// https://github.com/facebook/react/blob/0e67969cb1ad8c27a72294662e68fa5d7c2c9783/packages/react/src/ReactElement.js#L187
encodedKey = utfEncodeString(((key: any): string));
}
const encodedDisplayNameSize =
displayName === null ? 0 : encodedDisplayName.length;
const encodedKeySize = key === null ? 0 : encodedKey.length;
const operation = new Uint32Array(
7 + encodedDisplayNameSize + encodedKeySize
);
operation[0] = TREE_OPERATION_ADD;
operation[1] = id;
operation[2] = type;
operation[3] = parentID;
operation[4] = ownerID;
operation[5] = encodedDisplayNameSize;
if (displayName !== null) {
operation.set(encodedDisplayName, 6);
}
operation[6 + encodedDisplayNameSize] = encodedKeySize;
if (key !== null) {
operation.set(encodedKey, 6 + encodedDisplayNameSize + 1);
}
addOperation(operation);
}
}
function recordUnmount(id: number) {
const internalInstance = idToInternalInstanceMap.get(id);
const isRoot = rootIDs.has(id);
if (__DEBUG__) {
console.log(
'%crecordUnmount()',
'color: red; font-weight: bold;',
id,
getData(internalInstance).displayName
);
}
if (isRoot) {
const operation = new Uint32Array(2);
operation[0] = TREE_OPERATION_REMOVE;
operation[1] = id;
addOperation(operation);
rootIDs.delete(id);
} else {
const operation = new Uint32Array(2);
operation[0] = TREE_OPERATION_REMOVE;
operation[1] = id;
addOperation(operation);
}
idToInternalInstanceMap.delete(id);
internalInstanceToIDMap.delete(internalInstance);
mountedIDs.delete(id);
}
function setInProps(id: number, path: Array<string | number>, value: any) {
const internalInstance = idToInternalInstanceMap.get(id);
if (internalInstance != null) {
const element = internalInstance._currentElement;
internalInstance._currentElement = {
...element,
props: copyWithSet(element.props, path, value),
};
forceUpdate(internalInstance._instance);
}
}
function setInState(id: number, path: Array<string | number>, value: any) {
const internalInstance = idToInternalInstanceMap.get(id);
if (internalInstance != null) {
setIn(internalInstance.state, path, value);
internalInstance.forceUpdate();
}
}
function setInContext(id: number, path: Array<string | number>, value: any) {
const internalInstance = idToInternalInstanceMap.get(id);
if (internalInstance != null) {
setIn(internalInstance.context, path, value);
forceUpdate(internalInstance);
}
}
function setIn(obj: Object, path: Array<string | number>, value: any) {
const last = path.pop();
const parent = path.reduce(
// $FlowFixMe
(reduced, attr) => (reduced ? reduced[attr] : null),
obj
);
if (parent) {
// $FlowFixMe
parent[last] = value;
}
}
// v16+ only features
const getCommitDetails = () => {
throw new Error('getCommitDetails not supported by this renderer');
};
const getFiberCommits = () => {
throw new Error('getFiberCommits not supported by this renderer');
};
const getInteractions = () => {
throw new Error('getInteractions not supported by this renderer');
};
const getProfilingDataForDownload = () => {
throw new Error(
'getProfilingDataForDownload not supported by this renderer'
);
};
const getProfilingSummary = () => {
throw new Error('getProfilingSummary not supported by this renderer');
};
const handleCommitFiberRoot = () => {
throw new Error('handleCommitFiberRoot not supported by this renderer');
};
const handleCommitFiberUnmount = () => {
throw new Error('handleCommitFiberUnmount not supported by this renderer');
};
const overrideSuspense = () => {
throw new Error('overrideSuspense not supported by this renderer');
};
const setInHook = () => {
throw new Error('setInHook not supported by this renderer');
};
const startProfiling = () => {
throw new Error('startProfiling not supported by this renderer');
};
const stopProfiling = () => {
throw new Error('stopProfiling not supported by this renderer');
};
return {
cleanup,
flushInitialOperations,
getCommitDetails,
getFiberCommits,
getInteractions,
getInternalIDFromNative,
getNativeFromInternal,
getProfilingDataForDownload,
getProfilingSummary,
handleCommitFiberRoot,
handleCommitFiberUnmount,
inspectElement,
logElementToConsole,
overrideSuspense,
prepareViewElementSource,
renderer,
selectElement,
setInContext,
setInHook,
setInProps,
setInState,
startProfiling,
stopProfiling,
};
}
@@ -0,0 +1,146 @@
// @flow
const SEPARATOR = '.';
const SUBSEPARATOR = ':';
const FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.
// The Symbol used to tag the ReactElement type. If there is no native Symbol
// nor polyfill, then a plain number is used for performance.
const ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
const REACT_ELEMENT_TYPE =
(typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) ||
0xeac7;
/**
* Escape and wrap key so it is safe to use as a reactid
*
* @param {string} key to be escaped.
* @return {string} the escaped key.
*/
function escape(key: string): string {
const escapeRegex = /[=:]/g;
const escaperLookup = {
'=': '=0',
':': '=2',
};
const escapedString = ('' + key).replace(escapeRegex, function(match) {
return escaperLookup[match];
});
return '$' + escapedString;
}
/**
* Generate a key string that identifies a component within a set.
*
* @param {*} component A component that could contain a manual key.
* @param {number} index Index that is used if a manual key is not provided.
* @return {string}
*/
function getComponentKey(component, index) {
// Do some typechecking here since we call this blindly. We want to ensure
// that we don't block potential future ES APIs.
if (
typeof component === 'object' &&
component !== null &&
component.key != null
) {
// Explicit key
return escape(component.key);
}
// Implicit key determined by the index in the set
return index.toString(36);
}
/**
* We do a copied the 'traverseAllChildrenImpl' method from
* `React.Children` so that we don't pull in the whole React library.
* @param {?*} children Children tree container.
* @param {!string} nameSoFar Name of the key path so far.
* @param {!function} callback Callback to invoke with each child found.
* @param {?*} traverseContext Used to pass information throughout the traversal
* process.
* @return {!number} The number of children in this subtree.
*/
export default function traverseAllChildrenImpl(
children: any,
nameSoFar: string,
callback: Function,
traverseContext: any
): number {
const type = typeof children;
if (type === 'undefined' || type === 'boolean') {
// All of the above are perceived as null.
children = null;
}
if (
children === null ||
type === 'string' ||
type === 'number' ||
// The following is inlined from ReactElement. This means we can optimize
// some checks. React Fiber also inlines this logic for similar purposes.
(type === 'object' && children.$$typeof === REACT_ELEMENT_TYPE)
) {
callback(
traverseContext,
children,
// If it's the only child, treat the name as if it was wrapped in an array
// so that it's consistent if the number of children grows.
nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar
);
return 1;
}
let child;
let nextName;
let subtreeCount = 0; // Count of children found in the current subtree.
let nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR;
if (Array.isArray(children)) {
for (let i = 0; i < children.length; i++) {
child = children[i];
nextName = nextNamePrefix + getComponentKey(child, i);
subtreeCount += traverseAllChildrenImpl(
child,
nextName,
callback,
traverseContext
);
}
} else {
let iteratorFn =
(ITERATOR_SYMBOL && children[ITERATOR_SYMBOL]) ||
children[FAUX_ITERATOR_SYMBOL];
if (typeof iteratorFn === 'function') {
let iterator = iteratorFn.call(children);
let step;
let ii = 0;
while (!(step = iterator.next()).done) {
child = step.value;
nextName = nextNamePrefix + getComponentKey(child, ii++);
subtreeCount += traverseAllChildrenImpl(
child,
nextName,
callback,
traverseContext
);
}
} else if (type === 'object') {
let addendum =
' If you meant to render a collection of children, use an array ' +
'instead.';
let childrenString = '' + children;
throw Error(
`The React Devtools cannot render an object as a child. (found: ${
childrenString === '[object Object]'
? 'object with keys {' + Object.keys(children).join(', ') + '}'
: childrenString
}). ${addendum}`
);
}
}
return subtreeCount;
}
+55
View File
@@ -0,0 +1,55 @@
// @flow
import type { InternalInstance } from './renderer';
export function decorateResult(
object: Object,
attr: string,
fn: Function
): Function {
const old = object[attr];
object[attr] = function(instance: InternalInstance) {
const res = old.apply(this, arguments);
fn(res);
return res;
};
return old;
}
export function decorate(object: Object, attr: string, fn: Function): Function {
const old = object[attr];
object[attr] = function(instance: InternalInstance) {
const res = old.apply(this, arguments);
fn.apply(this, arguments);
return res;
};
return old;
}
export function decorateMany(
source: Object,
fns: { [attr: string]: Function }
): Object {
const olds = {};
for (const name in fns) {
olds[name] = decorate(source, name, fns[name]);
}
return olds;
}
export function restoreMany(source: Object, olds: Object): void {
for (let name in olds) {
source[name] = olds[name];
}
}
export function forceUpdate(instance: InternalInstance): void {
if (typeof instance.forceUpdate === 'function') {
instance.forceUpdate();
} else if (
instance.updater != null &&
typeof instance.updater.enqueueForceUpdate === 'function'
) {
instance.updater.enqueueForceUpdate(this, () => {}, 'forceUpdate');
}
}
+17 -10
View File
@@ -14,7 +14,7 @@ import {
ElementTypeRoot,
ElementTypeSuspense,
} from 'src/devtools/types';
import { getDisplayName, utfEncodeString } from '../utils';
import { getDisplayName, getUID, utfEncodeString } from '../utils';
import { cleanForBridge, copyWithSet, setInObject } from './utils';
import {
__DEBUG__,
@@ -25,7 +25,6 @@ import {
TREE_OPERATION_RECURSIVE_REMOVE_CHILDREN,
TREE_OPERATION_UPDATE_TREE_BASE_DURATION,
} from '../constants';
import { getUID } from '../utils';
import { inspectHooksOfFiber } from './ReactDebugHooks';
import type {
@@ -312,8 +311,6 @@ export function attach(
: symbolOrNumber;
}
// TODO: we might want to change the data structure once we no longer suppport Stack versions of `getData`.
// TODO: Keep in sync with getElementType()
function getDataForFiber(fiber: Fiber): FiberData {
const { elementType, type, key, tag } = fiber;
@@ -1166,7 +1163,7 @@ export function attach(
currentRootID = -1;
}
function findNativeByFiberID(id: number) {
function getNativeFromInternal(id: number) {
try {
const fiber = findCurrentFiberUsingSlowPath(idToFiberMap.get(id));
if (fiber === null) {
@@ -1190,7 +1187,7 @@ export function attach(
}
}
function getFiberIDFromNative(
function getInternalIDFromNative(
hostInstance,
findNearestUnfilteredAncestor = false
) {
@@ -1441,6 +1438,14 @@ export function attach(
case ForwardRef:
global.$type = fiber.type.render;
break;
case MemoComponent:
case SimpleMemoComponent:
const { elementType, type } = fiber;
global.$type =
elementType != null && elementType.type != null
? elementType.type
: type;
break;
default:
global.$type = null;
break;
@@ -1483,7 +1488,9 @@ export function attach(
tag === FunctionComponent ||
tag === IncompleteClassComponent ||
tag === IndeterminateComponent ||
tag === ForwardRef
tag === MemoComponent ||
tag === ForwardRef ||
tag === SimpleMemoComponent
) {
canViewSource = true;
if (stateNode && stateNode.context != null) {
@@ -1623,7 +1630,7 @@ export function attach(
if (result.hooks !== null) {
console.log('Hooks:', result.hooks);
}
const nativeNode = findNativeByFiberID(id);
const nativeNode = getNativeFromInternal(id);
if (nativeNode !== null) {
console.log('Node:', nativeNode);
}
@@ -1938,10 +1945,10 @@ export function attach(
cleanup,
flushInitialOperations,
getCommitDetails,
getFiberIDFromNative,
getInternalIDFromNative,
getFiberCommits,
getInteractions,
findNativeByFiberID,
getNativeFromInternal,
getProfilingDataForDownload,
getProfilingSummary,
handleCommitFiberRoot,
+11 -8
View File
@@ -19,7 +19,7 @@ export type FiberData = {|
type: ElementType,
|};
export type NativeType = {};
export type NativeType = Object;
export type RendererID = number;
type Dispatcher = any;
@@ -90,17 +90,20 @@ export type ProfilingSummary = {|
rootID: number,
|};
export type GetInternalIDFromNative = (
component: NativeType,
findNearestUnfilteredAncestor?: boolean
) => number | null;
export type GetNativeFromInternal = (id: number) => ?NativeType;
export type RendererInterface = {
cleanup: () => void,
findNativeByFiberID: (id: number) => ?NativeType,
flushInitialOperations: () => void,
getCommitDetails: (rootID: number, commitIndex: number) => CommitDetails,
getFiberIDFromNative: (
component: NativeType,
findNearestUnfilteredAncestor?: boolean
) => number | null,
getFiberCommits: (rootID: number, fiberID: number) => FiberCommits,
getInteractions: (rootID: number) => Interactions,
getInternalIDFromNative: GetInternalIDFromNative,
getNativeFromInternal: GetNativeFromInternal,
getProfilingDataForDownload: (rootID: number) => Object,
getProfilingSummary: (rootID: number) => ProfilingSummary,
handleCommitFiberRoot: (fiber: Object) => void,
@@ -112,14 +115,14 @@ export type RendererInterface = {
renderer: ReactRenderer | null,
selectElement: (id: number) => void,
setInContext: (id: number, path: Array<string | number>, value: any) => void,
setInProps: (id: number, path: Array<string | number>, value: any) => void,
setInState: (id: number, path: Array<string | number>, value: any) => void,
setInHook: (
id: number,
index: number,
path: Array<string | number>,
value: any
) => void,
setInProps: (id: number, path: Array<string | number>, value: any) => void,
setInState: (id: number, path: Array<string | number>, value: any) => void,
startProfiling: () => void,
stopProfiling: () => void,
};
+104 -1
View File
@@ -1,6 +1,16 @@
// @flow
const LRU = require('lru-cache');
import LRU from 'lru-cache';
import {
TREE_OPERATION_ADD,
TREE_OPERATION_REMOVE,
TREE_OPERATION_RESET_CHILDREN,
TREE_OPERATION_RECURSIVE_REMOVE_CHILDREN,
TREE_OPERATION_UPDATE_TREE_BASE_DURATION,
} from './constants';
import { ElementTypeRoot } from 'src/devtools/types';
import type { ElementType } from 'src/devtools/types';
const FB_MODULE_RE = /^(.*) \[from (.*)\]$/;
const cachedDisplayNames: WeakMap<Function, string> = new WeakMap();
@@ -76,3 +86,96 @@ export function utfEncodeString(string: string): Uint32Array {
function toCodePoint(string: string) {
return string.codePointAt(0);
}
export function operationsArrayToString(operations: Uint32Array) {
const rendererID = operations[0];
const rootID = operations[1];
console.group('rendererID:', rendererID, 'rootID:', rootID);
let i = 2;
while (i < operations.length) {
let id: number = ((null: any): number);
let parentID: number = ((null: any): number);
let type: ElementType = ((null: any): ElementType);
const operation = operations[i];
switch (operation) {
case TREE_OPERATION_ADD:
id = ((operations[i + 1]: any): number);
type = ((operations[i + 2]: any): ElementType);
i = i + 3;
if (type === ElementTypeRoot) {
console.log(`Add root fiber ${id}`);
i++; // supportsProfiling
i++; // hasOwnerMetadata
} else {
parentID = ((operations[i]: any): number);
i++;
i++; // ownerID
const displayNameLength = operations[i];
i++;
const displayName =
displayNameLength === 0
? null
: utfDecodeString(
(operations.slice(i, i + displayNameLength): any)
);
i += displayNameLength;
const keyLength = operations[i];
i++;
i += +keyLength;
console.log(
`Add fiber ${id} (${displayName || 'null'}) as child of ${parentID}`
);
}
break;
case TREE_OPERATION_RECURSIVE_REMOVE_CHILDREN: {
id = ((operations[i + 1]: any): number);
i = i + 2;
console.log(`Recursively remove children from fiber ${id}`);
break;
}
case TREE_OPERATION_REMOVE: {
id = ((operations[i + 1]: any): number);
i = i + 2;
console.log(`Remove fiber ${id}`);
break;
}
case TREE_OPERATION_RESET_CHILDREN:
id = ((operations[i + 1]: any): number);
const numChildren = ((operations[i + 2]: any): number);
const children = ((operations.slice(
i + 3,
i + 3 + numChildren
): any): Array<number>);
i = i + 3 + numChildren;
console.log(`Re-order fiber ${id} children ${children.join(',')}`);
break;
case TREE_OPERATION_UPDATE_TREE_BASE_DURATION:
// Base duration updates are only sent while profiling is in progress.
// We can ignore them at this point.
// The profiler UI uses them lazily in order to generate the tree.
i = i + 3;
break;
default:
throw Error(`Unsupported Bridge operation ${operation}`);
}
}
console.groupEnd();
}