3

我正在使用 Cloudfront 和 S3 部署 React 应用程序,我想启用 brotli 进行压缩。我看过一些使用 lambda@edge 解决这个问题的教程。我的 Cloudfront 发行版的行为配置如下

在此处输入图像描述

我还将“自动压缩对象”选项设置为“否”。我分别为源请求和查看器请求关联了以下两个 lambda 函数:

  • 来源请求:

'use strict';

/**
 * Funciton registered on 'Origin Request' CloudFront Event
 */
exports.handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;
  console.log(JSON.stringify(request));
  const headers = request.headers;
  const isBr = headers['x-compression'] && headers['x-compression'][0].value === "br";
  const isGzip =  headers['x-compression'] && headers['x-compression'][0].value === "gzip";

  /**
  * Update request path based on custom header
  */  
  let extension = "";
  if(isBr)
    extension = ".br";
  else if(isGzip)
    extension = ".gzip";
  request.uri =  request.uri + extension;
  callback(null, request);
};

  • 观众要求:

'use strict';

/**
 * Funciton registered on 'Viewer Request' CloudFront Event
 */
exports.handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;
  const headers = request.headers;
  
  console.log(JSON.stringify(request));

  /**
   * Detect if brotli is supported by the browser.
   * Pass a custom header x-compression to be captured by the lambda in the origin-request phase.
   */
  if(headers['accept-encoding'] && headers['accept-encoding'][0].value.indexOf('br') > -1) {
    headers['x-compression'] = [{
      key: 'X-Compression',
      value: 'br'
    }];
  }
  else if(headers['accept-encoding'] && headers['accept-encoding'][0].value.indexOf('gzip') > -1){
    headers['x-compression'] = [{
      key: 'X-Compression',
      value: 'gzip'
    }];
  }
  callback(null, request);
};

当我尝试在浏览器中使用 Cloudfront 的域名打开应用程序时,会抛出 Uncaught SyntaxError:bundle.js:1 中的非法字符。但是,当我使用 S3 的端点打开应用程序时,它运行良好。以下是我的webpack.config.js

const path = require('path');
const autoprefixer = require('autoprefixer');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');

module.exports = {
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
        chunkFilename: '[id].js',
        publicPath: ''
    },
    resolve: {
        extensions: ['.js', '.jsx']
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                exclude: /node_modules/,
                use: [
                    { loader: 'style-loader' },
                    { 
                        loader: 'css-loader',
                        options: {
                            modules: {
                                localIdentName: "[name]__[local]___[hash:base64:5]",
                            },                                                      
                            sourceMap: true
                        }
                     },
                     { 
                         loader: 'postcss-loader',
                         options: {
                             ident: 'postcss',
                             plugins: () => [
                                 autoprefixer({})
                             ]
                         }
                      }
                ]
            },
            {
                test: /\.(png|jpe?g|gif)$/,
                loader: 'url-loader?limit=10000&name=img/[name].[ext]'
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: __dirname + '/src/index.html',
            filename: 'index.html',
            inject: 'body'
        }),
        new CompressionPlugin({
            filename: '[path].gz',
            threshold: 0,
            minRatio: 2,
            test: /\.(js|css)$/i
          }),
          new CompressionPlugin({
            filename: '[path].br',
            algorithm: 'brotliCompress',
            threshold: 0,
            minRatio: 2,
            test: /\.(js|css)$/i,
            compressionOptions: {level: 11}
          })
    ]
};

我已将代码放在此 GitHub 存储库中(我还上传了 dist/ 目录,这是我上传到 S3 以进行部署的目录)。我是这项技术的新手,所以我没有想法。我还尝试将 .html 和 .png 扩展名添加到 Webpack 配置文件中的插件构造函数,但这也不起作用。任何帮助将不胜感激,在此先感谢

4

1 回答 1

3

CloudFront 现在支持 Brotli 边缘压缩。您可以将 Compress Objects Automatically 设置为“Yes”并取消 Lambda@Edge 函数。CloudFront 将从 S3 获取您的未压缩文件,并可以在边缘为您将可缓存的请求压缩到 Brotli 或 Gzip。

有关特定配置文档,请参见此处: https ://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/ServingCompressedFiles.html

于 2020-09-15T21:11:50.873 回答