webpack

webpack

webpack是一个用于现代JavaScript应用程序的静态模块打包工具,当webpack处理应用程序时,会在内部构建一个依赖图,此依赖图对应到项目所需的每个模块

_20250426163432.png

从v4.0.0开始,webpack可以不再引入一个配置文件来打包项目,但仍然有着高度可配置性


功能:

  • 模块打包:将项目中的各个模块及依赖打包成一个或多个文件,优化代码结构和加载速度。

  • 按需加载:通过代码拆分,将不同模块分成小包,只在需要时加载,减少初次加载时间。

  • 资源管理:通过各种Loaders和Plugins处理样式、图片、字体等各种静态资源,支持自动优化。

  • 开发友好:提供热更新实时重载等功能


核心:

  • 入口entry:Webpack 构建的起点,通常指向应用的主文件

  • 输出output:Webpack 打包后的文件存放位置与文件名配置

  • 加载器loaders:用于处理非JavaScript 文件(如 CSS、图片)的工具,通过加载器可以将这些资源转为可打包模块

  • 插件plugins:Webpack 功能扩展工具,用于优化、注入变量等


概念:Webpack 从入口文件开始,收集所有的 module,将其按照依赖关系和分割规则组织成 chunk,对 chunk 进行优化和压缩,最终生成 bundle 文件

  • module模块:是整个应用的基本组成部分,一切在项目中被引入的文件对于webpack来说都是一个模块

  • chunk代码块:打包过程中,一组module 的集合,根据文件间的依赖关系主要有三种类型

    • entry chunk:包含 webpack runtime 和模块依赖关系

    • async chunk:异步加载的模块

    • runtime chunk:运行时代码

  • bundle打包结果:是最终输出的一个或多个打包好的文件,是chunk经过压缩、合并等处理后的产物。这些文件会在览器中被直接加载


打包构建流程

  • 初始化:

    • 从配置文件和 Shell 语句中读取合并参数

    • 实例化 Compiler 对象(全局单例,负责把控整个打包构建流程,包含完整的webpack配置信息,全局只有一个),加载所有配置的插件

    • 执行 compiler.run() 开始编译

  • 编译阶段:

    • 根据配置中的 entry 找出所有入口文件

    • 调用 Loader 对模块进行转换

    • 通过 AST 分析模块依赖,递归本步骤直到所有入口依赖的文件都经过处理

    • 使用 Module 和 Dependency 管理代码模块之间的关系

  • 输出阶段:

    • 把模块组合成 Chunk

    • 把 Chunk 转换成文件,输出到文件系统中

    • 根据配置确定输出的路径和文件名


安装

npm install --save-dev webpack  //安装最新版
npm install --save-dev webpack@<version> //安装指定版本
npm install --global webpack@4.0.0  //全局安装
npm install --save-dev webpack-cli@3.3.12  //安装4+以上版本还需要另外安装CLI
npm i webpack@4.0.0 webpack-cli@3.3.12 --save-dev

安装完毕后会生成:package-lock.json ,把webpack所有的依赖包(依赖关系)全部扁平化出来


打包

不使用配置文件:

npx webpack ./src/index.js  -o ./dist   // 把scr/index.js打包到dist文件夹中
  • entry file:入口文件的路径,本文中是./src/index.js的路径

  • destination for bundled files :打包后存放的路径

使用配置文件:

npx webpack --config webpack.config.js

根目录创建webpack.config.js 文件

const path = require('path'); //path是node中自带的包,表示处理当前文件的目录

module.exports = {
  mode: 'development',
  // 入口文件配置
  entry: {
    main: './src/main.js',
   // index:'./src/index.js' //多入口
  },
  // 出口文件配置
  output: {
    path: path.resolve(__dirname, 'dist'), //把dist目录解析为绝对路径;__dirname表示全局变量
    filename: 'index.js', //单入口
 //   filename: '[name].js', //多入口
  },
  // 模块:例如解读CSS,图片如何转换,压缩
  module: {},
  // 插件:用于生产模板和各项功能
  plugins: [],
  // 配置webpack开发服务功能
  devServer: {}
};
  • path:Node.js Path模块

  • path.resolve:将文件转化为绝对路径

  • __dirname:Node.js中的全局变量,指向当前文件的所在目录

