Razzle: ¿Cómo soluciono problemas de renderización del servidor?

Creado en 5 feb. 2019  ·  9Comentarios  ·  Fuente: jaredpalmer/razzle

Hola,

Hemos notado un problema en el que si inicia sesión en la consola de búsqueda de Google y busca como Google, el sitio web se representa como una página en blanco.

He hecho algunas investigaciones y algunas de ellas me han llevado a este artículo:

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

Es muy probable que el motor de búsqueda y la búsqueda como Google no se comporten de la misma manera, o de lo contrario ya habríamos perdido rankings, sin embargo, me gustaría resolver este problema, ya que mantendría despierto a cualquier propietario de un sitio web.

He descargado phantomjs, con la suposición de que es lo mismo que buscar como Google, y tratar de renderizarlo arroja una serie de errores:

image

Este problema puede ser tan simple de resolver como cambiar los navegadores de destino que se están compilando, sin embargo, simplemente instalar babel / polyfil e importar no funciona.

¿Alguien podría indicarme la dirección correcta aquí?

stale

Comentario más útil

Entonces, mi sugerencia (y tal vez necesitemos una guía de solución de problemas en los documentos sobre esto) es comentar tanto como pueda desde server.js , client.js , App.js , y potencialmente aspectos de su paquete web anula (si tiene alguno) para que su aplicación Razzle vuelva a un estado similar al de "hola mundo". También sugeriría copiar la plantilla HTML de Razzle nuevamente en su archivo server.js solo para asegurarse de que todos los scripts se carguen correctamente desde el primer momento. Una vez que se esté ejecutando, abre las herramientas de desarrollo de Chrome y ve a la pestaña "Rendimiento", marca la casilla de verificación "Capturas de pantalla" y luego presiona el ícono Actualizar. Vea el GIF a continuación.

kapture 2019-02-05 at 8 33 42

El objetivo es asegurarse de que no haya ningún marco blanco en blanco en el área de la línea de tiempo. Después de obtener un renderizado adecuado sin flashes, debe volver a agregar más y más de su código anterior. Da pasos de bebé. Esto es bastante fácil de estropear si no tienes cuidado.

En cuanto a su caso específico, comenzaría por eliminar todas esas cosas del administrador de etiquetas de Google, todo su CSS, así como cualquier división de código que esté haciendo. Solo haz que se renderice y trabaje al revés. A continuación, haga que Redux funcione. Luego agregue react-helmet, y luego, una vez que crea que lo hizo bien, verifique nuevamente haciendo una prueba de Lighthouse también (pestaña Auditorías). Confirme este estado en una nueva rama para que pueda volver a él en el futuro. A continuación, vuelva a agregar sus scripts de análisis y verifique el renderizado nuevamente. Finalmente, intente volver a agregar la división de código.

Nota: Si mantiene su CSS y realiza el análisis anterior con Razzle en modo de desarrollo, puede obtener un FOUC porque Razzle no procesa estilos .css en el servidor durante el desarrollo (solo en el cliente). Por lo tanto, para probar completamente que está haciendo un SSR adecuado con hidratación de estilo si está usando archivos .css , debe compilar Razzle para producción y ejecutar el servidor de producción localmente. Sin embargo, si simplemente está comprobando la presencia de su HTML desde el servidor, puede ejecutarlo en modo de desarrollo.

Todos 9 comentarios

Si su página se está quedando en blanco, entonces ha roto su SSR o esquema de hidratación. Razzle no sufre de lo que ha descrito de fábrica, de hecho, se usa en sitios enfocados en SEO como BBC.com. ¿Puedes pegar tu archivo server.js? ¿Está recuperando sus datos en el servidor?

Hola jared

Gracias por la pronta respuesta, sí, obtenemos datos de un servidor.

Aquí está mi 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;

Puedo confirmar que Razzle no lo sufre, simplemente cargó una instalación limpia y usando phantomjs no apareció ninguna de las advertencias, lo que significa que probablemente sea algo de alguna biblioteca que instalamos.

¿Ves algo obvio en lo anterior?

¡Se siente como una búsqueda inútil en este momento! :-)

