Удалите стили блокировки рендеринга из серверного приложения React - PullRequest
2 голосов
/ 24 сентября 2019

Я провел аудит моего приложения React с помощью инструмента Chrome Lighthouse, и он обнаружил, что в моем приложении есть некоторые блокирующие CSS файлы рендеринга.Я провел дальнейшее исследование, запустив покрытие, и заметил, что мое приложение содержит около 50% неиспользуемого кода (CSS & JS).

Я пробовал различные плагины, такие как: Критический, Пентхаус, критический для веб-пакетов, Веб-пакет-плагин-critical, html-критический-webpack-plugin response-snap, чтобы удалить критические CSS из приложения, но ни один из них не работал в основном потому, что все плагины, которые должны помочь, ожидают, что приложение использует HTMLExtractPlugin.Однако это не относится ко мне, потому что все мое приложение отображается на сервере и обслуживается клиенту.

Вот функция рендеринга на моем сервере:

const serverRenderer = () => (req, res) => {
    const content = renderToString(
        <Provider store={req.store}>
            <App />
        </Provider>
    );

    const state = JSON.stringify(req.store.getState());

    return res.send(
        `<!doctype html>
            ${renderToString(
                <Html
                    css={[res.locals.assetPath('bundle.css'), res.locals.assetPath('vendor.css')]}
                    scripts={[res.locals.assetPath('bundle.js'), res.locals.assetPath('vendor.js')]}
                    state={state}
                >
                    {content}
                </Html>
            )}`
    );
};

export default serverRenderer;

КОМПОНЕНТ HTML

// @flow
/* eslint-disable react/no-danger */
import React from 'react';
import Helmet from 'react-helmet';

export default class HTML extends React.Component {
    static defaultProps = {
        css: [],
        scripts: [],
        state: '{}',
    };

    render() {
        const head = Helmet.renderStatic();
        const { children, scripts, css, state } = this.props;
        return (
            <html lang="">
                <head>
                    <meta charSet="utf-8" />
                    <meta name="viewport" content="width=device-width, initial-scale=1" />
                    {head.base.toComponent()}
                    {head.title.toComponent()}
                    {head.meta.toComponent()}
                    {head.link.toComponent()}
                    {head.script.toComponent()}
                    {css.map((href) => {
                        return <link key={href} href={href} rel="stylesheet" as="style" />;
                    })}
                    <script
                        dangerouslySetInnerHTML={{
                            __html: `window.__PRELOADED_STATE__ = ${state}`,
                        }}
                    />
                </head>
                <body>
                    <div id="app" dangerouslySetInnerHTML={{ __html: children }} />
                    {scripts.map((src) => {
                        return <script key={src} src={src} async />;
                    })}
                </body>
            </html>
        );
    }
}

Конфигурация веб-пакета

const webpack = require('webpack');
const ManifestPlugin = require('webpack-manifest-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const Critters = require('critters-webpack-plugin');
// const HtmlWebpackPlugin = require('html-webpack-plugin');
/* const LoadablePlugin = require('@loadable/webpack-plugin');
const ChunkExtractor = require('@loadable/server');
const statsFile = path.resolve('../../rafikibuild/client/statics/loadable-stats.json'); */

const env = require('../env')();

const shared = [];

const client = [
    // TODO: add client side only mode
    // new HtmlWebpackPlugin({
    //     inject: true,
    //     template: paths.appHtml,
    // }),
    new CaseSensitivePathsPlugin(),
    new webpack.DefinePlugin(env.stringified),
    new webpack.DefinePlugin({
        __SERVER__: 'false',
        __BROWSER__: 'true',
    }),
    new MiniCssExtractPlugin({
        filename:
            process.env.NODE_ENV === 'development' ? '[name].css' : '[name].[contenthash].css',
        chunkFilename:
            process.env.NODE_ENV === 'development' ? '[id].css' : '[id].[contenthash].css',
    }),
    new Critters({
        preload: 'swap',
        preloadFonts: true,
    }),
    new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
    new ManifestPlugin({ fileName: 'manifest.json' }),
    new CompressionPlugin({
        filename: '[path].gz[query]',
        algorithm: 'gzip',
        test: /\.js$|\.css$|\.html$/,
        threshold: 10240,
        minRatio: 0.8,
    }),
];

const server = [
    new webpack.DefinePlugin({
        __SERVER__: 'true',
        __BROWSER__: 'false',
    }),
];

module.exports = {
    shared,
    client,
    server,
};

Существует ли способ удаления стилей блокировки рендеринга на стороне рендеринга приложения React на стороне сервера?

Спасибо.

...