大家都知道的webpack优化策略

845 阅读3分钟

内容基于“手把手带你青铜上钻石之——webpack”篇

输出日志优化

friendly-errors-webpack-plugin——优化构建时命令行显示日志

npm install -D friendly-errors-webpack-plugin

webpack.base.conf.js:

 plugins: [ new FriendlyErrorsWebpackPlugin() ]

启用 quiet 后,除了初始启动信息之外的任何内容都不会被打印到控制台。这也意味着来自 webpack 的错误或警告在控制台不可见。

webpack.dev.conf.js:

module.exports = merge(webpackBaseConfig, {
    mode: 'development',
    devServer: {
        ...
        quiet: true
    }
})

执行开发环境打包npm run dev

webpack.prod.conf.js:

const {merge} = require('webpack-merge')
const webpackBaseConfig = require('./webpack.base.conf.js')
module.exports = merge(webpackBaseConfig, {
    mode: 'production',
    stats: 'errors-only'
})

stats表示统计信息:

  • errors-only:只在发生错误的时候输出
  • minimal:只在发生错误或新的编译时输出
  • none:没有输出
  • normal:标准输出
  • verbose:全部输出

执行生产环境打包npm run prod

webpack-dashboard——输出可视化面板

webpack-dashboard能够在终端以面板的形式输出打包日志,将信息分块显示。

npm install -D webpack-dashboard

webpack.prod.conf.js

var DashboardPlugin = require("webpack-dashboard/plugin");
plugins: [new DashboardPlugin()]

package.json

 "scripts": {
    "prod:dashboard": "webpack-dashboard -- webpack --mode=production --config ./webpack.prod.conf.js"
 }

构建分析

speed-measure-webpack-plugin——打包速度分析

npm install -D speed-measure-webpack-plugin

webpack.prod.conf.js:

const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
const smp = new SpeedMeasurePlugin();
module.exports = smp.wrap(merge(webpackBaseConfig, {
    ...
}))

使用方式就是将我们之前的webpack配置包裹(wrap)起来。

它会分析插件、loader等各项的处理时间,处理速度从快到慢分别使用绿、黄、红三种颜色的字体进行展示。

有什么用呢,比如你从中看出项目的压缩plugin耗时很长,那么你可以想到能不能对这个压缩过程进行优化,像是并行压缩等。

wepback-bundle-analyzer——打包体积分析

npm install -D webpack-bundle-analyzer

用于分析文件打包后的体积大小

webpack.prod.conf.js:

const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer');
module.exports = merge(webpackBaseConfig, {
    ...
    plugins: [
        new BundleAnalyzerPlugin()
    ]
})

执行构建命令后会在localhost:8888端口打开服务:

每个块所占面积的大小表示它所占用的大小。

代码压缩

html-webpack-plugin不为人知的另一面——压缩html文件

html-webpack-plugin中有个参数minify

minify{Boolean|Object}:true if mode is 'production', otherwise false

即在生产环境下自动开启压缩html文件。

terser-webpack-plugin——压缩js代码

npm install -D terser-webpack-plugin

webpack.dev.conf.js

const TerserPlugin = require('terser-webpack-plugin');
module.exports = merge(webpackBaseConfig, {
    mode: 'development',
    optimization: {
        minimize: true,
        minimizer: [
            new TerserPlugin({
                parallel: true,  //默认为true,开启并行压缩
            })
        ]
    }
})

加快二次构建速度

开启babel-loader缓存

我们多数处理的是js文件,因此可以开启babel-loader缓存,第二次进行构建的时候会从缓存中读取文件,加快二次构建速度

webpack.base.conf.js:

{
    test: /\.js$/,
    exclude: /(node_modules)/,
    use: {
      loader: 'babel-loader',
      options: {
        presets: ['@babel/preset-env'],
        cacheDirectory:true
      }
    }
}

cacheDirectory是缓存结果的存放目录,设置为true表示开启缓存。

默认缓存存放路径:node_modules/.cache/babel-loader目录。

teser-webpack-plugin开启压缩缓存

webpack.prod.conf.js:

optimization: {
    minimize: true,
    minimizer: [
        new TerserPlugin({
            parallel: true,  //默认为true
            cache: true
        })
    ]
}

缓存存放路径:node_modules/.cache/terser-webpack-plugin目录。

加快打包速度

externals

有时我们不想将一些依赖打包进最终的bundle,而是通过CDN的方式在运行时引入,此时可以通过external进行配置。

webpack.prod.config.js

module.exports = merge(webpackBaseConfig, {
    externals: {
        vue: 'Vue'
    }
})

其中,vue属性表示应该排除import vue from 'vue'中的vue模块,'Vue'表示在全局查找Vue变量。

src/index.html

<body><script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script></body>

开始构建npm run prod

可以看到项目依然运行正常。

externals的缺点就是如果要引入很多个CDN,会增加网络请求(script标签变多)。

thread-loader——多进程多实例构建

一般只在资源占用大的loader下使用。

{
    test: /\.js$/,
    exclude: /(node_modules)/,
    use: [
        {
            loader: "thread-loader",
            options: {
                workers: 
            }    
        },
        "babel-loader"
    ]
}

DLL——动态链接库

DLL(dynamic link library),在webpack中是一种预编译资源模块的手段,它能提前将一些依赖进行打包,以此方式来减少后面的打包时间。

需要注意的是,只要依赖不变,dll文件就不需要改变,如果其中的依赖版本发生改变,就需要重新打包dll文件。

新建webpack.dll.js:

const path = require("path")
const webpack = require("webpack")
module.exports = {
    mode: 'production',
    entry: {
        "custom": ['vue']
    },
    output: {
        filename: "[name].dll.js",
        path: path.resolve(__dirname, 'build/library'),
        library: "[name]",  //打包后暴露出的库的名字,[name].dll.js中引用的库名
        libraryTarget: "var"  //默认值,以一个变量的形式暴露出去
    },
    plugins: [
        new webpack.DllPlugin({
            name: "[name]",  //作为DllPlugin生成的json文件中的name属性
            path: path.resolve(__dirname, 'build/library/[name].json')
        })
    ]
}

需要注意的是,dll输出目录不要放在打包输出目录下,否则会被clean-webpack-plugin删掉的,而且我们需要的是持久使用这个文件,所以不应该放在打包输出目录。

package.json

"scripts": {
    "dll": "webpack --config ./webpack.dll.js"
}

执行打包命令npm run dll,对资源进行预编译。

const {merge} = require('webpack-merge')
const webpackBaseConfig = require('./webpack.base.conf.js')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
const path = require('path')
const webpack = require('webpack');
module.exports = merge(webpackBaseConfig, {
    mode: 'production',
    plugins: [
        new webpack.DllReferencePlugin({
            manifest: path.resolve(__dirname, 'build/library/custom.json')
        }),
        new AddAssetHtmlWebpackPlugin({
            filepath: path.resolve(__dirname, 'build/library/custom.dll.js')
        })
    ]
})

注意,需要安装add-asset-html-webpack-plugin插件,将这个dll文件引入:

npm install -D add-asset-html-webpack-plugin

然后就可以执行打包命令了。