bundle文件压缩
一、Bundle 核心定义
Bundle(捆绑) 是将多个前端代码文件(JS/CSS/图片等)合并为少数文件的技术,核心作用:
- 🚀 减少网络请求(浏览器加载 1 个文件 vs 100 个文件)
- 📦 管理依赖关系(自动处理模块导入导出)
- 🔧 优化静态资源(如删除未使用代码)
二、前端压缩代码原理
在 Bundle 基础上进行 代码压缩(Minify) ,实现方式:
- 删除空格/注释
- 缩短变量名(如
userData
→a
) - 简化语法(如
true
→!0
)
三、代码示例对比(清晰版)
1. 原始代码
javascript
// src/utils.js
export function formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
return `${year}-${month}`;
}
// src/app.js
import { formatDate } from './utils.js';
console.log(formatDate(new Date()));
- Bundle 后的代码(未压缩)
javascript
// dist/bundle.js
function formatDate(date){
const year=date.getFullYear();
const month=String(date.getMonth()+1).padStart(2,'0');
return year+'-'+month;
}
console.log(formatDate(new Date()));
- 压缩后的代码(体积减少 60%↑)
javascript
// dist/bundle.min.js
function f(d){return d.getFullYear()+"-"+String(d.getMonth()+1).padStart(2,"0")}console.log(f(new Date));
webpack都有哪些模块,各自的模块是什么作用
一、核心模块架构
xml
webpack.config.js
├── ==‌**entry**‌== 📌 程序入口
├── ==‌**output**‌== 📦 输出配置
├── ==‌**loaders**‌== ⚙️ 文件处理器(非JS→JS)
├── ==‌**plugins**‌== 🔌 扩展功能(如HTML生成)
├── ==‌**mode**‌== 🌓 环境模式(dev/prod)
├── ==‌**module**‌== 📂 模块解析规则
└── ==‌**resolve**‌== 🔎 路径解析策略
二、模块详解 + 代码示例
1️⃣ entry(入口)
arduino
// 单入口(SPA场景)
export default {
entry: './src/index.js'
};
// 多入口(MPA场景)
entry: {
main: './src/app.js',
admin: './src/admin.js'
}
2️⃣ output(输出)
lua
const path = require('path');
output: {
filename: '[name].[contenthash:8].js', // 利用哈希防缓存
path: path.resolve(__dirname, 'dist'),
clean: true // 自动清空旧文件(Webpack 5+)
}
3️⃣ loaders(加载器)
javascript
module: {
rules: [
// Babel转换(ES6→ES5)
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
// CSS处理(支持模块化)
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: { modules: true }
},
'postcss-loader' // 自动加前缀
]
}
]
}
4️⃣ plugins(插件)
javascript
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
plugins: [
// 自动生成HTML并注入资源
new HtmlWebpackPlugin({
template: './public/index.html'
}),
// 提取CSS为独立文件
new MiniCssExtractPlugin({
filename: 'styles.[contenthash].css'
})
]
5️⃣ mode(模式)
arduino
// 开发模式(启用热更新、不压缩)
mode: 'development',
// 生产模式(启用代码压缩)
mode: 'production'
6️⃣ resolve(路径解析)
csharp
resolve: {
extensions: ['.js', '.jsx', '.json'], // 可省略扩展名
alias: {
'@components': path.resolve(__dirname, 'src/components/')
}
}
三、完整配置示例
javascript
// webpack.config.js (2025 推荐配置)
import { defineConfig } from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
export default defineConfig({
entry: './src/index.jsx',
output: {
filename: 'bundle.[contenthash].js',
path: './dist'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.scss$/,
use: [
'style-loader',
'css-modules-loader', // 2025 原生CSS模块支持
'sass-loader'
]
}
]
},
plugins: [new HtmlWebpackPlugin()],
resolve: {
extensions: ['.jsx', '.js', '.json']
}
});
⚠️ 关键注意事项
Tree Shaking 优化
确保 package.json
中设置 "sideEffects": false
json
{
"name": "your-app",
"sideEffects": ["*.css", "*.global.js"]
}
开发/生产环境分离
使用 webpack-merge
拆分配置:
sql
npm install webpack-merge --save-dev
php
// webpack.dev.js
const { merge } = require('webpack-merge');
const baseConfig = require('./webpack.config.js');
module.exports = merge(baseConfig, {
mode: 'development',
devtool: 'eval-source-map'
});
性能监控
使用 speed-measure-webpack-plugin
分析构建耗时:
ini
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
const smp = new SpeedMeasurePlugin();
module.exports = smp.wrap(yourConfig);
1:如何实现 Tree Shaking 深度优化?
java
// webpack.config.js
module.exports = {
optimization: {
usedExports: true, // 标记未使用的导出
innerGraph: true, // 启用深层依赖分析(Webpack7 新增)
sideEffects: 'strict' // 强制要求 package.json 声明副作用(Webpack7 新配置)
},
experiments: {
syncWebAssembly: true // 支持 WASM 模块的 Tree Shaking
}
};
// package.json 必须声明(否则无法生效!)
{
"sideEffects": [
"**/*.css", // 所有 CSS 文件视为副作用
"src/polyfills.js" // 指定需要保留的文件
]
}
核心要点:
- 必须使用 ES Modules 语法(禁用 CommonJS)
- 通过
/*#__PURE__*/
标注副作用函数(如 React 组件) - 使用 Webpack Bundle Analyzer 可视化验证效果
2:解释 Module Federation 动态加载 原理
javascript
// 主机应用配置(Host App)
new ModuleFederationPlugin({
name: 'host',
filename: 'remoteEntry.js',
remotes: {
payment: 'payment@https://cdn.com/payment/remoteEntry.js',
},
shared: {
react: { singleton: true, eager: true }, // 共享核心库
'react-dom': { singleton: true }
}
});
// 动态加载远程模块
const PaymentModule = React.lazy(() => import('payment/PaymentPage'));
3: 自定义 Loader 开发全流程
javascript
// markdown-loader.js(完整实现)
const { getOptions } = require('loader-utils');
const marked = require('marked');
module.exports = function(source) {
const options = getOptions(this); // 获取配置参数
marked.setOptions(options); // 应用 Markdown 配置
// 添加缓存支持(Webpack7 默认启用)
this.cacheable(true);
// 转换逻辑
const html = marked.parse(source);
// 返回 ES 模块
return `export default ${JSON.stringify(html)};`;
};
// webpack 配置
module: {
rules: [
{
test: /\.md$/,
use: [
{
loader: 'html-loader',
options: { minimize: true }
},
{
loader: './markdown-loader',
options: { highlight: require('highlight.js') }
}
]
}
]
}
调试技巧:
bash
# 启用 Loader 调试模式
node --inspect-brk ./node_modules/webpack/bin/webpack.js
- Pitch 阶段 :通过
pitch
函数实现预处理拦截 - AST 操作 :集成
@babel/parser
实现代码分析 - 热更新 :添加
this._module.buildInfo.cacheable = false
禁用缓存
4: Loader 和 Plugin 的本质区别是什么?
维度 | Loader | Plugin |
---|---|---|
功能定位 | 文件内容转换器(如转译 JSX、SCSS) | 生命周期钩子扩展(如资源优化、环境注入) |
执行时机 | 模块解析阶段(Module Resolution) | 整个构建流程(从启动到产物生成) |
开发复杂度 | 简单(函数式处理) | 复杂(需理解 Compiler/Compilation API) |
手写示例:
javascript
// 自定义 Loader(大写转换器)
module.exports = function(source) {
return source.toUpperCase(); // 将文本全部转为大写
};
// 自定义 Plugin(构建完成通知)
class BuildDoneNotifyPlugin {
apply(compiler) {
compiler.hooks.done.tap('Notify', stats => {
require('node-notifier').notify({
title: 'Webpack',
message: `构建完成!耗时${stats.endTime - stats.startTime}ms`
});
});
}
}
常见应用场景:
- Loader 典型 :
babel-loader
,sass-loader
,file-loader
- Plugin 典型 :
HtmlWebpackPlugin
,DefinePlugin
,BundleAnalyzerPlugin
如何实现「代码分割」与「懒加载」?
核心配置:
less
// webpack.config.js
optimization: {
splitChunks: {
chunks: 'all', // 控制分割范围
minSize: 30000, // 最小分割阈值(30KB)
cacheGroups: { // 定义分割策略组
vendor: { // 自定义策略组名称
test: /[\\/]node_modules[\\/]/, // 匹配规则
name: 'vendors', // 输出文件名
chunks: 'all' // 覆盖全局 chunks 设置
}
}
}
}
动态加载实践:
javascript
// React 组件懒加载(Webpack 自动代码分割)
const ProductList = React.lazy(() => import(/* webpackChunkName: "product" */ './ProductList'));
// 使用示例(需配合 Suspense)
function App() {
return (
<Suspense fallback={<Spinner />}>
<ProductList />
</Suspense>
);
}