Entonces, mi sugerencia (y tal vez necesitemos una guía de solución de problemas en los documentos sobre esto) es comentar tanto como pueda desde server.js , client.js , App.js , y potencialmente aspectos de su paquete web anula (si tiene alguno) para que su aplicación Razzle vuelva a un estado similar al de "hola mundo". También sugeriría copiar la plantilla HTML de Razzle nuevamente en su archivo server.js solo para asegurarse de que todos los scripts se carguen correctamente desde el primer momento. Una vez que se esté ejecutando, abre las herramientas de desarrollo de Chrome y ve a la pestaña "Rendimiento", marca la casilla de verificación "Capturas de pantalla" y luego presiona el ícono Actualizar. Vea el GIF a continuación.

kapture 2019-02-05 at 8 33 42

El objetivo es asegurarse de que no haya ningún marco blanco en blanco en el área de la línea de tiempo. Después de obtener un renderizado adecuado sin flashes, debe volver a agregar más y más de su código anterior. Da pasos de bebé. Esto es bastante fácil de estropear si no tienes cuidado.

En cuanto a su caso específico, comenzaría por eliminar todas esas cosas del administrador de etiquetas de Google, todo su CSS, así como cualquier división de código que esté haciendo. Solo haz que se renderice y trabaje al revés. A continuación, haga que Redux funcione. Luego agregue react-helmet, y luego, una vez que crea que lo hizo bien, verifique nuevamente haciendo una prueba de Lighthouse también (pestaña Auditorías). Confirme este estado en una nueva rama para que pueda volver a él en el futuro. A continuación, vuelva a agregar sus scripts de análisis y verifique el renderizado nuevamente. Finalmente, intente volver a agregar la división de código.

Nota: Si mantiene su CSS y realiza el análisis anterior con Razzle en modo de desarrollo, puede obtener un FOUC porque Razzle no procesa estilos .css en el servidor durante el desarrollo (solo en el cliente). Por lo tanto, para probar completamente que está haciendo un SSR adecuado con hidratación de estilo si está usando archivos .css , debe compilar Razzle para producción y ejecutar el servidor de producción localmente. Sin embargo, si simplemente está comprobando la presencia de su HTML desde el servidor, puede ejecutarlo en modo de desarrollo.

Bien, gracias por el increíble trabajo con Razzle, y ahora por esto. Voy a auditarlo muy bien e informar.

Por supuesto, lo primero que debe verificar en cualquier página seo "vacía" (no en blanco, eso es un error) es: ¿su página depende de componentDidMount para cargar los datos que se mostrarán? Puede usar curl para verificar rápidamente. Si es así, necesita algo como After.js para precargar.

¿Podría aconsejarme cómo depurar usando la pestaña Rendimiento, si hay una página en blanco alrededor de la marca de 1000 ms? Sé que mi problema es que una biblioteca de fuentes de iconos no se carga en el servidor y, por lo tanto, muestra estos cuadrados vacíos en blanco en la carga inicial ...

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

Ah, todas mis fuentes personalizadas no se cargan hasta mucho más tarde. Estoy cargando mis fuentes a través de 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 Yo también tengo el mismo problema. Las fuentes y los recursos no se cargan en la página de mi cliente.

No he agregado ningún archivo webpack.config en la configuración de mi aplicación, que cloné desde su repositorio. Acabo de tomar la copia de su repositorio e instalé módulos npm, luego comencé a usar la aplicación ejecutando un comando de inicio npm.
¿Hay algo que me haya perdido para configurar o debo usar mi nuevo archivo de paquete web para resolver este problema?

Por favor, ayúdame a resolver este problema.

Mi archivo App.css se ve así ...
@Perfil delantero {
familia de fuentes: 'Roboto-medium';
src: url ("./ static / fonts / Roboto-Medium-webfont.eot");
src: url ("./ static / fonts / Roboto-Medium-webfont.eot? #iefix") formato ("embedded-opentype"), url ("./ static / fonts / Roboto-Medium-webfont.woff") formato ("woff"), url ("./ static / fonts / Roboto-Medium-webfont.ttf") formato ("truetype"); }

@Perfil delantero {
familia de fuentes: 'Roboto-regular';
src: url ("./ static / fonts / roboto-regular-webfont.eot");
src: url ("./ static / fonts / roboto-regular-webfont.eot? #iefix") formato ("embedded-opentype"), url ("./ static / fonts / roboto-regular-webfont.woff") formato ("woff"), url ("./ static / fonts / roboto-regular-webfont.ttf") formato ("truetype"); }

gracias inadvane :)

¿Fue útil esta página
0 / 5 - 0 calificaciones