Brotli в приложении React с использованием рендеринга на стороне сервера (SSR) - PullRequest
0 голосов
/ 17 февраля 2019

Я сейчас подключаю приложение с SSR в ответ.Однако у меня проблемы с сервером, НЕ возвращающим ответы в формате сжатого файла Brotli.Я вижу, что мои br-файлы генерируются webpack в моем конфигурационном файле webpack клиента.Но мой сервер не принимает возврат файлов br обратно моему клиенту.К вашему сведению .... У меня также есть мой веб-пакет для клиента, который также генерирует gz-файлы.Файлы, которые я пытаюсь вернуть обратно в режиме br, - это файл client_bundle.js и app.css.

. Как вы увидите в моем файле server.js, я отправляю ответ в формате строки HTML.Я попытался изменить теги ссылок и сценариев, чтобы они возвращали app.css.br и client_bundle.js.br, но безрезультатно.

Знаете ли вы, что я могу делать неправильно, и почему мой сервер не возвращается и/ или клиент не получит файлы br для CSS и JS?

FYI .... Я использую nodejs, express-static-zip в моем файле server.js.Кроме того, я используюression-webpack-plugin и brotli-webpack-plugin для генерации файлов br и gz для app.css и client_bundle.js.Еще одно замечание: я встраиваю свои клиентские файлы в build / public, а мои серверные файлы в build.

Спасибо за любую помощь.

webpack.client.js

const path = require("path");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const webpack = require("webpack");
const autoprefixer = require("autoprefixer");
const CompressionPlugin = require("compression-webpack-plugin");
const BrotliPlugin = require("brotli-webpack-plugin");

module.exports = {
    mode:"development",
  optimization: {
    usedExports: true
  },
  entry: "./src/client/client.js",
  output: {
    filename: "client_bundle.js",
    path: path.resolve(__dirname, "build/public/"),
    publicPath: "/build/public/"
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: "babel-loader",
        exclude: "/node_modules"
      },
      {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: ["css-loader", "postcss-loader", "sass-loader"]
        })
      },
      {
        test: /\.(jpe?g|png|gif|svg)$/i,
        use: [
          {
            loader: "file-loader",
            options: {
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin({
        filename: "app.css"
    }),
      new CompressionPlugin({
          filename: '[path].gz[query]'
      }),
      new BrotliPlugin({
          asset: '[path].br[query]',
          test: /\.(js|css|html|svg)$/,
          threshold: 10240,
          minRatio: 0.8
      })
  ]
};

Server.js

import express from "express";
import cors from "cors";
import React from "react";
import { renderToString } from "react-dom/server";
import { Provider } from "react-redux";
import { StaticRouter, matchPath } from "react-router-dom";
import serialize from "serialize-javascript";
import routes from "../shared/routes";
import configureStore from "../shared/configureStore";
import App from "../shared/app";
import "source-map-support/register";
import http from "http";
import reload from "reload";
import expressStaticGzip from "express-static-gzip";

const app = express();
const PORT = process.env.PORT || 3000;

app.use(cors());
app.use("/build/public", expressStaticGzip('/build/public', {
    enableBrotli: true,
    orderPreference: ['br', 'gz'],
    setHeaders: function (res, path) {
        res.setHeader("Cache-Control", "public, max-age=31536000");
    }
}));
app.use(express.static("build/public"));

var server = http.createServer(app);
reload(app);
      acc.push(Promise.resolve(store.dispatch(route.component.initialData())));
    }
    return acc;
  }, []);
   const currentRoute = routes.find(route => matchPath(req.url, route));
   const requestInitialData =
   currentRoute.component.initialData && currentRoute.component.initialData();
  Promise.all(promises)
    .then(() => {
      const context = {};
      const markup = renderToString(
        <Provider store={store}>
          <StaticRouter location={req.url} context={context}>
            <App />
          </StaticRouter>
        </Provider>
      );

      const initialData = store.getState();
      res.send(`
        <!DOCTYPE html>
        <html>
          <head>
            <basehref="/">
            <title>Sample</title>
            <link rel="stylesheet" href="app.css.br">
          </head>

          <body>
            <div id="root">${markup}</div>
             <script src="client_bundle.js.br"></script>
             <script src="/reload/reload.js"></script>
            <script>window.__initialData__ = ${serialize(initialData)}</script>
          </body>
        </html>
      `);
    })
    .catch(next);
});

app.listen(PORT, () => {
  console.log("App running,", PORT);
});

1 Ответ

0 голосов
/ 21 февраля 2019

Вы сжимаете клиентские файлы как в Br, так и в Gzip, что выглядит корректно, поскольку ваше приложение обслуживает их с build/public.

Но выполняется рендеринг на стороне сервера, где его ответом является HTML-страница., не сжимается ни с Бротли, ни с Гзипом.Таким образом, браузер попадает на ваш сервер, он отвечает несжатым HTML-ответом, а затем загружает сжатые файлы Brotli, прежде чем React выполнит гидратацию.

...