4

Der Versuch, eine Komponente Ich habe folgendes Problem mit chrome puppeteer läuft auf meinem Node.js Umwelt reagieren machen:Reagieren mit Google Chromes Puppeteer

  • Protokollierung element gibt mir in der kopflos Chrom Konsole : console.log(element) =><div id="test-wrapper"></div>
  • testWrapper in das Terminal 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); 
    }); 
    

So versuchen zu tun ...

ReactDOM.render(
    <div>{':)'}</div>, 
    testWrapper 
); 

... führt offensichtlich zu einem Fehler (node:90555) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Invariant Violation: _registerComponent(...): Target container is not a DOM element.

Ich mag sogar das Gefühl, wenn ich das DOM-Element verwalten bekommen ich hier etwas fehlt bin eine Reaktionsanwendung injizieren.

+0

Was ist in der testDocument.html vorhanden? Hat es alle Voraussetzungen zum Rendern einer Reactive-App? Wenn ja, sollten Sie es in der Evaluierungsfunktion rendern, nicht außerhalb davon (wo console.log (testWrapper)) jetzt ist. – tomahaug

+0

vielleicht minimalistischen Repository, um den Fehler zu reproduzieren, wird eine Leichtigkeit geben, um das Problem zu untersuchen. –

Antwort

2

.evaluate gibt kein dom-Element zurück. Und Sie versuchen, die Elemente in anderem Kontext zu ändern. Die Seite im Browserfenster und der Kontext, den Sie in Ihrem KnotenJS haben, unterscheiden sich grundlegend.

Hier ist ein anderer Weg, um mit React und Puppenspieler umzugehen. Zuerst habe ich eine Eingabedatei, wo ich die Funktion in Fenster exportieren.

Dadurch kann ich leicht aus dem Browser Kontext zugreifen. Statt Fenster können Sie es exportieren und expose-loader usw. ausprobieren. Ich werde Webpack verwenden, um es zu bauen.

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; 

Auf der webpack config

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 
    } 
}; 

Nun, wenn ich webpack laufen, wird es eine bundle.js Datei für mich erstellen. Lassen Sie uns jetzt einen puppeteer-Datei haben,

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(); 
})(); 

Wie Sie sehen, ich bin mit der renderIt Funktion, die ich Fenster ausgesetzt früher. Und wenn ich es laufen, hier ist das Ergebnis,

enter image description here

Sweet! Hallo von reagieren :)

Oh! Wenn das Skript aufgrund eines CORS-Problems nicht auf der Seite ausgeführt werden kann, können Sie es stattdessen mithilfe der alten Funktion injectFile einbinden, bis die Funktion addScriptTag korrigiert oder die IncrementFile-Eigenschaft entfernt wurde.

/** 
* 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

Also, was ist der richtige Weg, um mit Puppenspieler umzugehen und zu reagieren? Soweit ich es verstehe, habe ich zwei Möglichkeiten: a) übergebe eine URL, die eine Antwortseite zum Puppenspieler rendert oder b) eine reaktive Komponente als html übergebe (ReactDOMServer.renderToString (Element)) zum Puppenspieler. Ich habe eine komplexe Login-Logik, die ich vermeiden möchte, daher wird Option a) nicht bevorzugt. Mit Option b) stoße ich auf das Problem, dass Dinge von componentDidMount nicht mehr serverseitig laufen (die nicht in componentWillMount verschoben werden können) .... Irgendwelche Hinweise? – usagidon

+0

Was versuchst du genau zu machen? –

+1

Dort aktualisiert die tatsächliche Antwort mit realen Arbeitsbeispiel. –

Verwandte Themen