记录一下研究了一半天的 react code inject,主要思路是使用 js inject 一段 html,并引入 react,babel 相关的 umd 库,然后使用 babel.transform + eval 进行渲染。
const $section = document.createElement('section');
$section.innerHTML = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="rootxxx"></div>
</body>
<script type="text/babel" name="qwe">
const { useState } = React;
const App = () => {
const [a, setA] = useState(0);
const onClick = () => setA((x) => x + 1);
return (
<div>
hello, world! {a}
<button onClick={onClick}>click me!</button>
</div>
);
};
ReactDOM.render(React.createElement(App), document.getElementById('rootxxx'));
</script>
</html>
`;
$section.style.width = '100%';
$section.style.height = '800px';
$section.style.top = '0';
$section.style.left = '0';
$section.style.position = 'relative';
$section.style.zIndex = '9999';
$section.style.backgroundColor = 'white';
document.body.appendChild($section);
function loadScript(url) {
return new Promise((res) => {
const s = document.createElement('script');
s.src = url;
s.addEventListener('load', () => res(s));
document.body.appendChild(s);
});
}
loadScript('https://unpkg.com/react@17/umd/react.production.min.js')
.then(() =>
loadScript('https://unpkg.com/react-dom@17/umd/react-dom.production.min.js')
)
.then(() =>
loadScript('https://unpkg.com/@babel/standalone@7.13.15/babel.js')
)
.then(() => {
const scripts = document.querySelector('script[name="qwe"]');
const { code } = Babel.transform(scripts.innerText, { presets: ['react'] });
eval(code);
alert('inject ok, scroll end to get it');
});