Webpack[TBC]

核心概念

  1. 本质:模块打包器

    • 将各种资源(JS/CSS/图片等)视为模块
    • 通过依赖关系构建依赖图
    • 输出静态资源bundle
  2. 五大核心概念

    • Entry :打包入口起点,entry: './src/index.js'
    • Output :输出位置配置,path: path.resolve(__dirname, 'dist')
    • Loaders :处理非JS文件,{ test: /\.css$/, use: ['style-loader', 'css-loader'] }
    • Plugins :扩展功能,new HtmlWebpackPlugin()
    • Mode :环境模式,mode:'development'

核心工作原理

打包流程

graph LR A[入口文件 Entry] --> B[解析模块依赖] B --> C[构建依赖图] C --> D[应用 Loaders 转换] D --> E[打包模块资源] E --> F[执行插件优化] F --> G[输出 Bundles] G --> H[完成打包] classDef default fill:#f9f,stroke:#333,stroke-width:2px; classDef process fill:#6cf,stroke:#333,stroke-width:2px; classDef output fill:#2ecc71,stroke:#333,stroke-width:2px; class A,H process; class B,C,D,E,F process; class G output;

关键过程

  1. 入口文件
    • 从配置的入口文件开始打包过程
    • 通常是index.js/main.js
  2. 解析模块依赖
    • 分析文件中的import/require语句
    • 递归查找所有依赖模块
  3. 构建依赖图
    • 创建模块依赖关系图谱
    • 确定模块加载顺序
  4. 应用Loaders转换
    • 使用配置的Loaders处理各类资源
    • 如:JS转译、CSS预处理、图片优化
  5. 打包模块资源
    • 将所有模块合并为代码块chunk
    • 应用代码分割规则
  6. 执行插件优化
    • 运行插件进行额外处理
    • 如:代码压缩、资源注入、生成html
  7. 输出bundles
    • 将最终结果写入文件系统
    • 生成JS/CSS/资源文件
  8. 完成打包
    • 输出构建统计信息
    • 触发回调通知

配置webpack.config.js

基础结构

javascript 复制代码
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'bundle.[contenthash].js',
        path: path.resolve(__dirname, 'dist'),
        clean: true,
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: 'babel-loader',
            },
        ],
    },
    plugins: [
        new HtmlWebpackPlugin({ template: './src/index.html' }),
    ],
    mode:'production',
};

Loaders

文件类型 Loader配置
Javascript babel-loader, @babel/preset-env
CSS ['style-loader', 'css-loader', 'postcss-loader']
SASS ['sass-loader'] [需配合css-loader]
图片/字体 type: 'asset/resource' [webpack5内置]
SVG @svg/webpack

Plugins

插件 用途
HtmlWebpackPlugin 生成html文件
MiniCssExtractPlugin 提取CSS到单独文件
DefinePlugin 定义环境变量
CleanWebpackPlugin 清理构建目录
BundleAnalyzerPlugin 包体积分析

高级优化策略

代码分割Code Splitting

将应用代码拆分为多个独立报chunk,按需加载或并行加载,减少初始加载体积。

目的

  1. 减少初始加载体积:避免用户下载整个应用代码
  2. 提高加载速度:并行加载多个小文件比单个大文件更快
  3. 按需加载:只加载当前视图需要的代码
  4. 缓存优化:第三方库单独打包,充分利用浏览器缓存

实现方式

  1. 入口点分割 \手动
javascript 复制代码
// webpack.config.js
module.exports = {
    entry: {
        app: './src/app.js',
        vendor: ['react', 'react-dom']
    },
    output: {
        filename: '[name].bundles.js'
    }
};
  1. 动态导入
javascript 复制代码
// 使用import语法
const loadComponent = () => import('./HeavyComponent');

button.addEventListener('click', () => {
    loadComponent().then(module => {
        module.default.render();
    });
});
  1. 智能分割SplitChunksPlugin
javascript 复制代码
optimization: {
    splitChunks: {
        chunks: 'all',
        minSize: 20000,  // 超过20kb才分割
        maxSize: 0,
        minChunks: 1,
        cachedGroups: {
            vendors: {
                test: /[\\/]node_modules[\\/]/,
                name: 'vendors',
                priority: -10
            },
            commons:{
                name: 'commons',
                minChunks: 2,  // 被2个以上chunk引用
                priority: -20,
                reuseExistingChunk: true
            }
        }
    }
}

代码分割策略

策略类型 适用场景 示例
入口分割 多页面应用 entry: { home: './home.js', about: './about.js' }
动态分割 路由组件/弹窗 () => import('./UserProfile')
第三方库 稳定不常更新的库 cacheGroups.vendors
运行时代码 Webpack运行时 runtimeChunk: 'single'

Tree Shaking

  • 使用ES6模块语法import/export
  • 生产模式自动启动
  • package.json中添加:
json 复制代码
"sideEffects": ["*.css", "*.global.js"]

缓存优化

javascript 复制代码
output: {
    filename: '[name].[contenthash].js'
}

懒加载

javascript 复制代码
// dynamic import
const loadModule  = () => import('./heavyModule.js');

自定义扩展

自定义loader

javascript 复制代码
module.exports = function(source) {
    return source.replace(/console\.log\(.*\);?/g, '');
};

自定义plugin

javascript 复制代码
class myPlugin {
    apply(complier) {
        commplier.hooks.done.tap('MyPlugin', stats => {
            console.log('编译完成!');
        });
    }
}

性能优化实践

构建速度优化

方法 实现
缓存loaders use: ['cache-loader', 'babel-loader']
多进程处理 thread-loader
DLL预构建 DllPlugin + DllReferencePlugin
缩小搜索范围 resolve: { modules: [path.resolve('node_modules')] }

输出优化

方法 实现
CDN加速 output.publicPath: 'https://cdn.example.com/'
Gzip压缩 compression-webpack-plugin
图片优化 image-webpack-loader

原理深入

Tapable事件流机制

javascript 复制代码
compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
    // 处理逻辑
    callback();
});

核心对象关系

classDiagram Compiler *-- Compilation Compilation *-- Module Module *-- Dependency Compiler : hooks Compilation : modules Compilation : chunks

HMR热更新原理

  1. 建立WebSocket连接
  2. 文件修改触发重新编译
  3. 服务端发生更新消息
  4. 客户端拉取更新模块
  5. 执行模块替换逻辑
相关推荐
用户4099322502122 分钟前
FastAPI的查询白名单和安全沙箱机制如何确保你的API坚不可摧?
前端·后端·github
前端小巷子11 分钟前
深入 npm 模块安装机制
前端·javascript·面试
cypking1 小时前
electron中IPC 渲染进程与主进程通信方法解析
前端·javascript·electron
西陵1 小时前
Nx带来极致的前端开发体验——借助playground开发提效
前端·javascript·架构
江城开朗的豌豆2 小时前
Element UI动态组件样式修改小妙招,轻松拿捏!
前端·javascript·vue.js
float_六七2 小时前
JavaScript:现代Web开发的核心动力
开发语言·前端·javascript
zhaoyang03012 小时前
vue3笔记(2)自用
前端·javascript·笔记
德育处主任Pro3 小时前
# JsSIP 从入门到实战:构建你的第一个 Web 电话
前端
拾光拾趣录3 小时前
setTimeout(1) 和 setTimeout(2) 的区别
前端·v8
拾光拾趣录3 小时前
内存泄漏的“隐形杀手”
前端·性能优化