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. 执行模块替换逻辑
相关推荐
菌菇汤5 分钟前
uni-app实现单选,多选也能搜索,勾选,选择,回显
前端·javascript·vue.js·微信小程序·uni-app·app
Ramos丶13 分钟前
【ABAP】 从无到有 新建一个Webdynpro程序
java·前端·javascript
qq_4116719832 分钟前
vue3 的模板引用ref和$parent
前端·javascript·vue.js
清幽竹客2 小时前
vue-37(模拟依赖项进行隔离测试)
前端·vue.js
vvilkim2 小时前
Nuxt.js 页面与布局系统深度解析:构建高效 Vue 应用的关键
前端·javascript·vue.js
滿2 小时前
Vue3 父子组件表单滚动到校验错误的位置实现方法
前端·javascript·vue.js
夏梦春蝉3 小时前
ES6从入门到精通:模块化
前端·ecmascript·es6
拓端研究室4 小时前
视频讲解:门槛效应模型Threshold Effect分析数字金融指数与消费结构数据
前端·算法
工一木子5 小时前
URL时间戳参数深度解析:缓存破坏与前端优化的前世今生
前端·缓存
半点寒12W6 小时前
微信小程序实现路由拦截的方法
前端