4

Essayer de rendre un composant avec réagissent chrome puppeteer courir sur mon environnement Node.js j'ai problème suivant:avec Google Chromes React Marionnettiste

  • exploitation forestière element me donne dans le chrome sans tête console : console.log(element) =><div id="test-wrapper"></div>
  • testWrapper dans le 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); 
    }); 
    

donc essayer de faire ...

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

... résultats de toute évidence une erreur (node:90555) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Invariant Violation: _registerComponent(...): Target container is not a DOM element.

je me sens comme même si je parviens à obtenir l'élément DOM je manque quelque chose ici pour injecter une application de réaction.

+0

Que contient le testDocument.html? At-il tous les prérequis pour le rendu d'une application de réaction? Si c'est le cas, vous devriez le rendre dans la fonction d'évaluation, pas en dehors de celle-ci (où console.log (testWrapper)) est maintenant. – tomahaug

+0

peut-être faire référentiel minimaliste pour reproduire l'erreur, donnera une facilité à examiner le problème. –

Répondre

2

.evaluate ne retourne pas un élément dom. Et, vous essayez de modifier les éléments dans un contexte différent. La page dans la fenêtre du navigateur et le contexte que vous avez dans votre nodeJS sont absolument différents.

Voici une façon différente de traiter React et Puppeteer. D'abord, j'ai un fichier d'entrée où j'exporte la fonction à la fenêtre. En faisant cela, je peux facilement y accéder à partir du contexte des navigateurs. Au lieu de fenêtre, vous pouvez réellement l'exporter et essayer s'exposer-chargeur et ainsi de suite. Je vais utiliser webpack pour le construire.

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; 

Sur la configuration 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 
    } 
}; 

Maintenant, chaque fois que je lance webpack, il va créer un fichier bundle.js pour moi. Maintenant, nous allons avoir un fichier marionnettiste,

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

Comme vous pouvez le voir, je suis en utilisant la fonction renderIt que j'exposé à la fenêtre précédente. Et quand je le lance, voici le résultat,

enter image description here

Sweet! Bonjour de réagir :)

Oh! Et s'il échoue à exécuter le script sur la page en raison du problème CORS, vous pouvez l'injecter à la place en utilisant l'ancienne fonction injectFile, jusqu'à ce qu'ils corrigent leur fonction addScriptTag ou suppriment la dépréciation de 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

Alors, quelle est la bonne façon de traiter marionnettiste et de réagir? Pour autant que je comprenne j'ai deux options: a) passer une URL qui rend une page de réaction au marionnettiste ou b) passer un composant de réaction comme html (ReactDOMServer.renderToString (element)) à marionnettiste. J'ai une logique de connexion complexe que je voudrais éviter, donc l'option a) n'est pas préférée. Avec l'option b) je rencontre le problème qui oblige les composants de componentDidMount à ne plus être lancés côté serveur (qui ne peuvent pas être déplacés vers componentWillMount) .... Des conseils à ce sujet? – usagidon

+0

Qu'essayez-vous de faire exactement? –

+1

Là, mis à jour la réponse réelle avec un véritable exemple de travail. –