入口entry是查找依赖关系的起点(内部依赖图的开始),进入入口起点后,webpack会找出哪些模块和库是入口起点的依赖


loader模块

模块主要运用各种loader用于对模块的源代码进行转换,将sass、less或ES6/TS编译为HTML可以识别的CSS、JS等,或者进行一些代码、图片的压缩等处理

通过配置module.rules ,来处理某些类型的文件

loader中的执行顺序是从右到左,支持链式调用 ,如:use:['style-loader','css-loader'] 先执行css-loader再执行style-loader

noParse过滤不需要解析的文件

rules :设置解析规则数组

  • {test:xxx} :匹配特定条件,一般提供一个正则表达式或正则表达式数组

  • {include:xxx} :匹配特定条件,一般提供一个字符串式或字符串数组

  • {exclude:xxx} :排除特定条件,一般提供一个字符串式或字符串数组

  • {loader:[xxx] || [xxx]} :解析需要的loader,一般提供一个字符串式或字符串数组


常用loader

  • style-loader :将CSS 内容作为内联样式嵌入到 HTML 文件标签中的<style>将解析后的CSS内容添加到页面的DOM中

    修改 CSS 后会自动更新页面样式而不刷新整个页面(热更新时)——开发环境

    使用MiniCssExtractPlugin 提取CSS到单独文件中,优化加载性能、减少JS文件体积——生产环境

  • css-loader :解析CSS文件将CSS内容转化为JS模块 ,如果有@importurl() 引入的CSS文件会继续递归加载处理

  • sass-loader:负责将Sass文件转换为CSS

  • less-loader:负责将less文件转换为CSS

  • vue-loader:用于处理vue单文件组件

  • html-loader:用于导入HTML文件,并将其中的资源作为依赖处理

  • ts-loader:负责将TS文件转换为JS

  • babel-loader:将ES6+的JS代码转化为浏览器兼容的ES5代码

  • file-loader:将图像文件复制到输出目录,并返回其URL(大图)避免生成过大的JS文件

  • url-loader :类似于 file-loader,但支持将小图像转换为Base64 格式,嵌入到JavaScript 中。可以通过配置设置大小阈值,超过该值的图像将使用 file-loader 处理

  • responsive-loader :根据不同的视口大小生成多种尺寸的图像,适合响应式设计。支持自动生成适合不同屏幕的图片格式


Plugin插件

项目中的JS文件通过配置的插件进行解析

插件是用来拓展webpack功能,会在构架过程中生效,执行相关任务

区别

  • loader是在打包构建过程中处理源文件的(JSX、SCSS、LESS)一次处理一个module.rules中配置

  • 插件并不直接操作单个文件,直接对整个构建过程起作用plugins数组中配置


plugin安装完毕后需要进行引入配置

例:

  • 安装npm i html-webpack-plugin

  • 引入const HtmlWebpackPlugin=require('html-webpack-plugin')

  • 配置

    plugins: [
        new webpack.ProgressPlugin(),
        new HtmlWebpackPlugin({ template: './src/index.html' }),
      ],
    

