🚀Webpack 从入门到优化,一文全掌握!

参考资料

webpack.js.org/

核心概念

Webpack 是一个现代 JavaScript 应用程序的模块打包工具,它的核心概念包括以下几个:

  1. 入口 (Entry):

    1. 入口起点指示 webpack 应该使用哪个模块作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出哪些模块和库是入口起点(直接和间接)依赖的。

    JavaScript 复制代码
    module.exports = {
      entry: './src/index.js',
    };
  2. 输出 (Output):

    1. 输出选项指示 webpack 如何以及在哪里输出它所创建的 bundles,以及如何命名这些文件。

    JavaScript 复制代码
    module.exports = {
      output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist'),
      },
    };
  3. 加载器 (Loaders):

    1. 加载器让 webpack 能够处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。加载器可以将所有类型的文件转换为 webpack 能够处理的有效模块。

    JavaScript 复制代码
    module.exports = {
      module: {
        rules: [
          {
            test: /\.css$/,
            use: ['style-loader', 'css-loader'],
          },
        ],
      },
    };
  4. 插件 (Plugins):

    1. 插件用于执行范围更广的任务,包括打包优化、资源管理和注入环境变量等。插件的功能极其强大,可以用来处理各种各样的任务。

    JavaScript 复制代码
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    module.exports = {
      plugins: [
        new HtmlWebpackPlugin({ template: './src/index.html' }),
      ],
    };
  5. 模式 (Mode):

    1. 通过选择 development, productionnone 之中的一个,来设置 webpack 内置的优化。

    JavaScript 复制代码
    module.exports = {
      mode: 'development',
    };
  6. 模块 (Modules):

    1. 在 webpack 里,一切文件皆模块,通过入口文件来开始,并通过一系列的导入或加载请求来进行模块间的连接。

常用Loader

  1. Babel Loader

    1. 用于将 ES6+ 代码转译为 ES5。

    JavaScript 复制代码
    module.exports = {
      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: 'babel-loader',
          },
        ],
      },
    };
  2. CSS Loader 和 Style Loader

    1. css-loader 使你可以使用类似 @importurl() 的方式实现 require() 的功能。

    2. style-loader 将 CSS 插入到 DOM 中。

    JavaScript 复制代码
    module.exports = {
      module: {
        rules: [
          {
            test: /\.css$/,
            use: ['style-loader', 'css-loader'],
          },
        ],
      },
    };
  3. Sass Loader

    1. 将 Sass/SCSS 文件编译为 CSS。

    JavaScript 复制代码
    module.exports = {
      module: {
        rules: [
          {
            test: /\.scss$/,
            use: ['style-loader', 'css-loader', 'sass-loader'],
          },
        ],
      },
    };

常用Plugin

  1. HTML Webpack Plugin (html-webpack-plugin) :

    1. 生成一个 HTML 文件,并自动注入所有的生成的 bundle。

    JavaScript 复制代码
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    module.exports = {
      plugins: [
        new HtmlWebpackPlugin({
          template: './src/index.html',
        }),
      ],
    };
  2. Clean Webpack Plugin:

    1. Webpack 5 中可以通过 output.clean 选项替代 clean-webpack-plugin

    JavaScript 复制代码
    module.exports = {
      output: {
        path: path.resolve(__dirname, 'dist'),
        clean: true, // 每次构建前清理 /dist 文件夹
      },
    };
  3. Mini CSS Extract Plugin (mini-css-extract-plugin):

    1. 提取 CSS 到单独的文件中,而不是在 JavaScript 中内联。需要配合loader使用

    JavaScript 复制代码
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    module.exports = {
      module: {
        rules: [
          {
            test: /\.css$/,
            use: [MiniCssExtractPlugin.loader, 'css-loader'],
          },
        ],
      },
      plugins: [
        new MiniCssExtractPlugin({
          filename: '[name].[contenthash].css',
        }),
      ],
    };
  4. Hot Module Replacement Plugin (webpack.HotModuleReplacementPlugin):

    1. 启用热模块替换(HMR),在运行时更新各种模块,而无需完全刷新。

    2. 在 Webpack 5 中不需要显式添加插件,只需在 devServer 中启用 hot 选项。

    JavaScript 复制代码
    module.exports = {
      devServer: {
        contentBase: './dist',
        hot: true,
      },
    };

