11

据说compression-webpack-plugin应该这样做。

我用 npm 安装了插件

npm install compression-webpack-plugin --save-dev

并编辑了我的 webpack.config.js 文件以包含

const CompressionPlugin = require('compression-webpack-plugin');

...
  plugins: [
    new CompressionPlugin({
      filename: "[path].gz[query]",
      algorithm: "gzip",
      test: /\.(js|css)$/i,
    }),
...

当我使用页面洞察检查网页加载速度时,我的 gz 文件似乎无法识别,或者至少其中一个无法识别

在此处输入图像描述

这是我的主目录

在此处输入图像描述


这个问题与我的问题非常相似。我试图避免使用 .htaccess,因为我在某处听说它不是最好与 react 和 webpack 一起使用。也许这是错误的?

我尝试使用 kushalvm 的解决方案,但它不适合我。

4

3 回答 3

15

简短的回答:kushalvm 的解决方案并不完整。为了用 gzip/brotli 压缩页面大小,有两个步骤:

  1. 在构建时创建.gz/.br文件(或由服务器动态生成)
  2. 为他们服务(而不是.js文件)

你正在做第一部分,而不是第二部分。因为当您构建一个反应项目时(在客户端渲染的情况下 - CSR),您只需创建一个.html导入一些脚本标签的文件(您的反应项目)。如果你为 webpack 使用brotli压缩插件,你已经创建了一些.gz/.br文件,但 HTML 文件仍然会导入旧.js脚本。

那么您可以使用哪些不同的方法来提供配置服务器所需的压缩文件(您不能仅通过更改 React 配置来做到这一点

解决方案

1)如果你使用客户端渲染,你可以创建一个自定义的 express server 来提供文件,它非常简单,不到 10 行代码,你可以阅读官方 React Docs 中的文档(带有express-static-gzip) 所以你的服务器文件将如下所示:

const express = require('express');
const path = require('path');
const app = express();

app.use(
  expressStaticGzip(path.join(__dirname, 'build'), {
  enableBrotli: true, // only if you have brotli files too
  }),
);

app.use(express.static(path.join(__dirname, 'build')));

app.get('/', function(req, res) {
  res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

app.listen(9000);

该服务器将读取构建目录中的文件,如果对某些 js 资产的请求到达,它会检查(浏览器是否支持压缩,以及是否存在压缩文件)然后提供压缩文件

2)如果您使用 SSR(例如Next.jsReact-Starter-kit),您可以创建自定义快递服务器,并使用上述相同的方法。

3) 如果您使用 Apache 网络服务器,您可以使用 Apache gzip/brotli 压缩配置文件,如下所示:

# enable the rewrite capabilities
RewriteEngine On

# prevents the rule from being overrided by .htaccess files in subdirectories
RewriteOptions InheritDownBefore

# provide a URL-path base (not a file-path base) for any relative paths in the rule's target
RewriteBase /

# GZIP
## allows you to have certain browsers uncompress information on the fly
AddEncoding gzip .gz
## serve gzip .css files if they exist and the client accepts gzip
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.css $1\.css\.gz [QSA]
## serve gzip .js files if they exist and the client accepts gzip
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.js $1\.js\.gz [QSA]
## serve gzip .html files if they exist and the client accepts gzip
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.html $1\.html\.gz [QSA]
## serve correct content types, and prevent mod_deflate double gzip
RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1,E=is_gzip:1]
RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1,E=is_gzip:1]
RewriteRule \.html\.gz$ - [T=text/html,E=no-gzip:1,E=is_gzip:1]
Header set Content-Encoding "gzip" env=is_gzip

4) 如果您使用第三方 JamStack/CDN 提供商,如 Netlify 或 AWS,他们有一些配置供您启用动态 gzip。

于 2019-08-29T10:36:10.707 回答
2

您还可以构建时间 gzip。这是过程。

  1. 安装 Webpack 压缩插件

    npm install compression-webpack-plugin --save-dev

  2. 安装并导入插件 var CompressionPlugin = require('compression-webpack-plugin');

  3. 将其添加到插件数组

  plugins: [
    new webpack.DefinePlugin({ 
      'process.env': {
        'NODE_ENV': JSON.stringify('production')
      }
    }),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin(),
    new webpack.optimize.AggressiveMergingPlugin(),
    new CompressionPlugin({   <-- Add this
      asset: "[path].gz[query]",
      algorithm: "gzip",
      test: /\.js$|\.css$|\.html$/,
      threshold: 10240,
      minRatio: 0.8
    })
  ]
  1. 最后,将此中间件添加到 Express 以返回 .js.gz,这样您仍然可以从 html 加载 bundle.js,但会收到 bundle.js.gz
app.get('*.js', function (req, res, next) {
  req.url = req.url + '.gz';
  res.set('Content-Encoding', 'gzip');
  next();
});
于 2020-07-15T17:28:42.133 回答
0

我还在为使用我的 React SSR 应用程序提供压缩版本而苦苦挣扎;在我的情况下,带有 js.br 扩展名>“bundle.js.br”的 brotli 类型。下面的代码片段最终帮助我正确地服务它。我将开发模式下的客户端未压缩包从 1.7 MB 减少到 0.27 MB。试着为你弄清楚。提供文件不需要额外的插件。当然,压缩后的版本必须先用 webpack 生成。对于 webpack brotli 压缩,我将 npmjs 包compression-webpack-plugin 与 zlib 结合使用。

var express = require('express');
var app = express();

app.get('*.js', (req, res, next) => {
  if (req.header('Accept-Encoding').includes('br')) {
    req.url = req.url + '.br';
    console.log(req.header('Accept-Encoding'));
    res.set('Content-Encoding', 'br');
    res.set('Content-Type', 'application/javascript; charset=UTF-8');
  }
  next();
});

app.use(express.static('public'));

现在让我解释一下上面的片段,我用它来为我的 SSR React 应用程序提供压缩文件。

  • 在开头使用参数 '*.js' 意味着这个 app.get 适用于每个被触发以获取 JS 文件的端点。
  • 在回调中,我将 .br 附加到请求的 URL。此外,Content-Encoding 响应标头设置为 br。
  • Content-Type 标头设置为 application/javascript;charset=UTF-8 指定 MIME 类型。
  • 最后,非常重要的是,next() 可以继续执行可能是下一个回调的任何回调。
  • 不要忘记提供放置压缩包的文件夹。在我的案例中,我使用了 app.use(express.static('public')) 。
于 2021-09-05T17:51:12.963 回答