常用插件

  • HtmlWebpackPlugin自动生成一个HTML文件,并自动将打包好的JS/CSS文件插入到这个HTML中

    支持配置一个 minify 对象,用来配置压缩HTML

     module.export = {
       plugins: [new HtmlWebpackPlugin({// 动态⽣成 html ⽂件
         template: "./index.html",
          minify: {// 压缩HTML
           removeComments: true, // 移除HTML中的注释
           collapseWhitespace: true, // 删除空⽩符与换⾏符
           minifyCSS: true // 压缩内联css
         },
       })
       ]
     }
    

  • CleanWebpackPlugin:每次构建前会删除dist目录下的旧文件,确保输出文件夹干净

  • MiniCssExtractPlugin将CSS从JS文件中提取到单独的文件中,从而减少CSS文件的内联,优化浏览器加载性能

    默认webpack会把CSS内嵌到JS中,MiniCssExtractPlugin可以将CSS从JS中提取出生成一个独立的css文件

    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
    
    module.exports = {
        module: {
            rules: [
                {
                    test: /\.css$/,
                    use: [
                        // 提取成单独的⽂件
                        MiniCssExtractPlugin.loader,
                        'css-loader',
                    ],
                    exclude: /node_modules/,
                },
            ],
        },
        plugins: [
            new MiniCssExtractPlugin({
                // 定义输出⽂件名和⽬录
                filename: 'asset/css/main.css',
            }),
        ],
        optimization: {
            minimize: true,
            minimizer: [
                // 压缩 cssnew CssMinimizerPlugin({}),
            ],
        },
    };
    

  • OptimizeCSSAssetsPlugin :压缩CSS代码

  • ImageMinimizerPlugin:减小图片文件大小

  • TerserWebpackPlugin: 压缩JS代码,是webpack4以及上版本中默认的压缩插件

    const TerserPlugin=require("terser-webpack-plugin")
        optimization:{
          minimize: true,
    	  minimizer:[new TerserPlugin({}),// 显示配置
          ],
        }
    

  • CopyWebpackPlugin:可以将静态资源从一个目录复制到另一个目录

  • ProvidePlugin :自动加载模块,不需要在每个文件中显式引入,可以在整个应用中提供全局变量

  • DefinePlugin:用于创建全局常量,通常用于设置不同环境下的配置(开发环境/生产环境)

  • EnvironmentPlugin :将process.env中的环境变量注入到代码中

  • SplitChunksPlugin将共享的库和模块提取到独立的文件中,减少页面初次加载时的体积

    可以通过cacheGroups来分离第三方库和应用中的公共模块

    • vendor:将 node_modules 中的模块提取到一个独立的文件

    • common:将多个模块中共享的代码提取到一个文件

    optimization:{
      splitChunks:{
        chunks:'all',
          cacheGroups:{
            vendor:{
              test:/[\\/]node_modules[\\/]/,
              name:'vendor',
              chunks:'all',
               priority:10, //确保vendor优先提取
            },
            common:{
            name:'common', //公共代码的文件名
            minSize:3000, //最小文件大小
            minChunks:2, //至少被2个模块共享的代码才会被提取
          }
          }
           
      }
    }
    

  • HotModuleReplacementPlugin: 开发时可以通过热模块替换(HMR)避免刷新整个页面

  • BundleAnalyzerPlugin:分析构建产物的大小,有助于优化打包结果

    plugins:[
      new webpack.DefinePlugin({
        'process.env.NODE_ENV':JSON.stringify('production')
      })
    ]
    

HMR与Live-Reload

  • Live-Reload:开发服务器会监控文件变化,当文件变化时,会通知浏览器重新加载整个页面

    原理:主要通过监控文件系统上的变化,当文件发生变化时,触发浏览器的刷新请求。
    它一般依赖于开发服务器,开发服务器会监听源文件的更改(例如,通过 webpack-dev-server或其他工具)。当文件被修改时,服务器会通知浏览器进行刷新。

    优点:实现简单、开箱即用,支持所有类型的文件修改。

    缺点:每次修改都会刷新整个页面,状态丢失,页面加载时间较长。

    更适合简单应用或纯前端项目

    devServer:{
        contentBase: './dist',
        liveReload:true
    }
    


  • HMR:它只会替换更新的模块,而不需要重新加载整个页面

    原理:HMR 通过 Webpack 或其他模块打包工具集成,基于模块系统,它会监控每个模块的变化。当某个模块发生变化时,只替换该模块,而不重新加载整个页面,通常需要通过 WebSocket服务器推送的方式来实现。

    优点:页面不会完全刷新,能够保留应用状态。对于大型应用来说,HMR 能显著提高开发效率。

    缺点:实现相对复杂,对于一些变化(例如:改变了模块之间的依赖关系,或大规模改动)可能无法完美替换,依然需要刷新。

    更适合大型应用、复杂前端框架

    devServer:{
      hot:true,
    },
      plugins:[
        new webpack.HotModuleReplacementPlugin()
      ]
    

