6

我使用 chrome Lighthouse 工具对我的 React 应用程序进行了审核,它检测到我的应用程序有一些渲染阻塞 css 文件。我通过运行覆盖进行了进一步调查,发现我的应用程序有大约 50% 的未使用代码(CSS 和 JS)。

我尝试了各种插件,例如:Critical、Penthouse、webpack-critical、webpack-plugin-critical、html-critical-webpack-plugin react-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>
        );
    }
}

Webpack 配置

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 应用程序上删除渲染阻塞样式?

谢谢你。

4

0 回答 0