构建过程

  1. 初始化阶段
    1. 在这个阶段,Webpack 从配置文件和命令行参数中读取并解析配置。然后,Webpack 根据配置初始化内部状态和插件系统。
    2. 读取配置:从 webpack.config.js 文件或命令行参数中读取配置。
    3. 初始化插件:根据配置文件中的 plugins 选项初始化插件实例。
    4. 确定入口文件:确定项目的入口文件(entry)。
  2. 构建依赖图
    1. Webpack 会从入口文件开始,递归地解析所有依赖,形成一个依赖图。
    2. 解析模块:使用 Loaders 处理非 JavaScript 文件,如 CSS、图片等。每个模块会被递归地解析其依赖。
    3. 创建模块对象:Webpack 为每个模块创建一个模块对象,并保存在内存中。
  3. 模块编译
    1. Webpack 使用相应的 Loaders 将模块的源代码转换为可以在浏览器中运行的 JavaScript 代码。
    2. 处理模块:通过加载器链对模块进行转换。
    3. 生成 AST(抽象语法树):Webpack 将模块源代码转换为 AST,以便进一步处理。
    4. 收集依赖:从 AST 中提取模块的依赖项,并将其加入到依赖图中。
  4. 生成代码块(Chunks)
    1. Webpack 会根据依赖图将所有模块分组,形成不同的代码块(Chunks)。这些代码块最终会被打包成一个或多个输出文件。
    2. 代码拆分:根据配置中的 optimization.splitChunks 等选项,Webpack 会将代码拆分为多个 Chunk。
    3. 生成 Chunk 对象:Webpack 创建 Chunk 对象并将相关的模块添加到其中。
  5. 优化阶段
    1. 优化阶段是确保打包后的代码性能和大小得到提升的关键步骤。Webpack 5 提供了一些内置的优化功能:
    2. 代码压缩:使用 TerserWebpackPlugin 压缩 JavaScript 代码。
    3. CSS 压缩:使用 css-minimizer-webpack-plugin 压缩 CSS 代码。
    4. 代码分割:使用 SplitChunksPlugin 进行代码分割,将公共模块提取到单独的文件中。
    5. Tree Shaking:移除未使用的代码,减小包的大小。
    6. 作用域提升:模块合并,提升运行效率。
  6. 输出阶段
    1. Webpack 将每个代码块转换为一个或多个输出文件,并将其写入到磁盘上。
    2. 生成输出文件:Webpack 根据配置中的 output 选项生成最终的输出文件。
    3. 应用插件:在输出阶段,Webpack 会调用相关的插件(如 HtmlWebpackPlugin)来处理输出文件。

Webpack优化

开发优化

  1. 开启模块热替换(HMR)

    1. 模块热替换可以在不刷新整个页面的情况下更新模块,提高开发效率。
  2. 使用 Source Maps

    1. Source Maps 有助于在浏览器中调试原始源代码,而不是转换后的代码。不同类型的 Source Maps 在性能和详细程度上有所不同。
  3. 优化编译速度

    1. 使用 cacheparallel 选项来加速构建过程。

    YAML 复制代码
    const TerserPlugin = require('terser-webpack-plugin');
    
    module.exports = {
      mode: 'development',
      optimization: {
        minimize: true,
        minimizer: [
          new TerserPlugin({
            cache: true,
            parallel: true,
            sourceMap: true,
          }),
        ],
      },
    };
  4. 使用持久化缓存

    1. Webpack 5 提供了持久化缓存功能,可以显著提高重复构建的速度。

    JavaScript 复制代码
    module.exports = {
      cache: {
        type: 'filesystem', // 使用文件系统缓存
      },
    };
  5. 更快的增量编译

    1. 配置 watchOptions 来优化文件监听,减少不必要的文件扫描。

    JavaScript 复制代码
    module.exports = {
      watchOptions: {
        ignored: /node_modules/,
        aggregateTimeout: 300, // 防抖延迟
        poll: 1000, // 轮询时间
      },
    };

