项目打包构建优化

优化项目: vue3-elm-master

方法

  1. 查找并诊断性能瓶颈
    1. 构建速度分析: 影响构建性能和开发效率. speed-measure-webpack-plugin
    2. 构建体积分析: 影响页面访问性能 webpack-bundle-analyzer
  2. 构建性能优化常用方法:
    1. 通过多进程加快构建速度 thread-loader
    2. 通过分包减小构建目标容量(某些文件太大,就分成多个目标) DllPlugin
    3. 减少构建目标加快构建速度(文件太小,数量有多的, 合并文件)

1. speed-measure-webpack-plugin 分析项目构建速度

用来分析各个loader, plugin花费的时间.

// vue-cli的情况
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin({
    disable: process.env.MEASURE !== "true", // 是否使用 速度测试
    outputFormat: "humanVerbose", // 输出内容格式
});
module.exports = {
    // smp.wrap(webpackConfig), 在vue.config.js里包裹configureWebpack, 直接使用webpack的话, 就是包裹webpackConfig.
    configureWebpack: smp.wrap({
        devtool: "eval-source-map",
    })
}

// 直接使用webpack的情况
const webpackConfig = smp.wrap(webpackConfig);
var compiler = webpack(webpackConfig)

2. webpack-bundle-analyzer 检测打包后的文件的体积的插件

配置项 analyzerMode:
1. "serve" 启动后通过服务器开启浏览器页面
2. "static" 将检测结果生成一个html文件, 默认为 dist/report.html
3. "json" 将检测结果生成一个json文件
4. "disabled" 不启动检测.
webpack-bundle-analyzer检测打包文件体积.png

// 检测构建文件体积的插件
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;

// webpack的配置
{
    plugins: [
            new BundleAnalyzerPlugin({
                analyzerMode: process.env.MEASURE === "true" ? "server" : "disabled",
            }),
        ]
}

3. 用thread-loader,启动多进程构建.

thread-loader, 放到所有loader的前面, 可以开启多进程构建.

  1. 由于启动进程也需要时间, 所以如果构建本身就够快的情况下, 多进程反而会更耗费时间. 需要本身就很耗费时间的情况下, 多进程才有意义.
  2. worker属性: 进程数量.
  3. 以当前项目为例, 未开多进程,构建项目5359ms, 开了5个进程, 5037ms(有用但不多).
  4. vue-cli的parallel配置项, 是否开多进程编译, 尽在生产模式production生效.
    parallel: true, build时间: 8553ms,
    parallel: false build时间: 8671ms
{
        module: {
            rules: [
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    use: [
                        {
                            loader: "thread-loader",
                            options: {
                                // 进程数量
                                worker: 5,
                            }
                        }
                    ],

                }
            ]
        },
}

4. DllPlugin 分包

对于变化几率很小的一些第三方包(比如vue, vux, vue-router), 没必要每次build都打包一次. 可以把这些单独
抽出来打包好(一般不超过300kb).

webpack本身是要体现出模块之间的依赖关系, 当我们将一些包抽离出来后, 维护之前的依赖关系就需要manifest.json 这个文件,将vue, vue-router, vuex等基础包打包成一个文件,也就是使用DllPlugin进行分包,
DllReferencePlugin对manifest.json引用. manifest.json是对分离出来的包的描述

具体步骤

  1. 分包: 定义webpack.dll.config.js 使用DllPlugin配置分包, 定义script命令,完成分包
  2. 排除分包: 在vue.config.js中, 使用DllReferencePlugin引用manifest文件排除分包
  3. 引用dll: 使用add-asset-html-webpack-plugin 引用分包文件

5. 分包

分包原因:
包太大.导致请求缓慢.

分包方案:
对于变化几率很小的一些第三方包(比如vue, vux, vue-router), 没必要每次build都打包一次. 可以把这些单独
抽出来打包成一个文件,作为静态文件(一般不超过300kb).

分包好处:

  1. 这样不用每次打包的时候重复打包,减少打包时间
  2. 减少index.js的文件大小.分出300kb, 降低页面的请求时间.

6. 分包方案

  1. DllPlugin分包
    用DllPlugin, 把vue,vuex, vue-router打包成一个js文件包vue.dll.js . 作为一个静态文件存放到项目中
    执行 webpack --config build/webpack.dll.config.js,会生成
    dll文件夹
  • vue.dll.js 打包好的vue,vuex,vue-router总和的文件.对外输出vue_xxxxxxx作为入口.
  • vue-manifest.json 记录vue.dll.js信息的文件, 给webpack用, webpack打包时要知道哪些文件dll打包了,打包的文件怎么引用.
  • vue.dll.js.LICENSE.txt 分享权限声明文件, 无实际作用.
