javascript - 使用服务器端渲染 (SSR) 的 React 应用程序中的 Brotli

标签 javascript node.js reactjs webpack brotli

我目前正在使用 React 中的 SSR 连接一个应用程序。然而,我 服务器有问题不在 Brotli 中返回响应 压缩文件格式。我确实看到我的 br 文件正在生成 通过我的客户端 webpack 配置文件中的 webpack。但是我的服务器没有 接受将 br 文件返回给我的客户。仅供引用....我也有我的 客户端的 webpack 也会生成 gz 文件。我试图以 br 模式返回的文件是 client_bundle.js 文件和 app.css。

正如您将在我的 server.js 文件中看到的那样,我发回了一个 以 HTML 字符串格式响应。我试过更改我的链接和 脚本标签返回 app.css.br 和 client_bundle.js.br 但无济于事。

你知道我可能做错了什么以及为什么我的服务器不返回吗 和/或客户端不会选择 CSS 和 JS 的 br 文件?

仅供引用....我在我的 server.js 文件中使用 nodejs,express-static-zip。在 另外,我正在使用 compression-webpack-plugin 和 brotli-webpack-plugin 为 app.css 和 client_bundle.js 生成 br 和 gz 文件。其他 旁注,我正在将我的客户端文件构建到 build/public 和我的服务器中 文件构建。

感谢您的帮助。

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
      })
  ]
};

服务器.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);
});

最佳答案

您正在压缩 Br 和 Gzip 中的客户端文件,这看起来是正确的,因为您的应用程序从 build/public 为它们提供服务。

但是服务器端渲染(其响应是 HTML 页面)从外观上看并没有使用 Brotli 或 Gzip 进行压缩。因此,浏览器会访问您的服务器,它会以未压缩的 HTML 响应进行响应,然后在 React 进行水合作用之前下载 Brotli 压缩文件。

关于javascript - 使用服务器端渲染 (SSR) 的 React 应用程序中的 Brotli,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54730009/

相关文章:

javascript - 奇怪的 HTML 行为

javascript - WordJS body.getOoxml bug 添加空段落

node.js - 如何使用文件参数进行 mocha/chai 测试?

node.js - “nodejs web.js”有效, 'foreman start' 无效

javascript - 热衷于在 react native 平面列表上重叠按钮?

javascript - ng-show 基于数组中存在的值

JavaScript [对象][对象] 调试

javascript - 如何正确使用Parse.query.equalTo?

reactjs - 如何使用自定义输入 TextField 在下一个查询之前重置 Material 表查询对象

javascript - 在传单中使用react-leaflet-draw创建新层之前删除层