webpack

81 阅读4分钟

webpack优化

1、优化产出代码

1、小图片使用base64编码
2、bundle加hash--[contenthash:8]
3、懒加载
4、提取公共代码
5、IgnorePlugin
6、使用cdn加速
7、使用production
8、使用scope hosting

2、优化打包构建

1、优化babel-loader(production)
babel编译es6->es5过程中消耗多
{
    test: /\.js$/,
    use: ['babel-loader?cacheDirectory'], // 开启缓存
    include: path.reslove(__dirname, 'src'), // 明确范围
    // exclude: path.reslove(__dirname, 'node-modules') // 排除范围
    // include和exclude选择其一即可
}


2、ignorePlugin(production)
避免引入无用模块
plugin: [
    ...
    // 忽略moment下面的/locale目录
    new webpack.IgnorePlugin(/\.\/locale/, /moment/)
]

3、noParse(production)
避免重复打包
module.export = {
    module: {
        rules: [...],
        // 忽略对‘react.min.js’ 文件的递归解析处理
        noParse: [/react\.min\.js$/]
    }
}

IgnorePlugin vs noParse
IgnorePlugin直接不引入,代码中没有
noParse引入,但不打包
两者都优化打包体积

4、happyPack(production)
多进程打包工具
const HappyPack = require('happyPack');
module.export = {
    module: {
        rules: [
            test: /\.js$/,
            use: ['happypack/loader?id=babel']
        ]
    },
    plugin: { 
        new HappyPack({
            id: 'babel', //唯一标识符,与上面对应
            loaders: ['babel-loader?cacheDirectory']
        })
    }
}

5ParallelUglifyPlugin(production)
多进程代码压缩
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin);
...
plugin: [
    new ParallelUglifyPlugin({
        uglify: {
            output: {
                beautify: false, // 最紧凑的输出
                comments: false, // 删除所有注释
            },
            compress: {
                drop_console: ture, // 删除console
                collapse_var: true,
                reduce_vars: true
            }
        }
    })
]

happyPack、ParallelUglifyPlugin适合大型项目,小型会降低速度

6、自动刷新(development)
编译完成浏览器自动刷新
module.export = {
    watch: true, // 开启监听
    watchOption: {...} // 监听配置 
}

7、热更新(development)
浏览器不用刷新代码就生效

自动刷新 vs 热更新
自动刷新:整个网页全部刷新,网速较慢,状态会丢失
热更新:新代码生效,网页不刷新,状态丢失


8、DLLPlugin(development)
提前将第三方库打包成DLL取引用

3、为何要打包构建

体积更小,加载更快
编译高级语言或语法(ts、es6+、模块化、sass等)
兼容性和错误检查(polyfill、postcss、eslint)
统一高效的开发环境、构建流程和产出标准
集成公司构建规范(提测、上线等)

4、module、chunk、bundle区别

module-各个源码文件,js css png等
chunk--分析过程中多个模块合并成的
bundle--最终输出的文件

module-->chunk-->bundle

5、基本配置

// webpack.config.js文件写入

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
    mode: 'development',
    entry: 'index.js',
    output: {
        filename: 'bundle.js',
        path: path.join(__dirname, 'dist')
    },
    plugins: [
        new CleanWebpackPlugin(), // 在打包前删除所有上一次打包好的文件
        new HtmlWebpackPlugin({
            template: 'src/index.html'
        })
    ],
    module: {
        rules: [
            {
                test: /\.(js|ts)$/,
                loader: 'babel-loader',
                include: /src/,
                exclude: /node_modules/
            },
            {
                test: /\.(png|jpg|gif)$/,
                use: {
                    loader: 'url-loader',
                    options: '[name]_[hash].[ext]', // 打包名称 name-原始名称, hash使用md5算法,ext是后缀
                    outputPath: 'images/',
                    limit: 5*1024 // 小于5kb的图片用base64格式产出,否则沿用file-loader产出url格式
                }
            },
            {
                test: /\.css$/,
                use: ['style-loader','css-loader', 'postcss-loader']
            },
            {
                test: /\.sass$/,
                use: ['style-loader', 'css-loader', 'sass-loader', 'postcss-loader']
            }
        ]
    }
}

6、压缩抽离css、公共代码、js


// webpack.pro.js

