Webpack

2 阅读2分钟

Webpack

一、核心概念

1. Webpack 核心概念

问题:Webpack 核心概念

答案核心回答:Webpack 核心概念包括 Entry、Output、Loader、Plugin、Mode。

代码示例

// webpack.config.js
module.exports = {
    // 入口
    entry: './src/index.js',
    
    // 输出
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.[contenthash].js'
    },
    
    // Loader 处理非 JS 文件
    module: {
        rules: [
            { test: /\.css$/, use: ['style-loader', 'css-loader'] },
            { test: /\.js$/, use: 'babel-loader' }
        ]
    },
    
    // Plugin 执行更复杂任务
    plugins: [
        new HtmlWebpackPlugin({ template: './src/index.html' }),
        new CleanWebpackPlugin()
    ],
    
    // 模式
    mode: 'production' // development | production | none
};

二、代码分割与懒加载

2. Code Splitting

问题:Code Splitting

答案核心回答:代码分割将 bundle 拆分成多个 chunk,实现按需加载。

代码示例

// 1. 入口分割
module.exports = {
    entry: {
        main: './src/index.js',
        vendor: './src/vendor.js'
    },
    output: {
        filename: '[name].[contenthash].js'
    }
};

// 2. 动态 import
const LazyComponent = React.lazy(() => import('./LazyComponent'));

// 3. splitChunks
module.exports = {
    optimization: {
        splitChunks: {
            chunks: 'all',
            cacheGroups: {
                vendor: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'vendors',
                    priority: 10
                }
            }
        }
    }
};

3. Lazy Loading

问题:Lazy Loading

答案核心回答:懒加载延迟加载非首屏资源。

代码示例

// ES6 动态导入
const getModule = () => import('./module');

// React 懒加载
const LazyComponent = React.lazy(() => import('./Component'));
function App() {
    return (
        <Suspense fallback={<Loading />}>
            <LazyComponent />
        </Suspense>
    );
}

// Vue 路由懒加载
const routes = [
    { path: '/', component: () => import('./Home.vue') }
];

三、Loader 与 Plugin

4. 常用 Loader

问题:常用 Loader

答案核心回答:babel-loader、css-loader、style-loader、file-loader 等。

代码示例

module.exports = {
    module: {
        rules: [
            // Babel
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env', '@babel/preset-react']
                    }
                }
            },
            
            // CSS
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader', 'postcss-loader']
            },
            
            // 图片
            {
                test: /\.(png|jpg|gif)$/,
                type: 'asset/resource'
            },
            
            // 字体
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/,
                type: 'asset/resource'
            }
        ]
    }
};

5. 常用 Plugin

问题:常用 Plugin

答案核心回答:HtmlWebpackPlugin、CleanWebpackPlugin、MiniCssExtractPlugin 等。

代码示例

const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
    plugins: [
        // 清理 dist
        new CleanWebpackPlugin(),
        
        // 生成 HTML
        new HtmlWebpackPlugin({
            template: './src/index.html',
            minify: true,
            chunks: ['main']
        }),
        
        // 提取 CSS
        new MiniCssExtractPlugin({
            filename: '[name].[contenthash].css'
        }),
        
        // 代码压缩
        new TerserPlugin({
            terserOptions: {
                compress: { drop_console: true }
            }
        })
    ]
};

四、性能优化

6. Webpack 性能优化

问题:Webpack 性能优化

答案核心回答:减少resolve、压缩代码、提取公共代码、使用缓存等。

代码示例

module.exports = {
    // 1. 优化 resolve
    resolve: {
        extensions: ['.js', '.jsx', '.json'],
        alias: {
            '@': path.resolve(__dirname, 'src')
        }
    },
    
    // 2. externals 外部扩展
    externals: {
        react: 'React',
        'react-dom': 'ReactDOM'
    },
    
    // 3. DllPlugin 预编译
    // 4. HashedModuleIdsPlugin 稳定 ID
    // 5. terser-webpack-plugin 压缩
    optimization: {
        minimize: true,
        minimizer: [new TerserPlugin()],
        splitChunks: {
            chunks: 'all'
        }
    },
    
    // 6. 缓存
    cache: {
        type: 'filesystem'
    }
};

五、热模块替换

7. HMR 原理

问题:HMR 原理

答案核心回答:热模块替换在不刷新页面的情况下更新模块。

代码示例

// webpack-dev-server 自动支持 HMR
// 配置
module.exports = {
    devServer: {
        hot: true,
        hotOnly: true
    }
};

// 手动启用 HMR
if (module.hot) {
    module.hot.accept('./render', () => {
        render();
    });
}

// Vue HMR
import Vue from 'vue';
if (module.hot) {
    module.hot.accept();
}

// React HMR
import React from 'react';
if (module.hot) {
    module.hot.accept();
}