Razzle: Comment résoudre les problèmes de rendu du serveur ?

Créé le 5 févr. 2019  ·  9Commentaires  ·  Source: jaredpalmer/razzle

Bonjour,

Nous avons remarqué un problème où si vous vous connectez à la console de recherche de Google et récupérez en tant que Google, le site Web est affiché comme une page vierge.

J'ai fait quelques recherches, et certaines d'entre elles m'ont conduit à cet article :

https://medium.com/@gajus/react -application-seen-as-a-blank-page-via-fetch-as-google-afb11dff8562

Il est très probable que le moteur de recherche et l'extraction comme google lui-même ne se comportent pas de la même manière, sinon nous aurions déjà perdu des classements, néanmoins j'aimerais résoudre ce problème, car cela empêcherait tout propriétaire de site Web de rester éveillé.

J'ai téléchargé phantomjs, en supposant que c'est la même chose que fetch que Google, et essayer de le rendre renvoie un certain nombre d'erreurs :

image

Ce problème peut être aussi simple à résoudre que de changer les navigateurs cibles en cours de compilation, mais la simple installation de babel/polyfil et l'importation ne fonctionnent pas.

Quelqu'un pourrait-il m'indiquer la bonne direction ici?

stale

Commentaire le plus utile

Donc ma suggestion (et nous avons peut-être besoin d'un guide de dépannage dans la documentation à ce sujet) est de commenter autant que possible de server.js , client.js , App.js , et potentiellement certains aspects de votre webpack remplacent (le cas échéant) pour ramener votre application Razzle à un état semblable à "hello world". Je suggérerais également de copier le modèle HTML de Razzle dans votre fichier server.js juste pour être sûr que tous les scripts sont chargés correctement dès la sortie de la boîte. Une fois qu'il est en cours d'exécution, ouvrez les outils de développement Chrome et accédez à l'onglet "Performances", cochez la case "Captures d'écran", puis appuyez sur l'icône Actualiser. Voir le GIF ci-dessous.

kapture 2019-02-05 at 8 33 42

L'objectif est de s'assurer qu'il n'y a pas de cadre blanc vierge dans la zone de chronologie. Après avoir obtenu un rendu correct sans flashs, vous devriez rajouter de plus en plus de votre ancien code. Faites des pas de bébé. C'est assez facile à gâcher si vous ne faites pas attention.

En ce qui concerne votre cas spécifique, je commencerais par supprimer tous ces éléments du gestionnaire de balises google, tous vos CSS, ainsi que le fractionnement de code que vous effectuez. Faites simplement le rendu et travaillez à l'envers. Ensuite, faites fonctionner Redux. Ajoutez ensuite le casque de réaction, puis, une fois que vous pensez avoir bien compris, vérifiez également en effectuant un test Lighthouse (onglet Audits). Validez cet état dans une nouvelle branche afin de pouvoir y revenir ultérieurement. Ensuite, ajoutez à nouveau vos scripts d'analyse et vérifiez à nouveau le rendu. Enfin, essayez de rajouter le fractionnement de code.

Remarque : Si vous conservez votre css et effectuez l'analyse ci-dessus avec Razzle en mode développement, vous pouvez obtenir un FOUC car Razzle ne traite pas les styles .css sur le serveur pendant le développement (uniquement sur le client). Ainsi, pour tester pleinement que vous faites un SSR approprié avec une hydratation de style si vous utilisez des fichiers .css , vous devez créer Razzle pour la production et exécuter le serveur de production localement. Cependant, si vous vérifiez simplement la présence de votre code HTML depuis le serveur, vous pouvez l'exécuter en mode développement.

Tous les 9 commentaires

Si votre page est vide, c'est que vous avez rompu votre SSR ou votre schéma d'hydratation. Razzle ne souffre pas de ce que vous avez décrit, en fait, il est utilisé sur des sites axés sur le référencement comme BBC.com. peux-tu coller ton fichier server.js ? Récupérez-vous vos données sur le serveur ?

Salut Jared,

Merci pour la réponse rapide, oui, nous récupérons les données d'un serveur.

Voici mon server.js

import App from './App';
import React from 'react';
import Helmet from 'react-helmet';
import { StaticRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import express from 'express';
import compression from 'compression';
import { renderToString } from 'react-dom/server';

import configureStore from './store/configureStore';
import { remoteLoader } from './api/remoteLoader';
import serialize from 'serialize-javascript';

import { Capture } from 'react-loadable';
import { getBundles } from 'react-loadable/webpack';
import stats from '../build/react-loadable.json';

import { IS_PRODUCTION } from './components/shared/constants';

const assets = require(process.env.RAZZLE_ASSETS_MANIFEST);

const server = express();
server.use(compression());

if (!IS_PRODUCTION) {
    server.set('cache', false);
}

server
    .disable('x-powered-by')
    .use(express.static(process.env.RAZZLE_PUBLIC_DIR, { Expires: '30d' }))
    .get('/*', (req, res) => {
        //Ensures clients with old css paths are served the current file
        if (req.path.indexOf('/static/css') > -1 && assets.client.css) {
            const currentCssFile = `${process.env.RAZZLE_PUBLIC_DIR}${assets.client.css}`;
            return res.sendFile(currentCssFile);
        }

        remoteLoader(apiResult => {
            const responseCode = typeof apiResult.status === 'undefined' ? 404 : apiResult.status;

            if (responseCode === 301) {
                return res.redirect(responseCode, apiResult.headers.location);
            }

            // Compile an initial state
            const initialState = {
                remote: {
                    cms: {
                        result: apiResult ? apiResult.data : false,
                        loading: false
                    },
                    myDrewberry: {
                        searchResults: null,
                        loading: false,
                        failed: false
                    }
                }
            };
            // Create a new Redux store instance
            const store = configureStore(initialState);

            const context = {};
            const modules = [];
            const markup = renderToString(
                <Capture report={moduleName => modules.push(moduleName)}>
                    <StaticRouter context={context} location={req.url}>
                        <Provider store={store}>
                            <App />
                        </Provider>
                    </StaticRouter>
                </Capture>
            );
            const helmet = Helmet.renderStatic();

            if (context.url) {
                res.redirect(context.url);
            } else {
                const bundles = getBundles(stats, modules);
                const chunks = bundles.filter(bundle => bundle.file.endsWith('.js'));

                res.status(responseCode).send(
                    `<!doctype html>
                    <html ${helmet.htmlAttributes.toString()}>
                    <head>

                        ${assets.client.css ? `<link rel="stylesheet" href="${assets.client.css}">` : ''}
                        ${helmet.title.toString()}
                        ${helmet.meta.toString()}
                        ${helmet.link.toString()}
                        <link rel="icon" type="image/png" href="/favicon16.png" sizes="16x16"/>
                        <link rel="icon" type="image/png" href="/favicon32.png" sizes="32x32"/>
                        <link rel="icon" type="image/png" href="/favicon96.png" sizes="96x96"/>
                        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/> <!--320-->
                        <meta http-equiv="expires" content="0">
                    </head>
                    <body class="drewberry-preload">

                        <!-- Google Tag Manager -->
                            <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
                            new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
                            j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
                            'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
                            })(window,document,'script','dataLayer','GTM-TKPXWB');</script>
                        <!-- End Google Tag Manager -->

                        <div id="root">${markup}</div>
                        <script>
                            window.__PRELOADED_STATE__ = ${serialize(initialState)}
                        </script>
                        ${
                            IS_PRODUCTION
                                ? `<script src="${assets.client.js}"></script>`
                                : `<script src="${assets.client.js}" crossorigin></script>`
                        }
                          ${chunks
                              .map(chunk =>
                                  IS_PRODUCTION
                                      ? `<script src="/${chunk.file}"></script>`
                                      : `<script src="http://${process.env.HOST}:${parseInt(process.env.PORT, 10) + 1}/${
                                            chunk.file
                                        }"></script>`
                              )
                              .join('\n')}
                          <script>window.main();</script>
                    </body>
                </html>`
                );
            }
        }, req.path);
    });

export default server;

Je peux confirmer que dès la sortie de la boîte, Razzle n'en souffre pas, il vient de charger une installation propre et d'utiliser phantomjs aucun des avertissements ne s'est affiché, ce qui signifie que c'est probablement quelque chose qu'une bibliothèque que nous avons installée.

Voyez-vous quelque chose d'évident dans ce qui précède ?

Cela ressemble à une chasse à l'oie sauvage en ce moment ! :-)

Donc ma suggestion (et nous avons peut-être besoin d'un guide de dépannage dans la documentation à ce sujet) est de commenter autant que possible de server.js , client.js , App.js , et potentiellement certains aspects de votre webpack remplacent (le cas échéant) pour ramener votre application Razzle à un état semblable à "hello world". Je suggérerais également de copier le modèle HTML de Razzle dans votre fichier server.js juste pour être sûr que tous les scripts sont chargés correctement dès la sortie de la boîte. Une fois qu'il est en cours d'exécution, ouvrez les outils de développement Chrome et accédez à l'onglet "Performances", cochez la case "Captures d'écran", puis appuyez sur l'icône Actualiser. Voir le GIF ci-dessous.

kapture 2019-02-05 at 8 33 42

L'objectif est de s'assurer qu'il n'y a pas de cadre blanc vierge dans la zone de chronologie. Après avoir obtenu un rendu correct sans flashs, vous devriez rajouter de plus en plus de votre ancien code. Faites des pas de bébé. C'est assez facile à gâcher si vous ne faites pas attention.

En ce qui concerne votre cas spécifique, je commencerais par supprimer tous ces éléments du gestionnaire de balises google, tous vos CSS, ainsi que le fractionnement de code que vous effectuez. Faites simplement le rendu et travaillez à l'envers. Ensuite, faites fonctionner Redux. Ajoutez ensuite le casque de réaction, puis, une fois que vous pensez avoir bien compris, vérifiez également en effectuant un test Lighthouse (onglet Audits). Validez cet état dans une nouvelle branche afin de pouvoir y revenir ultérieurement. Ensuite, ajoutez à nouveau vos scripts d'analyse et vérifiez à nouveau le rendu. Enfin, essayez de rajouter le fractionnement de code.

Remarque : Si vous conservez votre css et effectuez l'analyse ci-dessus avec Razzle en mode développement, vous pouvez obtenir un FOUC car Razzle ne traite pas les styles .css sur le serveur pendant le développement (uniquement sur le client). Ainsi, pour tester pleinement que vous faites un SSR approprié avec une hydratation de style si vous utilisez des fichiers .css , vous devez créer Razzle pour la production et exécuter le serveur de production localement. Cependant, si vous vérifiez simplement la présence de votre code HTML depuis le serveur, vous pouvez l'exécuter en mode développement.

Ok, merci pour le travail formidable avec Razzle, et maintenant pour ça. Je vais l'auditer gentiment et faire rapport.

Bien sûr, la première chose à vérifier sur toute page de référencement "vide" (pas vide, c'est une erreur) est : votre page dépend-elle de componentDidMount pour charger les données à afficher. Vous pouvez utiliser curl pour vérifier rapidement. Si oui, vous avez besoin de quelque chose comme After.js à précharger.

pourriez-vous nous conseiller sur la façon de déboguer à l'aide de l'onglet Performances, s'il y a une page blanche autour de la barre des 1000 ms ? Je sais que mon problème concerne une bibliothèque de polices d'icônes qui ne se charge pas sur le serveur et qu'elle affiche donc ces carrés vides au chargement initial...

screen shot 2019-02-11 at 9 57 30 am

Ah, toutes mes polices personnalisées ne sont chargées que bien plus tard. Je charge mes polices via CSS' @font-face {}.

@font-face {
  font-family: 'SFProText';
  font-display: auto;
  src: url('fonts/SFPro/SF-Pro-Display-Regular.otf') format('truetype');
  font-weight: normal;
  font-style: normal;
}

@jaredpalmer J'ai aussi le même problème. Les polices et les actifs ne sont pas chargés dans ma page client.

Je n'ai ajouté aucun fichier webpack.config dans la configuration de mon application, que j'ai cloné à partir de votre référentiel. Je viens de prendre la copie de votre référentiel et d'installer les modules npm, puis j'ai commencé à utiliser l'application en exécutant une commande de démarrage npm.
quelque chose que j'ai manqué de configurer ou dois-je utiliser mon nouveau fichier webpack pour résoudre ce problème ?

Merci de m'aider à résoudre ce problème.

Mon fichier App.css ressemble à ceci.
@font-face {
font-family : 'Roboto-medium' ;
src : url("./static/fonts/Roboto-Medium-webfont.eot");
src : url("./static/fonts/Roboto-Medium-webfont.eot?#iefix") format("embedded-opentype"), url("./static/fonts/Roboto-Medium-webfont.woff") format("woff"), url("./static/fonts/Roboto-Medium-webfont.ttf") format("truetype"); }

@font-face {
font-family : 'Roboto-regular' ;
src : url("./static/fonts/roboto-regular-webfont.eot");
src : url("./static/fonts/roboto-regular-webfont.eot?#iefix") format("embedded-opentype"), url("./static/fonts/roboto-regular-webfont.woff") format("woff"), url("./static/fonts/roboto-regular-webfont.ttf") format("truetype"); }

merci d'avance :)

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

sebmor picture sebmor  ·  4Commentaires

krazyjakee picture krazyjakee  ·  3Commentaires

ewolfe picture ewolfe  ·  4Commentaires

Jayphen picture Jayphen  ·  4Commentaires

kkarkos picture kkarkos  ·  3Commentaires