刷刷题17(webpack)

bundle文件压缩

一、Bundle 核心定义

Bundle(捆绑) 是将多个前端代码文件(JS/CSS/图片等)合并为少数文件的技术,核心作用:

  • 🚀 减少网络请求(浏览器加载 1 个文件 vs 100 个文件)
  • 📦 管理依赖关系(自动处理模块导入导出)
  • 🔧 优化静态资源(如删除未使用代码)

二、前端压缩代码原理

在 Bundle 基础上进行 代码压缩(Minify),实现方式:

  • 删除空格/注释
  • 缩短变量名(如 userDataa
  • 简化语法(如 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()));
  1. 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()));
  1. 压缩后的代码(体积减少 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>
  );
}
相关推荐
@大迁世界31 分钟前
构建 Next.js 应用时的安全保障与风险防范措施
开发语言·前端·javascript·安全·ecmascript
IT、木易2 小时前
ES6 新特性,优势和用法?
前端·ecmascript·es6
is今夕2 小时前
postcss.config.js 动态配置基准值
javascript·vue.js·postcss
青茶绿梅*22 小时前
500字理透react的hook闭包问题
javascript·react.js·ecmascript
计算机软件程序设计2 小时前
vue和微信小程序处理markdown格式数据
前端·vue.js·微信小程序
指尖时光.2 小时前
【前端进阶】01 重识HTML,掌握页面基本结构和加载过程
前端·html
前端御书房2 小时前
Pinia 3.0 正式发布:全面拥抱 Vue 3 生态,升级指南与实战教程
前端·javascript·vue.js
NoneCoder2 小时前
JavaScript系列(84)--前端工程化概述
前端·javascript·状态模式
晚安7202 小时前
idea添加web工程
java·前端·intellij-idea