const path = require('path');
const WebpackCommonConf = require('./webpack.common');
const { merge } = require('webpack-merge'); // merge合并WebpackCommonConf公共配置
const MiniCssExtractorPlugin = require('mini-css-extrator-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-plugin');

module.exports = merge(WebpackCommonConf, {
    mode: 'production',
    output: {
        filename: '[name][contenthash:8].js',
        path: path.join(__dirname, 'dist_pro')
    },
    plugins: [
        // 抽离css
        new MiniCssExtractorPlugin({
            filename: '[name][contenthash:8].css'
        })
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractorPlugin.loader,  // 生产环境由‘style-loader’换为 MiniCssExtractPlugin.loader
                    'css-loader',
                    'postcss-loader'
                ]
            },
            {
                test: /\.less$/,
                use: [
                    MiniCssExtractorPlugin.loader,
                    'css-loader',
                    'less-loader',
                    'postcss-loader'
                ]
            }
        ]
    },
    optimization: {
        // 压缩css
        minimizer: [ new TerserJSPlugin(), new OptimizeCssAssetsPlugin() ],

        // 分割代码块
        splitChunks: {
            chunks: 'all',
            /*
            * initial 入口chunk,对异步导入的文件不处理
            * async 异步chunk,只对异步导入的文件处理
            * all 全部chunk
            * */

            // 缓存分组
            cacheGroups: {
                // 第三方模块
                vendor: {
                    name: 'vendor', // chunk名称
                    priority: 1, // 权重更高,优先抽离
                    test: /node-modules/,
                    minSize: 0, // 大小限制
                    minChunk: 1 // 最少复用过几次
                },
                // 公共模块
                common: {
                    name: 'common',
                    priority: 0,
                    minSize: 0,
                    minChunk: 2
                }
            }
        }
    }
})

webpack和vite对比

  • 1.开发模式不同

Webpack在开发模式下依然会对所有模块进行打包操作,虽然提供了热更新,但大型项目中依然可能会出现启动和编译缓慢的问题;而Vite则采用了基于ES Module的开发服务器,只有在需要时才会编译对应的模块,大幅度提升了开发环境的响应速度。

  • 2.打包效率不同

Webpack在打包时,会把所有的模块打包成一个bundle,这会导致初次加载速度较慢;而Vite则利用了浏览器对ES Module的原生支持,只打包和缓存实际改动的模块,从而极大提高了打包效率。

  • 3.插件生态不同

Webpack的插件生态非常丰富,有大量社区和官方插件可以选择,覆盖了前端开发的各个方面;而Vite的插件生态尽管在不断发展,但相比Webpack来说还显得较为稀少。

  • 4.热更新机制不同

Webpack的热更新需要整个模块链重新打包和替换,对于大型项目可能会有延迟;Vite的热更新则只会针对改动的模块进行更新,提高了更新速度。

  • 5.应用场景不同

webpack由于其丰富的功能和扩展性,适合于大型、复杂的项目。而vite凭借其轻量和速度,更适合于中小型项目和快速原型开发。

vite比webpack快的原因

  • 利用了浏览器对 ESM 的原生支持

    Vite 利用了现代浏览器对 ES Modules(ESM)的原生支持,这使得在开发环境下,Vite 可以直接运行源代码,而无需像 Webpack 那样先进行打包。由于省去了打包的过程,Vite 的启动速度非常快。相比之下,Webpack 需要将源代码打包成浏览器可识别的格式,这个过程会消耗一定的时间。

  • 按需编译

    Vite 采用了按需编译的策略,只有当请求某个模块时,才会对该模块进行编译。这种按需加载的方式极大地缩减了编译时间。而 Webpack 在构建时会对整个项目进行扫描和分析,无论模块是否被使用,都会被打包进最终的输出文件中,这会增加构建的时间。

  • 采用了不同的构建机制

    Webpack 是基于 Node.js 实现的,而 Vite 是使用 Esbuild 预构建依赖。Esbuild 是一个使用 Go 语言编写的打包工具,其构建速度比以 Node.js 编写的打包器要快得多。这是因为 Go 语言在编译和执行速度上具有优势,使得 Esbuild 能够更快速地完成依赖的预构建。

前端重新部署如何通知浏览器刷新

可以结合使用Service Worker和WebSocket来实现更高效的通知机制;

同时,也可以在后端配合设置版本号接口和HTTP响应头来控制缓存(如Cache-ControlETag)和版本更新