提升热跟新效率

  • 减少不必要的文件监听:可以通过配置 watchOptions ignore 来忽略一些变化频率高且不需要监听的文件,如node_modules

    watchOption:{
    	ignored: /node_modules/
    }
    
  • 优化模块解析:添加resolve中的aliasextensions减少Webpack 在解析模块时的搜索范围,可以显著加快打包速度

    resolve:{
      alias:{
        '@components': path.resolve(__dirname,'src/components')
      },
        extensions:['.js','.jsx','.json','.css']
    }
    

  • 使用热更新插件:使用如webpack-dev-serverwebpack-hot-middleware等工具,搭配react-hot-loadervueloader等插件,可以实现更高效的热更新

  • 开启缓存:利用 Webpack 的cache功能,避免每次重新构建都需要从头开始,极大提高构建速度

    webpack4+版本内置了一些缓存机制,开启缓存:

    cache:{
      type:'filesystem'
    }
    

  • 分离开发和生产配置: 在开发环境中尽量少用或不用代码压缩、文件优化等耗时操作,保留这些优化仅在生产环境中执行

    使用webpack-merge 将开发和生产环境的配置文件分开

    const { merge } = require('webpack-merge');
    const commonConfig = require('./webpack.common');
    
    const devConfig = merge(commonConfig, {
        mode: 'development',
        devtool: 'inline-source-map'
    });
    
    const prodConfig = merge(commonConfig, {
        mode: 'production',
        optimization: {
            minimize: true
        }
    });
    
    module.exports = process.env.NODE_ENV === 'production' ? prodConfig : devConfig;
    

插件原理

通过使用 Tapable 库实现事件触发机制,插件可以在 Webpack 构建生命周期的不同阶段挂钩,执行特定的任务。

  • Webpack 使用 Tapable 来创建钩子(hooks),这些钩子允许插件在构建过程的特定时机插入逻辑

    • 同步钩子SyncHook:按顺序执行

    • 异步钩子:

      • AsyncSeriesHook:异步钩子,按顺序执行

      • AsyncParallelHook:异步钩子,并行异步执行

  • 插件通过定义一个包含 apply 方法的类来实现。apply 方法接收一个 compiler 对象(包含了所有的构建配置和状态)

  • 插件在 apply 方法中使用 compiler 对象上的钩子,注册回调函数,在构建过程中执行自定义逻辑

class MyPlugin {
  apply(compiler) {
    compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
      // 在 emit 阶段执行特定逻辑
      console.log('This is my custom plugin!');
      callback();
    });
  }
}

module.exports = MyPlugin;

开发配置

const path=require('path')
module.exports = {
  devServer: {
    contentBase: path.join(__dirname, 'dist'),
    compress:true, //gzip压缩
    port: 3000,
    open: true,
    https:true
    host:'0.0.0.0', //ip地址
    proxy:{
      'api':{
        target:'http://localhost:3000', //代理地址
    	changeOrigin:true
        pathRewrite:{'^/api':''}
      }
    }, 
      watchOption:{  //进行文件监控
        poll:1000, //每秒检查一次变更
        igonred: /node_modules/
      },
      clientLogLevel:'info' //输出日志,其他可选值:warning、error
  }
};

启动webpack dev server:npx webpack serve

运行机制

