4

试图反应渲染与运行在我的Node.js环境我有以下问题chrome puppeteer 反应成分与谷歌铬合金木偶

  • 记录element让我在无头铬控制台:console.log(element) =><div id="test-wrapper"></div>
  • 在终端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元素注入反应应用程序。

+0

testDocument.html中有什么?它是否具有呈现反应应用程序的所有先决条件?如果是这样,你应该在评估函数中渲染它,而不是在它之外(console.log(testWrapper))现在。 – tomahaug

+0

可能会使极简主义存储库重现错误,将会轻松检查问题。 –

回答

2

.evaluate不返回一个dom元素。而且,您正在尝试修改不同上下文中的元素。浏览器窗口中的页面和nodeJS中的上下文完全不同。

以下是处理React和Puppeteer的不同方法。 首先,我有一个入口文件,我将函数导出到窗口。

通过这样做,我可以轻松地从浏览器上下文访问它。您可以实际导出它并尝试使用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(); 
})(); 

正如你所看到的,我使用,我接触到窗口早些时候renderIt功能。当我运行它,这里是结果,

enter image description here

甜!你好,反应:)

哦!如果由于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 
+0

那么对付木偶师并作出反应的正确方法是什么?据我了解,我有两个选择:a)传递一个url来呈现一个反应页面给puppeteer,或者b)传递一个反应组件作为html(ReactDOMServer。renderToString(元素))给木偶。我有一些我想避免的复杂登录逻辑,所以选项a)不是首选。使用选项b)我遇到了需要componentDidMount的问题,不再运行服务器端(不能移动到componentWillMount)....对此有何建议? – usagidon

+0

你想要做什么? –

+1

那里,用实际工作示例更新了实际答案。 –