与 Google Chromes Puppeteer 互动
React with Google Chromes Puppeteer
尝试使用chrome puppeteer渲染反应组件
运行 在我的 Node.js 环境中,我遇到了以下问题:
- logging
element
在 headless chrome 控制台中给我:console.log(element)
=> <div id="test-wrapper"></div>
testWrapper
在终端 console.log(testWrapper)
=> {}
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
const testDocumentPath = path.resolve('./lib/components/util/testDocument.html');
await page.goto(`file://${testDocumentPath}`);
const testWrapper = await page.evaluate((selector) => {
const element = document.querySelector(selector);
console.log(element);
return element;
}, '#test-wrapper');
console.log(testWrapper);
});
所以想做……
ReactDOM.render(
<div>{':)'}</div>,
testWrapper
);
…显然会导致错误(node:90555) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Invariant Violation: _registerComponent(...): Target container is not a DOM element.
我觉得即使我设法获得了 DOM 元素,我还是遗漏了一些东西来注入 React 应用程序。
.evaluate
不是 return 一个 dom 元素。而且,您正试图在不同的上下文中修改元素。浏览器中的页面 window 和你在 nodeJS 中的上下文是完全不同的。
这是处理 React 和 Puppeteer 的另一种方式。
首先,我有一个入口文件,我将函数导出到 window。
通过这样做,我可以轻松地从浏览器上下文访问它。代替 window,您实际上可以将其导出并尝试使用 expose-loader 等。我将使用 webpack 来构建它。
import React from 'react';
import { render } from 'react-dom';
function Hello() {
return <h1>Hello from React</h1>;
}
function renderIt(domNode) {
render(<Hello />, domNode);
}
window.renderIt = renderIt;
在 webpack 配置上,
const webpack = require('webpack');
const loaders = [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['babel-preset-es2015', 'babel-preset-react'],
plugins: []
}
}
];
module.exports = {
entry: './entry.js',
output: {
path: __dirname,
filename: 'bundle.js',
libraryTarget: 'umd'
},
module: {
loaders: loaders
}
};
现在,每当我 运行 webpack 时,它都会为我创建一个 bundle.js 文件。现在让我们有一个人偶文件,
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://github.com');
await page.addScriptTag({ path: require.resolve('./bundle.js') });
await page.evaluate(() => {
renderIt(document.querySelector('div.jumbotron.jumbotron-codelines > div > div > div > h1'));
});
await page.screenshot({ path: 'example.png' });
await browser.close();
})();
如您所见,我正在使用我之前公开给 window 的 renderIt 函数。当我 运行 它时,结果如下,
太棒了!来自 React 的问候 :)
哦!如果由于 CORS 问题而无法在页面上执行脚本,您可以使用旧的 injectFile 函数注入它,直到他们修复其 addScriptTag 函数,或从 injectFile 中删除弃用。
/**
* injects file to puppeteer page context
* @param {Object} page context where to execute the script
* @param {String} filePath path of specific script
* @return {Promise} Injects content to page context
*/
const fs = require('fs');
async function injectFile(page, filePath) {
let contents = await new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) return reject(err);
resolve(data);
});
});
contents += `//# sourceURL=` + filePath.replace(/\n/g, '');
return page.mainFrame().evaluate(contents);
}
// usage: await injectFile(page, require.resolve('FILE PATH'));
// export it if you want to keep things seperate
尝试使用chrome puppeteer渲染反应组件 运行 在我的 Node.js 环境中,我遇到了以下问题:
- logging
element
在 headless chrome 控制台中给我:console.log(element)
=><div id="test-wrapper"></div>
testWrapper
在终端console.log(testWrapper)
=>{}
puppeteer.launch().then(async browser => { const page = await browser.newPage(); const testDocumentPath = path.resolve('./lib/components/util/testDocument.html'); await page.goto(`file://${testDocumentPath}`); const testWrapper = await page.evaluate((selector) => { const element = document.querySelector(selector); console.log(element); return element; }, '#test-wrapper'); console.log(testWrapper); });
所以想做……
ReactDOM.render(
<div>{':)'}</div>,
testWrapper
);
…显然会导致错误(node:90555) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Invariant Violation: _registerComponent(...): Target container is not a DOM element.
我觉得即使我设法获得了 DOM 元素,我还是遗漏了一些东西来注入 React 应用程序。
.evaluate
不是 return 一个 dom 元素。而且,您正试图在不同的上下文中修改元素。浏览器中的页面 window 和你在 nodeJS 中的上下文是完全不同的。
这是处理 React 和 Puppeteer 的另一种方式。 首先,我有一个入口文件,我将函数导出到 window。
通过这样做,我可以轻松地从浏览器上下文访问它。代替 window,您实际上可以将其导出并尝试使用 expose-loader 等。我将使用 webpack 来构建它。
import React from 'react';
import { render } from 'react-dom';
function Hello() {
return <h1>Hello from React</h1>;
}
function renderIt(domNode) {
render(<Hello />, domNode);
}
window.renderIt = renderIt;
在 webpack 配置上,
const webpack = require('webpack');
const loaders = [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['babel-preset-es2015', 'babel-preset-react'],
plugins: []
}
}
];
module.exports = {
entry: './entry.js',
output: {
path: __dirname,
filename: 'bundle.js',
libraryTarget: 'umd'
},
module: {
loaders: loaders
}
};
现在,每当我 运行 webpack 时,它都会为我创建一个 bundle.js 文件。现在让我们有一个人偶文件,
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://github.com');
await page.addScriptTag({ path: require.resolve('./bundle.js') });
await page.evaluate(() => {
renderIt(document.querySelector('div.jumbotron.jumbotron-codelines > div > div > div > h1'));
});
await page.screenshot({ path: 'example.png' });
await browser.close();
})();
如您所见,我正在使用我之前公开给 window 的 renderIt 函数。当我 运行 它时,结果如下,
太棒了!来自 React 的问候 :)
哦!如果由于 CORS 问题而无法在页面上执行脚本,您可以使用旧的 injectFile 函数注入它,直到他们修复其 addScriptTag 函数,或从 injectFile 中删除弃用。
/**
* injects file to puppeteer page context
* @param {Object} page context where to execute the script
* @param {String} filePath path of specific script
* @return {Promise} Injects content to page context
*/
const fs = require('fs');
async function injectFile(page, filePath) {
let contents = await new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) return reject(err);
resolve(data);
});
});
contents += `//# sourceURL=` + filePath.replace(/\n/g, '');
return page.mainFrame().evaluate(contents);
}
// usage: await injectFile(page, require.resolve('FILE PATH'));
// export it if you want to keep things seperate