服务端流程:

  1. 启动 webpack-dev-server,建立 websocket 连接

  2. 监听文件变化,触发重新编译

  3. 编译完成后,生成新的 hash 值

    output:{
    	path:path.resolve(__dirname,'dist')
        filename:'[name].[hash].js'      //整个项目构建相关
        filename:'[name].[chunkhash].js' //和打包的chunk有关,不同的入口生成不同的chunkhash
        filename:'[namel.[contenthash].js //根据文件内容来定义hash
    }
    
  4. 推送更新消息到客户端

客户端流程:

  1. 接收服务端消息

  2. 对比新旧模块 hash

  3. 通过 JSONP 请求最新模块代码

  4. 执行模块更新回调


性能优化

减少搜索范围

  • 使用 resolve.modules 指定模块搜索目录

  • 配置 resolve.alias 创建路径别名

  • 合理使用 resolve.extensions 配置


代码分割

通过动态导入或入口配置,将应用拆分成多个小块,按需加载,提高首次加载速度。

module.exports = {//...
   optimization: {
     splitChunks: {
       chunks: 'all', // 值有 all拆分所有类型模块;async拆分import()动态导入的模块; initial拆分入口文件中引入的模块
       minSize: 20000, // ⽣成 chunk 的最⼩体积(以 bytes 为单位)。
       minRemainingSize: 0,
       minChunks: 1, // 拆分前必须共享模块的最⼩ chunks 数。
       maxAsyncRequests: 30, // 按需加载时的最⼤并⾏请求数。
       maxInitialRequests: 30, // ⼊⼝点的最⼤并⾏请求数。
       enforceSizeThreshold: 50000,
      cacheGroups: {
        defaultVendors: {
        test: /[\/]node_modules[\/]/, //第三⽅模块拆出来
        priority: -10,
        reuseExistingChunk: true,
        },
      util.vendors: {
        test: /[\/]utils[\/]/, //公共模块拆出来
        minChunks: 2,
        priority: -20,
        reuseExistingChunk: true,
      },
      },
    },
  },
};

资源压缩

使用 TerserWebpackPlugin 对 JavaScript 进行压缩(生产模式自动开启),使用 css-minimizer-webpack-plugin 压缩 CSS,减少文件体积。


图片优化

使用 image-webpack-loader 压缩图片,降低加载时间,改善用户体验。

module.exports = {module: {
 rules: [
 {
 test: /\.(png|jpg|gif|jpeg|webp|svg)$/,
 use: ["file-loader",
 {
 loader: "image-webpack-loader",
 options: {
 mozjpeg: {
 progressive: true,
 },
 optipng: {
 enabled: false,
 },
 pngquant: {
 quality: [0.65, 0.9],
 speed: 4,
 },
 gifsicle: {
 interlaced: false,
 },
 },
 },
 ],
 exclude: /node_modules/, //排除 node_modules ⽬录
 },
 ]
 },
 }

其他图片处理加载器:

  • file-loader:将图像文件复制到输出目录,并返回其URL(大图)避免生成过大的JS文件

  • url-loader :类似于 file-loader,但支持将小图像转换为Base64 格式,嵌入到JavaScript 中。可以通过配置设置大小阈值,超过该值的图像将使用 file-loader 处理

  • responsive-loader :根据不同的视口大小生成多种尺寸的图像,适合响应式设计。支持自动生成适合不同屏幕的图片格式


预加载和预取

使用 Webpack 的webpackPrefetchwebpackPreload提高资源加载效率。


缓存管理

设置合适的缓存策略,通过 hash 文件名管理缓存,避免用户下载过期资源。

output:{
    filename: '[name].[contenthash].js',
    chunkFilename:'[name].[contenthash].js'
}

打包缓存优化

使用 cache-loaderhard-source-webpack-plugin 对打包结果进行缓存


优化依赖

定期检查,使用npm prune删除不必要的依赖


Tree Shaking