打包优化

  1. 使用生产模式

    1. 生产模式下,Webpack 会自动启用各种优化,如压缩代码和启用 Tree Shaking。

    JavaScript 复制代码
    module.exports = {
      mode: 'production',
    };
  2. 启用 Tree Shaking

    1. Tree Shaking 可以移除未使用的代码,减小打包后的文件大小。确保使用 ES6 模块语法(importexport)。

    JavaScript 复制代码
    module.exports = {
      mode: 'production',
      optimization: {
        usedExports: true,
      },
    };
  3. 代码分割

    1. 使用代码分割技术,将代码拆分为多个文件,以便更好地利用浏览器缓存和加速加载速度。

    JavaScript 复制代码
    module.exports = {
      optimization: {
        splitChunks: {
          chunks: 'all',
        },
      },
    };
  4. 压缩 JavaScript

    1. 使用 TerserPlugin 压缩 JavaScript 代码。

    JavaScript 复制代码
    const TerserPlugin = require('terser-webpack-plugin');
    
    module.exports = {
      optimization: {
        minimize: true,
        minimizer: [new TerserPlugin()],
      },
    };
  5. 压缩 CSS

    1. 使用 css-minimizer-webpack-plugin 压缩 CSS 文件。

    Java 复制代码
    const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
    
    module.exports = {
      optimization: {
        minimize: true,
        minimizer: [
          '...', // 保留默认的 minimizer
          new CssMinimizerPlugin(),
        ],
      },
    };
  6. 持久化缓存

    1. 配置持久化缓存,以便在后续构建中复用编译结果。

    JavaScript 复制代码
    module.exports = {
      cache: {
        type: 'filesystem', // 使用文件系统缓存
        buildDependencies: {
          config: [__filename], // 当配置文件变化时,缓存失效
        },
      },
    };
  7. Bundle 分析

    1. 使用 webpack-bundle-analyzer 插件可视化和分析打包结果,帮助发现和解决性能瓶颈。

    JavaScript 复制代码
    const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
    
    module.exports = {
      plugins: [
        new BundleAnalyzerPlugin(),
      ],
    };
  8. 懒加载和按需加载

    1. 使用动态 import() 语法实现懒加载和按需加载模块,优化首次加载时间。

    JavaScript 复制代码
    // 在你的代码中
    import(/* webpackChunkName: "my-chunk-name" */ './myModule').then(module => {
      // 使用模块
    });
  9. 内联 CSS 和 JavaScript

    1. 在某些情况下,将关键 CSS 和 JavaScript 内联到 HTML 中可以减少 HTTP 请求次数,提高加载速度。

    JavaScript 复制代码
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      plugins: [
        new HtmlWebpackPlugin({
          template: './src/index.html',
          minify: {
            collapseWhitespace: true,
            removeComments: true,
            removeRedundantAttributes: true,
            removeScriptTypeAttributes: true,
            removeStyleLinkTypeAttributes: true,
            useShortDoctype: true,
          },
          inject: 'body',
        }),
      ],
    };
相关推荐
Dragon Wu10 分钟前
前端 下载后端返回的二进制excel数据
前端·javascript·html5
北海几经夏16 分钟前
React响应式链路
前端·react.js
晴空雨44 分钟前
React Media 深度解析:从使用到 window.matchMedia API 详解
前端·react.js
一个有故事的男同学1 小时前
React性能优化全景图:从问题发现到解决方案
前端
探码科技1 小时前
2025年20+超实用技术文档工具清单推荐
前端
Juchecar1 小时前
Vue 3 推荐选择组合式 API 风格(附录与选项式的代码对比)
前端·vue.js
uncleTom6661 小时前
# 从零实现一个Vue 3通用建议选择器组件:设计思路与最佳实践
前端·vue.js
影i1 小时前
iOS WebView 异步跳转解决方案
前端
Nicholas681 小时前
flutter滚动视图之ScrollController源码解析(三)
前端
爪洼守门员1 小时前
安装electron报错的解决方法
前端·javascript·electron