美文网首页程序猿阵线联盟-汇总各类技术干货webpack让前端飞
webpack 打包优化的四种方法(多进程打包,多进程压缩,资源

webpack 打包优化的四种方法(多进程打包,多进程压缩,资源

作者: HashTang | 来源:发表于2019-11-16 20:36 被阅读0次

    如今,webpack 毫无疑问是前端构建领域里最耀眼的一颗星,无论你前端走哪条路线,都需要有很强的webpack 知识。webpack 的基本用法这里就不展开讲了。主要探讨一下如何提高 webpack 的打包速度。

    这篇文章以 vue cli3.0+webpack4.0+nodejs10.0+ 这几个版本为例。

    一、打包分析

    1.1、速度分析

    我们的目的是优化打包速度,那肯定需要一个速度分析插件,此时 speed-measure-webpack-plugin 就派上用场了。它的作用如下:

    • 分析整个打包总耗时
    • 每个 pluginloader 的耗时情况

    首先,安装插件

    npm i -D speed-measure-webpack-plugin
    

    然后修改 vue.config.js 配置文件 (vuecli3+ 版本的配置文件统一在这个文件里修改,如果没有该文件,在根目录新建一个)

    // 导入速度分析插件
    const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
    
    // 实例化插件
    const smp = new SpeedMeasurePlugin();
    
    module.exports = {
        configureWebpack: smp.wrap({
            plugins: [
                // 这里是自己项目里需要使用到的其他插件
                new yourOtherPlugin()
            ]
        })
    }
    

    运行打包命令之后,可以看到,打包总耗时为 2min,51.99s

    1.2、体积分析

    分析完打包速度之后,接着我们来分析打包之后每个文件以及每个模块对应的体积大小。使用到的插件为 webpack-bundle-analyzer,构建完成后会在 8888 端口展示大小。

    首先,安装插件

    npm i -D webpack-bundle-analyzer
    

    修改 vue.config.js 配置文件

    // 导入速度分析插件
    const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
    
    // 导入体积分析插件
    const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
    
    // 实例化速度分析插件
    const smp = new SpeedMeasurePlugin();
    
    module.exports = {
        configureWebpack: smp.wrap({
            plugins: [
                // 实例化体积分析插件
                new BundleAnalyzerPlugin()
            ]
        })
    }
    

    构建之后可以看到,其中黄色块 chunk-vendors 文件占比最大,为 1.34MB

    二、打包优化

    2.1、多进程多实例构建,资源并行解析

    多进程构建的方案比较知名的有以下三个:

    • thread-loader (推荐使用这个)
    • parallel-webpack
    • HappyPack

    这里以 thread-loader 为例配置多进程多实例构建
    安装 loader

    npm i -D thread-loader
    

    接下来在 vue.config.js 配置文件中使用该 loader

    // 导入速度分析插件
    const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
    
    // 实例化插件
    const smp = new SpeedMeasurePlugin();
    module.exports = {
        configureWebpack: smp.wrap({
            module: {
                rules: [
                    {
                        test: /\.js$/,
                        use: ['thread-loader']
                    }
                ]
            }
        })
    }
    

    然后看下构建花费的时间, 2min,49.21s,相较于之前提升了 5s

    2.2、公用代码提取,使用 CDN 加载

    对于vue,vuex,vue-router,axios,echarts,swiper等我们可以利用webpack的externals参数来配置,这里我们设定只需要在生产环境中才需要使用。
    下面配置 vue.config.js

    // 导入速度分析插件
    const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
    
    // 导入体积分析插件
    const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
    
    //判断是否为生产环境
    const isProduction = process.env.NODE_ENV === 'production';
    
    //定义 CDN 路径,这里采用 bootstrap 的 cdn
    const cdn = {
        css: [
            'https://cdn.bootcss.com/Swiper/4.5.1/css/swiper.min.css'
        ],
        js: [
            'https://cdn.bootcss.com/vue/2.6.10/vue.min.js',
            'https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js',
            'https://cdn.bootcss.com/vuex/3.1.1/vuex.min.js',
            'https://cdn.bootcss.com/axios/0.19.0/axios.min.js',
            'https://cdn.bootcss.com/echarts/4.3.0/echarts.min.js',
            'https://cdn.bootcss.com/Swiper/4.5.1/js/swiper.min.js',
        ]
    }
    
    // 实例化插件
    const smp = new SpeedMeasurePlugin();
    module.exports = {
        chainWebpack: config => {
            // 生产环境配置
            if (isProduction) {
                // 生产环境注入 cdn
                config.plugin('html')
                    .tap(args => {
                        args[0].cdn = cdn;
                        return args;
                    });
            }
        },
        configureWebpack: smp.wrap({
            module: {
                rules: [
                    {
                        test: /\.js$/,
                        use: ['thread-loader']
                    }
                ]
            },
            plugins: [
                new BundleAnalyzerPlugin()
            ],
            //生产环境注入 cdn
            externals: isProduction && {
                'vue': 'Vue',
                'vuex': 'Vuex',
                'vue-router': 'VueRouter',
                'axios': 'axios',
                'echarts': 'echarts',
                'swiper': 'Swiper'
            } || {}
        })
    }
    

    紧接着,改造 html 页面。用于让我们配置的 cdn 路径注入到 html 页面

    <!DOCTYPE html>
    <html lang="zh">
    
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width,initial-scale=1.0">
      <!-- 使用 CDN 的 CSS 文件 -->
      <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
        <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet">
      <% } %>
    </head>
    
    <body>
      <noscript>
        <strong>We're sorry but eye-admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
      </noscript>
      <div id="app"></div>
      <!-- built files will be auto injected -->
    
     <!-- 使用 CDN 的 JS 文件 -->
      <% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
        <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
      <% } %>
    </body>
    
    </html>
    

    最重要的一步,看下效果,可以看到现在耗时 1min,39.19s,整整提升了 1 分多钟!

    2.3、多进程多实例并行压缩

    并行压缩主流有以下三种方案

    • 使用 parallel-uglify-plugin 插件
    • uglifyjs-webpack-plugin 开启 parallel 参数
    • terser-webpack-plugin 开启 parallel 参数 (推荐使用这个,支持 ES6 语法压缩)

    安装插件依赖

    npm i -D terser-webpack-plugin
    

    接下来在 vue.config.js 配置文件中使用插件,最终的配置文件如下

    // 导入速度分析插件
    const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
    
    // 导入代码压缩插件
    const TerserPlugin = require("terser-webpack-plugin");
    
    // 导入体积分析插件
    const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
    
    //判断是否为生产环境
    const isProduction = process.env.NODE_ENV === 'production';
    
    //定义 CDN 路径,这里采用 bootstrap 的 cdn
    const cdn = {
        css: [
            'https://cdn.bootcss.com/Swiper/4.5.1/css/swiper.min.css'
        ],
        js: [
            'https://cdn.bootcss.com/vue/2.6.10/vue.min.js',
            'https://cdn.bootcss.com/vue-router/3.1.3/vue-router.min.js',
            'https://cdn.bootcss.com/vuex/3.1.1/vuex.min.js',
            'https://cdn.bootcss.com/axios/0.19.0/axios.min.js',
            'https://cdn.bootcss.com/echarts/4.3.0/echarts.min.js',
            'https://cdn.bootcss.com/Swiper/4.5.1/js/swiper.min.js',
        ]
    }
    
    // 实例化插件
    const smp = new SpeedMeasurePlugin();
    module.exports = {
        chainWebpack: config => {
            // 生产环境配置
            if (isProduction) {
                // 生产环境注入 cdn
                config.plugin('html')
                    .tap(args => {
                        args[0].cdn = cdn;
                        return args;
                    });
            }
        },
        configureWebpack: smp.wrap({
            module: {
                rules: [
                    {
                        test: /\.js$/,
                        use: ['thread-loader']
                    }
                ]
            },
            plugins: [
                new BundleAnalyzerPlugin()
            ],
            //生产环境注入 cdn
            externals: isProduction && {
                'vue': 'Vue',
                'vuex': 'Vuex',
                'vue-router': 'VueRouter',
                'axios': 'axios',
                'echarts': 'echarts',
                'swiper': 'Swiper'
            } || {},
            optimization: {
                minimizer: [
                    new TerserPlugin({
                        parallel: 4
                    })
                ]
            }
        })
    }
    

    2.4、使用 polyfill 动态服务

    动态 polyfill 指的是根据不同的浏览器,动态载入需要的 polyfillPolyfill.io 通过尝试使用 polyfill 重新创建缺少的功能,可以更轻松地支持不同的浏览器,并且可以大幅度的减少构建体积。

    Polyfill Service 原理

    识别 User Agent,下发不同的 Polyfill


    使用方法:在 index.html 中引入如下 script 标签

    <script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js"></script>
    

    三、完结

    At last,看完之后有什么不懂的,可以留言反馈。

    转载请注明出处:https://www.jianshu.com/p/481e7214a134
    作者:TSY
    个人空间:https://hxkj.vip

    相关文章

      网友评论

        本文标题:webpack 打包优化的四种方法(多进程打包,多进程压缩,资源

        本文链接:https://www.haomeiwen.com/subject/fqnbvctx.html