// webpack.dll.config.js
const path = require("path");
const webpack = require("webpack");
const dllPath = "../dll";
module.exports = {
    mode: "production",
    entry: {
        // 入口文件, vue, vue-router, vuex, 命名为一个vue
        vue: ['vue', 'vue-router', 'vuex'],
        // 将 better-scroll, 命名为scroll
        // scroll: ["better-scroll"],
    },
    output: {
        // 输出文件路径
        path: path.join(__dirname, dllPath),
        // 输出的文件名, name就是entry里的"vue", "scroll", 最后生成 vue.dll.js, scroll.dll.js
        filename: '[name].dll.js',
        // library是在全局声明一个变量. 变量的内容就是entry里的内容.
        // 具体在这个案例就是声明一个 `vue_xxxxxxxx`的变量.里面有{vue: xxx, vuex: xxx, vue-router: xxxx}
        // 通过这种方式来获取entry里的内容.
        library: `[name]_[hash]`,
    },
    plugins: [
        new webpack.DllPlugin({
            //生成vue-manifest.json文件,记录vue.dll.js里都打包了哪些文件
            // 给webpack build打包用, 用来排除vue,vuex,vue-router 
            path: path.join(__dirname, dllPath, '[name]-manifest.json'),
            // 用来记录 相关对象的导出方式(比如获取vue对象方式: vue_xxxxxxxx.vue ) , 和 output.library想同.
            name: '[name]_[hash]',
            context: process.cwd(),
        })
    ]
}
  1. 由于vue,vuex, vue-router打成一个包了, 那么webpack build的时候, 就要把vue,vuex, vue-router去掉.
const path = require("path");
const webpack = require("webpack");
{
     plugins: [
            new webpack.DllReferencePlugin({
                context: __dirname,
                // 获取dll打包的信息文件, 后续webpack打包时就不会打包manifest.json里记录的文件了.
                manifest: path.resolve(__dirname, "./dll/vue-manifest.json"),
            }) 
        ]
}
  1. 默认生成的index.html是不会引入vue.dll.js的, 需要用 add-asset-html-webpack-plugin插件创建一个script标签把vue.dll.js导入到index.html里

按理说如下所示使用即可, 但是实际操作中,未生效. 网上提示需要 Html-Webpack-Plugin@3.2.0, 我未使用此种方案

const AddAssetHtmlWebpackPlugin = require("add-asset-html-webpack-plugin");
{
    plugins: [
         new AddAssetHtmlWebpackPlugin({
                filepath: path.resolve(__dirname, './dll/vue.dll.js'),
            })
    ]
}

我的方案:

  1. htmlWebpackPlugin指定了一个index.html模板, 在index.html模板中直接用script引入 vue.dll.js文件
  2. copy-webpack-plugindll/vue.dll.js直接复制到 dist/js/vue.dll.js.
//  index.html直接加入这一行
    <script src="js/vue.dll.js"></script>

// vue.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");

export default {
    configureWebpack: {
        plugins: [
            new HtmlWebpackPlugin({
                template: path.resolve(__dirname, './public/index.html')
            }),
            new CopyWebpackPlugin({
                patterns: [{
                    from: path.resolve(__dirname, "./dll/vue.dll.js"),
                    to: path.resolve(__dirname, "./dist/js/vue.dll.js"),
                }]
            }),
        ]
    }
}

7. cache缓存

webpack的cache缓存属性. 开发环境默认 true, 生产环境禁用.
一般是测试环境build代码时使用. 用jenkins在线打包时, 第一次慢,第二次快用的就是cache.

生成的缓存文件

  • 0.pack : 应该是 node_modules里的总和文件
  • index.pack : 应该是业务的总和文件.

build时间:

  • 不适用缓存 17838ms
  • 使用缓存 1548ms
export default {
    configureWebpack: {
        // 使用缓存, 开发环境默认 true, 生产环境禁用.
        cache: {
            type: 'filesystem',
            cacheDirectory: path.resolve(__dirname, "node_modules/.cache_temp"),
        }, 
    }
}

8. image-webpack-loader 图片压缩

插件下载: cnpm i -D image-webpack-plugin, 用npm下载会报错

9. purgecss-webpack-plugin css 去掉未使用的css

该插件会把css文件里有的, 但是在html中未使用的css类去掉.达到压缩css文件的目的.

未压缩前app.css: 131kb. 压缩后 6kb;
插件下载: cnpm i -D purgecss-webpack-plugin, 用npm下载会报错

const glob = require("glob");
// 去掉未使用的css的插件
const { PurgeCSSPlugin } = require("purgecss-webpack-plugin");
const PATHS = {
    src: path.join(__dirname, "src"),
}
export default {
    plugins: [
        new PurgeCSSPlugin({
                paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),
        })
    ]
}

posted on 2024-11-27 19:53  下辈子当座桥-李飞  阅读(36)  评论(0)    收藏  举报