• 【webpack系列】从零搭建 webpack4+react 脚手架(五)


    本章节,我们一起来探讨以下问题:如何对编译后的文件进行gzip压缩,如何让开发环境的控制台输出更加高逼格,如何更好的对编译后的文件进行bundle分析等。

    1 gzip压缩

    如果你想节省带宽提高网站速度,压缩是一种简单有效的方法。我们模拟一次html的请求,想象一下浏览器和服务器的对话:

    1. 浏览器:嘿,给我来一个 index.html文件
    2. 服务器:好的,让我去找找它是不是在~
    3. 服务器:找到它了,我会返回一个成功的状态码(200 ok),我正在发送文件……
    4. 浏览器:100kb? 我滴天……等啊……等啊,好的,下载下来了

    那现在问题在哪呢?

    好吧,这系统是正常的,但是太低效了,坦白讲100kb是一大段的文字,HTML是冗余的,每一个标签都有一个几乎相同的闭合标签。虽然通篇文字都有重复,但是只要你砍掉任何的内容,html都不会正常显示。

    当文件太大的时候有什么好办法呢,就是gzip压缩它。

    如果我们传输一个替代原始大文件的zip的压缩文件给浏览器,就会节省带宽和下载时间。当浏览器可以下载zip文件,解压,并且渲染给用户。下载很快,页面加载也很快。现在,这个浏览器–服务器的会话大概是这样的:

    1. 浏览器:嘿,给我来一个index.html,如果要有,给我来一个压缩版的可以吗
    2. 服务器:容我找找……好,满足你
    3. 服务器:yep,找到了,马上传给你。
    4. 浏览器:太棒了,只有10kb,我来解压,并且渲染给用户。

    情况很简单:文件越小,下载更快,用户感受更好。下面我们讲讲通过webpack如何对文件进行gzip压缩。

    (1)前期准备

    开启gzip压缩,需要在webpack配置文件中添加一个plugin,而我们希望把是否开启gzip压缩做成可配置化,也就是说,这个gzip的plugin可以选择添加也可以不添加。
    我们在config.js中的build下添加一个配置项,取名为productionGzip

    productionGzip:true,

    另外,我们还需要修改下webpack.prod.conf.js。首先我们把原来export出来的配置对象放一个变量webpackConfig中,这样,我们可以后续访问的到plugins数组,并且可以追加plugin。稍微修改webpack.prod.conf.js,就像这样:

        const webpackConfig=merge(baseWebpackConfig, {
            mode: 'production',
            output: {
                path: config.build.assetsRoot,
                filename: utils.assetsPath('js/[name].[chunkhash:16].js'),
                chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
            },
            module: {
                rules: utils.styleLoaders({
                    sourceMap: config.build.productionSourceMap,
                    extract: true,
                    usePostCSS: true,
                    cssModule:config.base.cssModule,
                    cssModuleExcludePath:config.base.cssModuleExcludePath
                  })
            },
            plugins: [
                new HtmlWebpackPlugin({
                    template: config.build.index,
                    inject: 'body',
                    minify: {
                        removeComments: true,
                        collapseWhitespace: true,
                        removeAttributeQuotes: true
                    },
                }),
                new CleanWebpackPlugin([config.build.assetsRoot], { allowExternal: true }),
    
                //导出css 
                new MiniCssExtractPlugin({
                    filename: utils.assetsPath('css/[name].[hash].css'),
                    chunkFilename: utils.assetsPath('css/[id].[hash].css'),
                }),
            ],
            optimization: {
                minimizer: [
                    new UglifyJSPlugin(),
                    new OptimizeCSSAssetsPlugin({
                        cssProcessorOptions: true
                            ? {
                                map: { inline: false }
                            }
                            : {}
                    })
                ],
                splitChunks: {
                    chunks: "all",
                    minChunks: 1,
                    cacheGroups: {
                        framework: {
                            priority: 200,
                            test: "framework",
                            name: "framework",
                            enforce: true,
                            reuseExistingChunk: true
                        },
                        vendor: {
                            priority: 10,
                            test: /node_modules/,
                            name: "vendor",
                            enforce: true,
                            reuseExistingChunk: true
                        }
                    }
                }
            }
        });
    
        if (config.build.productionGzip) {
            //添加gzip压缩插件
        }
    
        module.exports = webpackConfig;
    (2)添加gzip压缩插件

    安装gzip插件:compression-webpack-plugin

    npm i compression-webpack-plugin --save-dev
    (3)使用插件

    使用只要把CompressionWebpackPlugin的实例对象追加到plugins内即可。支持传入一个配置对象,相关说明:

    1. filename 压缩后的文件名
    2. algorithm 算法 默认gzip
    3. test 针对文件的正则表达式规则,符合规则的文件被压缩
    4. threshold 文件大于这个值的会被压缩
    5. minRatio 压缩率 默认0.8

    要配置test,我们在config.js的build属性下新增加一个配置项,取名productionGzipExtensions,是一个数组,定义了那些后缀的文件要被压缩。

    productionGzipExtensions: ['js', 'css'],

    然后这样通过正则表达式:

        new RegExp('\.(' +
            config.build.productionGzipExtensions.join('|') +
        ')$')

    配置的后缀会符合规则被gzip压缩。
    在webpack.prod.conf.js详细的配置如下:

        if (config.build.productionGzip) {
            const CompressionWebpackPlugin = require('compression-webpack-plugin')
    
            webpackConfig.plugins.push(
              new CompressionWebpackPlugin({
                filename: '[path].gz[query]',
                algorithm: 'gzip',
                test: new RegExp(
                  '\.(' +
                  config.build.productionGzipExtensions.join('|') +
                  ')$'
                ),
                threshold: 10240,
                minRatio: 0.8
              })
            )
          }

    执行命令查看:

    npm run build

    查看编译后生成的js,多了.gz文件,这个就是gzip压缩后的文件,把它们上传到服务器,并且服务器开启gzip的功能即可。

    bundle分析工具
     
    编译后,我们不能直观地知道那些组件被编译到哪些文件中。通过bundle分析工具,可以直观地看清楚这个问题。好处是帮助我们更好地优化代码和改进编译。
    (1) 安装webpack-bundle-analyzer
    npm install --save-dev webpack-bundle-analyzer
    (2)配置是否启用的参数

    在config.js文件的build属性下增加配置项bundleAnalyzerReport,用来表示是否开启分析。这个变量会不停修改,所以我们希望会在npm命令后面加上--report 就表示最后启动bundle分析,不加就不会启动bundle分析。怎么做?通过process.env.npm_config_report可以获取到npm命令的配置

    bundleAnalyzerReport: process.env.npm_config_report
    (3)使用

    在webpack.prod.conf.js增加如下代码:

        if (config.build.bundleAnalyzerReport) {
          const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
          webpackConfig.plugins.push(new BundleAnalyzerPlugin())
        }
    (4)执行命令

    分别以下2个执行试试看吧

    npm run build
    npm run build --report

    通过增加--report 编译成功后会启动Webpack Bundle Analyzer。默认是http://127.0.0.1:8888。你可以直观看到每个文件有哪些模块被编译进去。

    美化终端的提示
     
    在编译过程中,我们希望在终端能给出提示,编译成功给出我们自定义的一些说明。
    (1)ora和chalk

    这里需要介绍2个npm库。ora是一个能让你在终端提示状态的库,chalk是方便我们美化输出的文本。
    我们先安装这2个库。

    npm i --save-dev ora chalk
    (2)修改编译的方法

    看看我们原先的build方法,打开package.json,在scripts属性下找到build属性,可以看到它的值是
    webpack --config build/webpack.prod.conf.js
    通过webpack命令在终端去编译,我们无法获取webpack的编译状态,webpack还提供了webpack方法,通过webpack方法编译,编译结束可以执行回调函数。我们需要美化终端的显示,希望在编译中能显示编译的状态,编译结束提示编译成功,很有必要修改成通过webpack方法来编译。
    在build目录下新增加一个build.js文件:内容如下:

        const ora = require('ora');
        const chalk = require('chalk')
        const webpack = require('webpack')
        const webpackConfig = require('./webpack.prod.conf');
        const spinner = ora('编译中...
    ').start();
        webpack(webpackConfig, function (err, stats) {
            if (err) {
                spinner.fail("编译失败");
                console.log(err);
                return;
            }
            spinner.succeed('编译已结束. 
    ');
    
            process.stdout.write(stats.toString({
                colors: true,
                modules: false,
                children: false,
                chunks: false,
                chunkModules: false
            }) + '
    
    ');
            console.log(chalk.cyan('  编译成功!
    '))
            console.log(chalk.yellow(
                '  提示: 编译后的文件可以上传并且部署到服务器
    ' +
                '  通过file:// 打开index.html不会起作用.
    '
            ))
        })

    stats是编译结束后webpack回调回来的参数,包含了编译后的文件信息。
    修改package.json的build属性:

    "build": "node build/build.js",

    最后重新执行编译命令看看吧

    npm run build

    观察终端的输出,是不是漂亮了很多。当然你可以自己定制输出的内容。

  • 相关阅读:
    一文总结十大经典排序算法(思维导图 + 动图演示 + 代码实现 C/C++/Python + 致命吐槽)
    VulnHub——Kioptrix Level 2
    史上最全Redis面试题(2020最新版)
    js 根据秒数获取多少小时,多少分钟,多少秒
    RabbitMQ的死信队列
    女朋友也能看懂的多线程同步
    RabbitMQ的备份交换器
    BI Publisher(rtf)模板开发语法大全
    修改CUSTOM.PLL文件调用客户化FORM&修改标准FORM
    EBS客户化迁移SQL
  • 原文地址:https://www.cnblogs.com/nianzhilian/p/10229344.html
Copyright © 2020-2023  润新知