通过 ES6 模块(import/export)的静态分析,去除未使用的代码,减小打包后的体积 (import必须放在模块顶层

CommonJS:动态导入,运行时加载,不支持tree-shaking,可以放在代码任何位置,导入用require,导出用module.exports/exports(导入导出都是值的拷贝

依赖于ES6模块的静态结构特性,能够在编译时确定模块的依赖关系,以此识别出哪些代码未被使用

module.exports={
  mode:'production', //生产模式自动启用
  optimization:{
    usedExports:true //启用Tree shaking
  }
}
  • 生产模式下默认开启

  • 仅适用于ES6模块

  • 只能处理模块级别,不能处理函数级别的冗余

  • 只能处理JS相关冗余代码,不能处理CSS冗余代码(可以通过purgecss-webpack-plugin对CSS进行tree shaking)

    const path = require("path");
      const PurgecssPlugin = require("purgecss-webpack-plugin");
     const glob = require("glob"); // ⽂件匹配模式module.exports = {//...
     plugins: [
     ...new PurgeCSSPlugin({
     paths: glob.sync(`${PATH.src}/**/*`, { nodir: true }),
     })
     ],
     };
    

按需加载

不需要一次性加载所有的 JS 文件,而应该在不同阶段去加载所需要的代码。

懒加载路由可以打包到一个 chunk 里面。比如某个列表页和编辑页它们之间存在相互跳转,如果对它们拆分成两个import() JS资源加载模块,在跳转过程中视图会出现白屏切换过程

在跳转期间,浏览器会动态创建 script 标签来加载这个 chunk 文件,在这期间,页面是没有任何内容的。所以一般会把路由懒加载打包到一个chunk 里面

注意:动态导入 import() 一个模块,这个模块就不能再出现被其他模块使用同步import 方式导入,否则会造成动态import()失效


gzip

实现对资源进一步压缩

  • 当用戶访问 web 站点的时候,会在请求头中设置accept-encoding:gzip,表明浏览器是否支持 Gzip

  • 服务器在收到请求后,判断如果需要返回 Gzip 压缩后的文件,那么服务器就会先将JS\CSS 等其他资源文件进行Gzip 压缩后再传输到客戶端,同时将响应头设置 content-encoding:gzip

    一般情况下我们并不会让服务器实时 Gzip 压缩,而是利用 webpack 提前将静态资源进行 Gzip 压缩,然后将 Gzip 资源放到服务器(compression-webpack-plugin 实现)

  • 反之,则返回源文件。

  • 浏览器在接收到服务器返回的文件后,判断服务端返回的内容是否为压缩过的内容,是的话则进行 解压操作。,当请求需要的时候直接将 Gzip 资源发送给客戶端


作用域提升

Scope Hoisting 可以让 webpack 打包出来的代码文件体积更小,运行更快

在开启 Scope Hoisting 后,构建后的代码会按照引入顺序放到一个函数作用域里,通过适当重命名某些变量以防止变量名冲突,从而减少函数声明和内存花销

需要注意: Scope Hoisting 需要分析模块之间的依赖关系,所以源码必须采用 ES6 模块化语法

只需要在 plugins 里面使用即可,或者直接开启生产环境也可以让作用域提升生效

module.exports = {
  //⽅式1
 mode: 'production',
 //⽅式2
 plugins: [// 开启 Scope Hoisting 功能new
webpack.optimize.ModuleConcatenationPlugin()
 ]
 }

构建工具区别

vite

  • 基于原生 ES 模块,使用浏览器支持的 import,在旧浏览器中需要polyfill(一种用于在旧版浏览器或环境中实现现代 Web 特性的代码。它通过模拟新 API 的行为,为旧浏览器提供功能上的替代实现,从而解决浏览器兼容性问题)

  • 开发时不打包,使用按需加载

  • 适合现代浏览器,支持 HMR

  • 开发启动快,热更新速度快,构建速度快,使用rollup打包,支持ES6+特性

webpack

  • 功能强大:能处理各种文件类型,如支持 JavaScript、Css、SASS、LESS图片等多种资源的打包。

  • 模块化和插件生态:拥有广泛的plugin和loaders 生态,几乎能满足所有前端构建需求,且支持各种plugin和loaders来处理不同类型的文件。

  • 灵活性:配置非常灵活,可以满足各种复杂的需求,如代码分割、懒加载、热更新、树摇等

  • 适用于复杂的应用程序、企业级项目,但是配置相对复杂,在大规模应用中构建速度可能较慢

  • 初次构建较慢,增量构建较快


rollup

  • 专注于 ES 模块:Rollup 主要是为现代 JavaScript(尤其是ES6 模块)打包而设计的,特别适合用于构建库和组件。

  • 优化效果好:在打包时可以更好的做Tree Shaking(树摇),可以移除未使用的代码,从而生成更小的打包文件。

  • 输出格式多样:支持多种输出格式,如CommonJS、ESM、IIFE、UMD 等。

  • 适用于构建JS库,对模块化支持友好

  • 在构建速度上比webpack快

    • 采用增量构建技术,只对修改过的模块进行重新打包

    • Rollup对 ES6 模块进行了深度优化,能够更高效地进行静态分析和代码分割。它通过静态分析确定哪些代码是真正需要的,从而更有效地移除未使用的代码;Webpack:由于其处理的模块类型更多,且需要处理复杂的依赖关系,在代码分析和优化上可能不如 Rollup 高效

  • 相比于webpack,插件生态较弱,配置的灵活性较差,不适合大型单页应用


Parcel

  • 零配置:开箱即用,无需任何配置,可以自动检测项目中的依赖,自动进行打包

  • 构建速度快:利用多核 CPU 进行并行构建,特别适用于快速开发和原型设计

  • 内置支持类型:Parcel内置支持TypeScript、JSX、SASS 等常见的前端技术,无需额外安装loader或插件

  • 适合小型项目或快速原型开发

  • 相比Webpack,插件和社区支持较少,缺乏精细化控制,不能满足某些复杂的定制需求。


Grunt

  • 基于任务的构建工具,通过配置任务来完成文件的压缩、合并、转译等工作,更偏向于通过配置来进行任务管理

  • 配置简单,任务定义明确,适合简单的自动化操作

  • 插件丰富,几乎所有常见的构建任务都可以找到现成的插件。易于集成到现有项目中,尤其是较小的项目

  • 但性能较差,任务是顺序执行的,不能并行执行任务,效率较低。任务定义过于单一,不支持现代前端开发中的模块化和组件化需求。相较于 Gulp 和 Webpack,灵活性较差


Gulp

  • 流式构建工具,依赖于 Node.js 流的特性,通过管道(pipe)将任务链接起来,通过 JavaScript 代码来描述任务,相比于 Grunt 的配置文件,Gup 提供了更大的灵活性。

  • 支持任务并行执行,性能更好

  • 使用流处理数据,避免了大量的临时文件,提高了构建效率

  • 配置灵活,但相对复杂,支持通过 JavaScript 代码来编写任务,灵活性较高。

webpack生命周期

webpack使用Tapable库来管理这些生命周期的钩子,插件可以通过这些钩子在特定阶段执行自定义逻辑

  • 初始化阶段:解析配置文件,初始化各种插件和加载器,并创建 Compiler 对象

  • 编译阶段:从入口开始,递归解析和构建依赖关系图 (每个模块都会被解析为一个节点,模块之间的依赖关系作为边)

  • 构建模块阶段:处理每个模块的依赖,并将其转化为内部表示;包括对模块的解析、加载和转换

  • 优化阶段:webpack进行各种优化操作,如代码分割、Tree Shaking等

  • 生成阶段:根据优化后的模块生成最终的输出文件,包括对代码的压缩和其他生成操作

  • 输出阶段:将生成的文件写入指定的输出目录中


  • beforeRunrun :在编译开始之前
  • compilecompilation :在编译创建时
  • emit :在生成输出文件之前
  • done :在编译完成时
posted @ 2025-04-27 22:02  原语  阅读(15)  评论(0)    收藏  举报