工程化专题之webpack

说说你对前端工程化的理解?为什么要工程化

前端工程化是将软件开发工程学 的理念引入前端开发,通过规范化流程、工具链集成、自动化手段 ,解决复杂项目中的协作、维护、性能等问题,最终实现高效、稳定、可扩展 的研发体系。其核心包括: www.jianshu.com/p/7f2c0a818...

维度 具体表现
模块化 代码按功能拆分(如 ES Module、组件库),降低耦合度
规范化 统一代码风格(ESLint)、提交规范(Commitizen)、目录结构
自动化 构建(Webpack)、测试(Jest)、部署(CI/CD)等流程无需手动干预
可维护性 通过类型系统(TypeScript)、文档生成(Storybook)提升长期迭代效率

原因

指标 工程化影响
开发效率 减少重复劳动(如热更新代替手动刷新),工具链集成节省配置时间
代码质量 静态检查 + 自动化测试提前拦截 Bug,类型系统减少运行时错误
性能表现 构建优化(Chunk 拆分、按需加载)、资源压缩(CSS/JS minify)、缓存策略
团队协作 统一开发环境、规范提交日志,降低新人上手成本
总结

前端工程化不是单纯引入工具,而是通过标准化、自动化、数据化 的手段,将"手工作坊"升级为"现代化工厂"。其本质是用工具约束人,用流程保证质量 ,最终实现可预测、可度量、可持续的交付能力。

与webpack类似的工具还有哪些?区别?

场景 推荐工具 理由
企业级复杂应用 Webpack 大而全 ,丰富的生态,loader,plugin可以满足各种使用场景的
偏向JS库/框架打包 Rollup 输出代码精简,Tree-shaking ,可选的输出格式
零配置简单项目 Parcel 资源编译流程优化,无需复杂配置 (简称0配置) 不支持tree shaking
追求极限构建速度 esbuild Go 语言实现,线程间可以共享内存,性能碾压传统工具
快速原型/现代 SPA Vite 取长补短(用Rollup pro输入输出,用esbuild dev快速构建),按需打包,未来趋势

webpack的配置有哪些

Webpack的配置主要包括以下几个方面‌:

  1. 入口(Entry) ‌:Webpack通过入口点开始打包过程。可以配置单个入口点或多个入口点。例如,可以指定一个或多个JavaScript文件作为入口点‌。
  2. 输出(Output) ‌:配置打包后的文件输出位置和文件名。通常在webpack.config.js文件中设置output对象,包括filenamepath等属性‌。
  3. 加载器(Loaders) ‌:Webpack本身只能理解JavaScript和JSON,加载器允许webpack处理其他类型的文件,如CSS、Images等。例如,使用style-loadercss-loader来处理CSS文件‌。
  4. 插件(Plugins) ‌:插件用于执行范围更广的任务,如bundle优化、资源管理和环境变量注入等。常见的插件包括HtmlWebpackPluginMiniCssExtractPlugin等‌。
  5. 开发服务器(DevServer) ‌:配置开发服务器以提供实时重新加载功能。可以通过webpack-dev-server来实现‌。
  6. 模式(Mode) ‌:Webpack支持两种模式------开发模式(development)和生产模式(production)。不同模式下,Webpack会应用不同的优化策略‌。
  7. 拆分代码(Code Splitting) ‌:通过入口起点、入口起点依赖和运行时依赖等方式拆分代码,以优化加载时间‌15。
  8. 性能优化‌:包括压缩代码、减少文件大小、缓存处理等,以提高应用性能‌。
  9. 跨域请求(CORS) ‌:在开发服务器中配置代理解决跨域问题,通常使用devServer.proxy选项‌。
  10. 自定义配置 ‌:根据项目需求自定义配置项,如环境变量、别名等‌。 **optimization。可以使用optimization.splitChunks和optimization.runtimeChunk配置代码拆分和运行时代码提取等优化策略。
  • externals。用于配置排除打包的模块,例如,可以将jQuery作为外置扩展,避免将其打包到应用程序中。

  • devtool。配置source-map类型。

  • context。webpack使用的根目录,string类型必须是绝对路径。

  • target。指定Webpack编译的目标环境。

  • performance。输出文件的性能检查配置。

  • noParse。不用解析和处理的模块。

  • stats。控制台输出日志控制。

webpack核心原理(也就是webpack做了什么)(webpack介绍)

Webpack是一个开源的JavaScript静态 模块打包工具(Module Bundler),其最核心的功能是解决模块之间的依赖 (模块打包),把各个模块按照特定的规则和顺序组织在一起,最终合并为一个JS文件(有时会有多个)使其打包后的结果能运行在浏览器上​。这个过程就叫作模块打包。其核心目标是解决前端开发中的依赖管理资源优化问题。

为了什么需要webpack? 当应用的规模大了之后,就必须借助一定的工具,否则人工维护代码的成本将逐渐变得难以承受。使用工具可以让开发效率成倍地提升,所谓"工欲善其事,必先利其器"就是这个意思。

为何模块? 在设计程序结构时,把所有代码都堆到一起是非常糟糕的做法。更好的组织方式是按照特定的功能将其拆分为多个代码段,每个代码段实现一个特定的目的。你可以对其进行独立的设计、开发和测试,最终通过接口来将它们组合在一起。这就是基本的模块化思想。

markdown 复制代码
1. 通过导入和导出语句我们可以清晰地看到模块间的依赖关系
2. 模块可以借助工具来进行打包,所以在页面中只需要加载合并后的资源文件,减少了网络开销。
3. 多个模块之间的作用域是隔离的,彼此不会有命名冲突。

核心原理/为什么选择webpack

  1. 模块化支持
    • 统一处理 ES Module、CommonJS AMD等模块化规范 。
  2. 依赖管理
    • 自动解析模块间的依赖关系,避免手动维护加载顺序。
  3. 代码转换
    • 通过 Loader 处理非 JS 文件(如 SASS → CSS → JS 内联)。
  4. 扩展功能
  • 通过插件(Plugin)实现环境变量注入、HTML 生成等高级功能。 生态成熟
  1. 打包优化
    • 代码分割(Code Splitting)、按需加载(Lazy Loading)优化性能。** **
  2. 开发支持
    • 提供热更新(HMR)、Source Map 等提升开发效率。

webpack5 的新特性

  1. 持久化缓存:通过将编译结果缓存到磁盘上,可以显著提高构建速度.

    1. 配置中设置 cache.type:'filesystem' ,可以启用持久化缓存
    2. webpack4 每次编译都需要重新执行构建流程,即使文件没变化也重新构建,所以导致速度慢。
    3. 社区提供 HardSourceWebpackPlugin 实现持久化缓存,5 代是对这功能进行官方支持与优化。
css 复制代码
cache: {
  type: 'filesystem', // 使用文件系统级别的缓存
}
  1. 长缓存优化: 通过文件名哈希和缓存控制头来缓存静态资源,减少服务器负载和加快页面加载速度。

  2. Tree Shaking 优化:提高了对未使用模块的检测能力,从而在打包时排除更多未使用的代码。

  3. 输出文件名优化ContentHash,基于内容粒度变化来判断是否更新文件名

  4. 资产模块:是一种新的模块类型,处理字体、图标、图片等资源。

    • Webpack 4 中需通过 file-loaderurl-loader 处理的文件,5 代不用额外的 Loader 就能用
  5. 模块联邦:通过插件实现不同前端应用见资源共享与集成,跟微前端相关,细节没用过。

webpac的生命周期/构建流程(高频)

webpack打包的整个过程

webpack如何优化编译速度/webpack打包优化

webpack如何减少打包后的体积代码?(高频)

以下是减少 Webpack 打包体积的优化方案,按优先级排序:


一、代码压缩
  1. JS 压缩

    使用 TerserPlugin 压缩 JS 代码:

    javascript 复制代码
    optimization: {
      minimize: true,
      minimizer: [new TerserPlugin()]
    }
  2. CSS 压缩

    使用 css-minimizer-webpack-plugin 压缩 CSS:

    javascript 复制代码
    const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
    optimization: {
      minimizer: [new CssMinimizerPlugin()]
    }

二、Tree Shaking
  1. 启用 ES 模块

    确保使用 import/export 语法,并在 package.json 中设置 "sideEffects": false

  2. 标记未使用代码

    使用 /*#__PURE__*/ 标记无副作用的函数调用,帮助 Tree Shaking 识别。


三、代码分割
  1. 提取公共代码

    使用 SplitChunksPlugin 提取公共模块:

    javascript 复制代码
    optimization: {
      splitChunks: {
        chunks: 'all',
        cacheGroups: {
          vendors: {
            test: /[\\/]node_modules[\\/]/,
            name: 'vendors'
          }
        }
      }
    }
  2. 动态加载

    使用 import() 实现按需加载:

    javascript 复制代码
    import('path/to/module').then(module => {
      module.default();
    });

四、优化依赖
  1. 按需引入

    使用 babel-plugin-import 按需加载组件库(如 Ant Design):

    javascript 复制代码
    plugins: [
      ['import', { libraryName: 'antd', style: 'css' }]
    ]
  2. 移除无用依赖

    使用 webpack-bundle-analyzer 分析并移除未使用的依赖。


五、图片优化
  1. 压缩图片

    使用 image-webpack-loader 压缩图片:

    javascript 复制代码
    {
      test: /\.(png|jpe?g|gif|svg)$/,
      use: [
        {
          loader: 'file-loader',
          options: { name: 'images/[name].[hash:8].[ext]' }
        },
        { loader: 'image-webpack-loader' }
      ]
    }
  2. Base64 内联

    小图片转为 Base64:

    javascript 复制代码
    {
      test: /\.(png|jpe?g|gif)$/,
      use: [
        {
          loader: 'url-loader',
          options: { limit: 8192 } // 小于 8KB 的图片转为 Base64
        }
      ]
    }

六、Gzip 压缩
  1. 启用 Gzip

    使用 compression-webpack-plugin 生成 .gz 文件:

    javascript 复制代码
    const CompressionPlugin = require('compression-webpack-plugin');
    plugins: [
      new CompressionPlugin({
        algorithm: 'gzip',
        test: /\.(js|css)$/
      })
    ]
  2. 服务器配置

    确保服务器支持 Gzip 压缩(如 Nginx 配置 gzip on;)。


七、其他优化
  1. Scope Hoisting

    启用作用域提升,减少闭包:

    javascript 复制代码
    optimization: {
      concatenateModules: true
    }
  2. 移除调试代码

    使用 DefinePlugin 移除开发环境代码:

    javascript 复制代码
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production')
    })

总结

通过 代码压缩Tree Shaking代码分割依赖优化 等策略,可显著减少 Webpack 打包体积,提升应用性能。

webpack proxy工作原理?为什么能解决跨域

多页面打包是什么,如何实现 / webpack怎么实现多入口分模块打包

SPA打包:只有一个 HTML 页面和一个 JS 入口文件

MPA打包:是指在一个项目中,通过配置,构建多个独立的 HTML 页面,每个页面有自己的 JS 入口和依赖。更适合页面间相互独立。实现步骤如下:

  1. 定义入口配置:为每个页面配置一个入口文件,例如 page1 和 page2;
  2. 定义出口配置 :使用 [name].bundle.js 模板字符串,为每个入口文件生成独立的输出文件。
  3. HTML插件配置HtmlWebpackPlugin 插件能为每个页面生成一个 HTML 文件,并将构建后的资源自动注入到这个 HTML 文件中。
  4. 优化配置(可选) :根据需要配置代码分割、压缩等优化功能。
  5. 输出结果:dist 目录中将包含 page1.html、page2.html 以及对应的 page1.bundle.js 和 page2.bundle.js 文件。
css 复制代码
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'production', // 或 'development'
  entry: {
    page1: './src/page1/index.js',
    page2: './src/page2/index.js',
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  // 为每个页面生成独立的 HTML 文件
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'page1.html',
      template: './src/page1/index.html',
      chunks: ['page1'],
    }),
    new HtmlWebpackPlugin({
      filename: 'page2.html',
      template: './src/page2/index.html',
      chunks: ['page2'],
    }),
  ],
};

Chunkhash和Contenthash区别

  • Chunkhash:基于整个代码块(chunk)内容生成哈希值,只要该chunk内的任一模块发生变动,哈希值就会改变‌
  • Contenthash:基于单个文件内容生成哈希值,仅当文件内容变化时,哈希值才会更新‌

打包时Hash码是怎么生成的

一、Hash 码的作用

在文件名中插入 Hash 码,用于标识文件内容。当文件内容变化时,Hash 值改变,触发浏览器缓存失效,确保用户获取最新资源。

二、Hash 码生成规则

Webpack 通过 内容摘要算法(如 MD4)生成哈希值,具体规则由配置的哈希类型决定。

三、三种哈希类型
哈希类型 作用范围 触发变化的因素 适用场景
[hash] 整个项目构建 任何文件内容或配置变化 不推荐使用(全局影响)
[chunkhash] 单个代码块(Chunk) 当前 Chunk 内容或其依赖变化 JS 文件
[contenthash] 单个文件内容 仅文件自身内容变化 CSS/图片/字体等静态资源
四、配置示例
javascript 复制代码
// webpack.config.js
module.exports = {
  output: {
    // JS 文件使用 chunkhash
    filename: '[name].[chunkhash:8].js',
    // 图片使用 contenthash
    assetModuleFilename: 'images/[name].[contenthash:8][ext]'
  },
  plugins: [
    // CSS 文件使用 contenthash
    new MiniCssExtractPlugin({ filename: 'css/[name].[contenthash:8].css' })
  ]
};

五、哈希生成流程图
graph LR A[文件/Chunk 内容] --> B[哈希算法处理] --> C[生成完整哈希] --> D[截断为指定长度] --> E[插入文件名]

总结
  • [hash]:全局哈希,任何改动都会变化(慎用)。
  • [chunkhash]:基于 Chunk 内容,适合 JS 文件。
  • [contenthash]:基于文件内容,适合静态资源。

合理选择哈希类型可精准控制缓存策略,平衡构建性能和用户体验。

随机值存在一样的情况,如何避免

1. webpack.HashedModuleIdsPlugin

该插件可根据模块路径生成稳定的哈希 ID,避免因模块顺序变化而导致 ID 改变,确保每次构建时模块 ID 一致

2. webpack.NamedModulesPlugin(Webpack 4 及以下)或 webpack.NamedChunksPlugin(Webpack 5 及以上)

这两个插件可以使用模块或代码块的路径作为 ID,使 ID 具有可读性和稳定性。

3. terser-webpack-plugin

该插件用于压缩 JavaScript 代码,在压缩过程中可以确保生成的代码具有稳定的哈希值。

总结:通过使用这些插件,可以确保 Webpack 构建过程中生成的随机值(如模块 ID、哈希值等)具有稳定性和唯一性,避免因随机值重复导致的缓存失效等问题。

验证方法

  1. 修改文件内容后重新构建,观察哈希值是否变化
  2. 使用 webpack-bundle-analyzer 检查重复模块
  3. 运行 npx webpack --stats=verbose 查看详细构建日志

通过以上措施可有效避免哈希冲突,确保构建产物的唯一性。

如何对相对路径引用进行优化

webpack和vite的区别都有哪些, 分别适用于什么样的情形

### 为什么 Vite 速度比 Webpack 快?

一、开发模式的差异

  • 当使用 Webpack 时,所有的模块都需要在开发前进行打包 会增加启动时间和构建时间。
  • Vite 则是直接启动,它会在请求模块时再进行实时编译,这种按需动态编译的模式极大地缩短了编译时间,特别是在大型项目中,文件数量众多,Vite 的优势更为明显。

二、底层语言的差异

  • Webpack 是基于 Node.js 构建的,毫秒级别的
  • Vite 则是基于 esbuild 进行预构建依赖。esbuild 是采用 Go 语言编写的,纳秒级别的

因此,Vite 在打包速度上相比Webpack 有 10-100 倍的提升。

三、热更新的处理

  • Webpack 中,当一个模块或其依赖的模块内容改变时,需要重新编译这些模块。

  • Vite 中,当某个模块内容改变时,只需要让浏览器重新请求该模块即可,这大大减少了热更新的时间。

使用webpack构建时有无做一些自定义操作

在使用 Webpack 构建时,你可以通过编写自定义 Loader、自定义插件或者使用 Webpack 的配置选项来实现一些自定义操作。下面为你详细介绍具体的实现方式。

编写自定义 Loader

Loader 用于对模块的源代码进行转换,你可以编写自己的 Loader 来处理特定类型的文件。

编写自定义插件

插件可以在 Webpack 构建过程的不同阶段执行自定义操作,例如在构建完成后生成一个文件清单。

使用 Webpack 配置选项

Webpack 提供了丰富的配置选项,你可以通过配置这些选项来实现自定义操作,例如修改输出文件名、添加环境变量等。

通过以上方法,你可以在 Webpack 构建过程中实现各种自定义操作,满足不同的项目需求。

什么是长缓存?在webpack中如何做到长缓存优化?


一、什么是长缓存?

长缓存(Long-term Caching) 是一种通过优化资源文件名和缓存策略,使浏览器能够长期缓存静态资源(如 JS、CSS 文件)的技术。其核心目标是:

  1. 减少重复加载:用户再次访问时直接从缓存加载资源,提升页面加载速度。
  2. 降低服务器压力:减少不必要的资源请求,节省带宽。

二、长缓存的核心原理
  1. 内容哈希:根据文件内容生成唯一哈希值,内容不变则文件名不变。
  2. 分离稳定代码:将频繁变动的代码与稳定代码分离,避免缓存失效。

三、Webpack 长缓存优化方案

1. 使用 [contenthash]

在文件名中添加内容哈希,确保内容变化时文件名更新:

javascript 复制代码
output: {
  filename: '[name].[contenthash:8].js', // JS 文件名
  chunkFilename: '[name].[contenthash:8].chunk.js' // 异步 chunk 文件名
}

2. 提取第三方库

node_modules 中的依赖单独打包,避免业务代码更新导致缓存失效:

javascript 复制代码
optimization: {
  splitChunks: {
    cacheGroups: {
      vendors: {
        test: /[\\/]node_modules[\\/]/,
        name: 'vendors',
        chunks: 'all'
      }
    }
  }
}

3. 提取 Webpack Runtime

将 Webpack 的运行时代码单独打包,避免因模块 ID 变化导致缓存失效:

javascript 复制代码
optimization: {
  runtimeChunk: 'single'
}

4. 模块 ID 固化

使用 HashedModuleIdsPluginmoduleIds: 'deterministic' 固定模块 ID,避免因模块顺序变化导致缓存失效:

javascript 复制代码
optimization: {
  moduleIds: 'deterministic' // Webpack 5+ 推荐
}

5. 提取 CSS 文件

将 CSS 提取为独立文件,并添加内容哈希:

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:8].css', // CSS 文件名
      chunkFilename: '[name].[contenthash:8].chunk.css'
    })
  ]
};

四、验证长缓存效果
  1. 构建产物分析

    使用 webpack-bundle-analyzer 检查打包结果,确保代码分割合理。

  2. 缓存命中率测试

    修改业务代码后重新构建,观察 vendorsruntime 文件是否未变化。

  3. 浏览器缓存验证

    通过开发者工具的 Network 面板,检查资源是否从缓存加载。


五、注意事项
  1. 避免过度分割
    过多的 chunk 文件会增加 HTTP 请求数,影响性能。
  2. CDN 缓存策略
    确保 CDN 配置支持长缓存(如设置 Cache-Control: max-age=31536000)。
  3. 版本管理
    使用版本号或时间戳管理 HTML 文件,确保用户获取最新资源。

通过以上优化,可实现高效的长缓存策略,显著提升用户体验和服务器性能。

什么是bundle,是什么chunk,什么是module?

  • Module:webpack 里一个概念性内容,每个文件都可以看为一个 module。 js、css、图片等都可以看作 module。

  • Chunk:代码块,webpack 处理代码时候的一个中间态,它表示有一组功能相关的模块的集合。一个 Chunk 可以由多个模块(module)组成

  • Bundle:是 Webpack 构建结果的输出,由一个或多个 Chunk 的合并优化后的结果,最终以文件形式输出,用于在浏览器中加载和执行。

externals

文件监听是什么,怎么用,原理是什么

按需加载如何实现,原理是什么(高频)


一、什么是按需加载?

按需加载(Lazy Loading) 是一种将代码分割为多个小块,在需要时动态加载的技术。其核心目标是:

  1. 减少首屏加载时间:只加载当前页面所需的代码。
  2. 优化资源利用率:按需加载非关键资源,减少带宽消耗。

二、实现方式
1. 使用 import() 动态导入

Webpack 会将 import() 语法自动转换为动态加载的代码块。

示例

javascript 复制代码
// 动态加载模块
button.addEventListener('click', () => {
  import('./module.js').then(module => {
    module.default(); // 调用模块的默认导出
  });
});

打包结果

  • 生成独立的 chunk 文件(如 1.bundle.js)。
  • 在用户点击按钮时动态加载该文件。


2. Vue 中的按需加载

使用 defineAsyncComponent 实现组件的动态加载。

示例

javascript 复制代码
const AsyncComponent = defineAsyncComponent(() =>
  import('./AsyncComponent.vue')
);

三、核心原理
  1. 代码分割

    • Webpack 将 import() 语法标记为动态加载点,生成独立的 chunk 文件。
  2. 运行时加载

    • 在浏览器中通过 JSONPfetch 动态加载 chunk 文件。
  3. 缓存管理

    • 使用 webpackJsonpimport() 的缓存机制,避免重复加载。

四、Webpack 配置
  1. 默认配置

    Webpack 5+ 默认支持动态加载,无需额外配置。

  2. 自定义 chunk 名称

    使用魔法注释指定 chunk 名称:

    javascript 复制代码
    import(/* webpackChunkName: "my-chunk" */ './module.js');
  3. 预加载与预获取

    使用魔法注释优化加载优先级:

    javascript 复制代码
    import(/* webpackPrefetch: true */ './module.js'); // 空闲时预加载
    import(/* webpackPreload: true */ './module.js');  // 高优先级预加载

五、优化建议
  1. 合理分割代码

    • 按路由或功能模块分割代码,避免过度拆分。
  2. 预加载关键资源

    • 对非首屏但关键的资源(如首页轮播图)启用 webpackPreload
  3. 错误处理

    • 捕获动态加载失败的情况:

      javascript 复制代码
      import('./module.js')
        .then(module => module.default())
        .catch(err => console.error('加载失败', err));

六、注意事项
  1. 兼容性

    • import() 语法需要支持 Promise 的浏览器(可通过 @babel/plugin-syntax-dynamic-import 转译)。
  2. 性能监控

    • 使用 webpack-bundle-analyzer 分析 chunk 文件大小,确保合理分割。
  3. SEO 影响

    • 动态加载的内容可能不被搜索引擎抓取,需结合服务端渲染(SSR)优化。

通过按需加载,可显著提升应用性能,优化用户体验。

AMD和CMD

AMD (Asynchronous Module Definition)和CMD (Common Module Definition)的主要区别在于加载方式、依赖声明和适用环境

加载方式
  • AMD ‌:支持异步加载,模块的加载不会阻塞页面其他内容的加载和执行。这种异步加载方式使得AMD尤其适合在浏览器环境中使用,尤其是在Web应用**中‌12。
  • CMD‌:支持同步加载,模块会在遇到时立即执行,不管它是否已经加载完成。这种同步加载方式使得CMD更适合在服务器端环境或需要同步加载的场景中使用‌
依赖声明
  • AMD‌:在定义模块时需要明确列出所有依赖的模块,并将它们作为参数传递给模块的回调函数。这种"依赖前置"的方式使得代码结构清晰,但可能会增加模块间的耦合度‌
  • CMD‌:不需要在定义模块时明确列出所有依赖的模块,而是在需要使用模块时再引入它们。这种"依赖就近"的方式使得代码更加灵活,适合复杂的模块化需求‌。
适用环境
模块规范 适用场景
AMD 浏览器端,适合依赖关系明确、模块数量较少的场景。
CMD 浏览器端和 Node.js,适合依赖关系复杂、模块数量较多的场景。

介绍模块化发展历程

模块化主要作用:抽离公共代码,隔离作用域,避免代码冲突

  1. 无模块化 → 2. IIFE → 3. CommonJS → 4. AMD → 5. UMD → 6. ES6 Module
    最终趋势是 ES6 Module,成为现代 JavaScript 开发的标准。

常用的loader/用过哪些loader

  • babel-loader:将ES6+的代码转换成ES5的代码。

  • css-loader:解析CSS文件,并处理CSS中的依赖关系。

  • style-loader:将CSS代码注入到HTML文档中。

  • file-loader:用于打包文件类型的资源,并返回其publicPath。

  • url-loader:类似于file-loader,但是可以将小于指定大小的文件转成base64编码的Data URL格式

  • sass-loader:将Sass文件编译成CSS文件。

  • less-loader:将Less文件编译成CSS文件。

  • postcss-loader:自动添加CSS前缀,优化CSS代码等。

  • vue-loader:将Vue单文件组件编译成JavaScript代码。

  • source-map-loader: 加载额外的Source Map文件

  • eslint-loader: 通过ESlint 检查js代码

  • cache-loader: 可以在一些开销较大的Loader之前添加可以将结果缓存到磁盘中,提高构建的效率

  • thread-loader: 多线程打包,加快打包速度

如何编写loaders/自定义loader

juejin.cn/post/713820... 详细参考loader编写思路

在 Webpack 中编写 Loader 的核心流程(以同步 Loader 为例):


1. 接收输入:获取源码内容
  • loader支持链式调用,上一个loader的执行结果会作为下一个loader的入参。 根据这个特性,我们知道我们的loader 想要有返回值,并且这个返回值必须是标准的JavaScript字符串或者AST代码结构,这样才能保证下一个loader的正常调用。
javascript 复制代码
// 基础结构
module.exports = function(source, map, meta) {
  // source: 输入内容
  // map: SourceMap
  // meta: 其他元数据
  return transformedSource; // 返回处理后的字符串
}
2. 转换处理:按需求修改源码
  • loader的主要职责就是将代码转译为webpack可以理解的js代码。

    • 根据这个特性,loader内部一般需要通过return / this.callback来返回转换后的结果
  • 单个loader一把只负责单一的功能。

    • 根据这个特性,我们的loader应该符合单一职责的原则,尽量别让单个loader执行太多职责
  • 善于利用开发工具

    • loader-utilsloader-utils 是一个非常重要的 Loader 开发辅助工具,为开发中提供了诸如读取配置、requestString的序列化和反序列化、getOptions/getCurrentRequest/parseQuery等核心接口....等等功能,对于loader的开发十分有用
    • schema--utilsschema-utils是用于校验用户传入loader的参数配置的校验工具,也是在开发中十分有用
  • loader是无状态的

    • 根据此特性,我们不应该在loader保存状态
javascript 复制代码
module.exports = function(source) {
  // 替换操作
  const result = source.replace(/world/g, 'loader');
  // 返回处理后的 JS 代码
  return `export default ${JSON.stringify(result)}`;
}

3. 异步 Loader 写法

处理需要异步操作时(如文件读取):

javascript 复制代码
module.exports = function(source) {
  const callback = this.async(); // 获取异步回调
  setTimeout(() => {
    const result = source.replace(/world/g, 'loader');
    callback(null, result); // 参数:错误, 处理结果
  }, 100);
}

4. 本地测试方法

webpack.config.js 中直接引用本地 Loader:

javascript 复制代码
module.exports = {
  module: {
    rules: [
      {
        test: /\.txt$/,
        use: [
          {
            loader: path.resolve(__dirname, 'loaders/my-loader.js'),
            options: { /* 传参 */ }
          }
        ]
      }
    ]
  }
}

5. 核心特性
功能 实现方式
获取参数 通过 this.getOptions() 获取配置中的 options
处理二进制 设置 raw = true,接收 Buffer 类型输入
Source Map 返回 this.callback(null, result, sourceMap)
缓存优化 通过 this.cacheable(false) 关闭缓存(默认启用)

6. 完整示例(带参数传递)
javascript 复制代码
// my-loader.js
module.exports = function(source) {
  const options = this.getOptions(); // 获取配置参数
  return source.replace(new RegExp(options.target, 'g'), options.replaceWith);
}

// webpack.config.js
{
  loader: path.resolve(__dirname, 'loaders/my-loader.js'),
  options: {
    target: 'foo',
    replaceWith: 'bar'
  }
}

总结

编写 Loader 只需三步:

  1. 接收输入:获取源码内容
  2. 转换处理:按需求修改源码
  3. 返回输出:返回字符串或调用回调

实际开发中可结合 loader-utils 等工具库处理参数和复杂场景。

webpack 如何确定依赖引用顺序

依赖图的构建过程

  1. 入口点:Webpack 从配置的入口点entry开始,从入口文件开始解析。
  2. 递归解析:递归解析每个模块的依赖,找到所有被引用的模块。
  3. 构建依赖图:根据模块之间的依赖关系构建一个依赖图。
  4. 确定顺序:根据依赖图确定模块的引用顺序,确保被依赖的模块先于依赖它们的模块打包。

如何保证众多Loader按照想要的顺序执行?

可以通过enforce来强制控制Loader的执行顺序 (pre 表示在所有正常的loader执行之前执行,post则表示在之后执行)

loader的执行顺序为什么是后写的先执行

Webpack 中 *‌**Loader 的执行顺序是「从右到左」*(配置数组靠后的 Loader 先执行),原因如下:

核心原理:

  1. 链式管道模型

    Loader 处理资源的过程类似管道传输,后一个 Loader 的输入是前一个 Loader 的输出。配置顺序需要直观反映资源逐步加工 的逻辑。
    示例

    less 复制代码
    javascriptCopy Code
    use: ['style-loader', 'css-loader', 'sass-loader']  

    实际流程:

    SCSS → sass-loader(编译为 CSS) → css-loader(解析依赖) → style-loader(注入 DOM)。

一句话总结:

后写的 Loader 先执行,是为了让配置顺序与资源处理的实际步骤一致(如先编译 SCSS → 再处理 CSS → 最后插入 DOM)。

webpack如何配sass,需要配哪些loader

所需的 loader
  • sass-loader :该 loader 依赖 Sass 编译器(如 Dart Sass),它能把 Sass(.sass)或 SCSS(.scss)文件编译成 CSS 文件。
  • css-loader :负责解析 CSS 文件里的 @importurl() 等语句,处理 CSS 模块和 CSS 中的依赖关系,将 CSS 文件转换为 CommonJS 模块。
  • style-loader :会把编译后的 CSS 以 <style> 标签的形式插入到 DOM 中,让样式在页面上生效。
  • mini-css-extract-plugin(可选) :在生产环境中,通常使用该插件将 CSS 提取到单独的文件中,而不是将其内嵌到 JavaScript 代码里,这样有助于提升性能和缓存效率。
配置解释
  1. entryoutput:指定入口文件和输出文件的路径。
  2. module.rules :定义了处理不同类型文件的规则。对于.scss.sass文件,使用style-loader(开发环境)或MiniCssExtractPlugin.loader(生产环境)、css-loadersass-loader来处理。
  3. MiniCssExtractPlugin:在生产环境下,使用该插件将 CSS 提取到单独的文件中。
开发环境与生产环境的区别
  • 开发环境 :使用style-loader将 CSS 内联到 JavaScript 中,这样可以实现热更新,方便开发调试。
  • 生产环境 :使用MiniCssExtractPlugin.loader将 CSS 提取到单独的文件中,以提高性能和缓存效率。

postcss配置

PostCSS 是一个用 JavaScript 编写的工具,用于将 CSS 转换为另一种 CSS。它可以处理诸如添加浏览器前缀、压缩 CSS、使用未来的 CSS 特性等任务。以下为你详细介绍在不同场景下如何配置 PostCSS。

安装依赖

首先,确保你已经安装了 PostCSS 及其相关插件,在项目根目录下的终端中执行以下命令: bash

css 复制代码
npm install postcss postcss-loader autoprefixer cssnano --save-dev
  • postcss:核心库。
  • postcss-loader:用于在 Webpack 中使用 PostCSS。
  • autoprefixer:自动添加浏览器前缀。
  • cssnano:压缩和优化 CSS。
package.json 中配置浏览器列表

为了让 autoprefixer 知道要为哪些浏览器添加前缀,需要在 package.json 中配置 browserslist 字段:

json

json 复制代码
{
    "browserslist": [
        "last 2 versions",
        "> 1%",
        "not dead"
    ]
}

这个配置表示为最近两个版本的浏览器、市场占有率大于 1% 的浏览器以及未停止维护的浏览器添加前缀。

如何配置把js、css、html单独打包成一个文件

在项目根目录下的终端中执行以下命令来安装所需的依赖:

bash

css 复制代码
npm install webpack webpack-cli html-webpack-plugin mini-css-extract-plugin --save-dev
  • webpackwebpack-cli:Webpack 的核心库和命令行工具。
  • html-webpack-plugin:用于生成 HTML 文件,并自动注入打包后的 JS 和 CSS 文件。
  • mini-css-extract-plugin:用于将 CSS 提取到单独的文件中。

loader和plugin有什么区别(高频)

webpack的plugins和loaders的实现原理( webpack里面的插件是怎么实现的) x4(高频)

常用的plugins

如何编写plugins

webpack热更新(HMR)原理(高频)

什么是code spliting?原理

Code Splitting代码分割,是一种优化技术。它允许将一个大的chunk拆分成多个小的chunk,从而实现按需加载,减少初始加载时间,并提高应用程序的性能 。在Webpack中通过optimization.splitChunks配置项来开启代码分割

什么是tree shaking?原理?如何实现


一、什么是 Tree Shaking?

Tree Shaking 是一种通过静态分析移除 JavaScript 中未使用代码的优化技术。其名称源自"摇树"动作------摇掉树上未成熟的果实(未使用的代码)。可以减小打包文件的体积,提高加载性能


二、核心原理
  1. 静态分析

    • 在编译阶段分析代码的 import/export 依赖关系。
    • 识别未被引用的模块或函数。
  2. 标记未使用代码

    • 通过 /*#__PURE__*/ 标记无副作用的函数调用。
    • 结合 package.json"sideEffects" 字段排除副作用模块。
  3. 移除死代码

    • 在压缩阶段(如 Terser)移除标记为未使用的代码。

Tree shaking的工作流程可以分为

1.标记 哪些导出值没有被使用; 2. 使用Terser将这些没用到的导出语句删除

标记的流程如下:

  1. make阶段:收集模块导出变量并记录到模块依赖关系图中

  2. seal阶段:遍历模块依赖关系图并标记那些导出变量有没有被使用

  3. 构建 阶段:利用Terser将没有被用到的导出语句删除


三、实现条件
  1. 使用 ES 模块

    • 代码必须使用 import/export 语法(CommonJS 不支持 Tree Shaking)。
  2. 配置生产模式

    • Webpack 的 mode 设置为 production,默认启用 Tree Shaking。
  3. 标记副作用

    • package.json 中声明无副作用的模块:

      json 复制代码
      {
        "sideEffects": false // 或指定有副作用的文件 ["*.css", "*.scss"]
      }

四、Webpack 配置
  1. 启用 Tree Shaking

    javascript 复制代码
    module.exports = {
      mode: 'production', // 生产模式默认启用
      optimization: {
        usedExports: true, // 标记未使用的导出 启动
        minimize: true     // 压缩时移除未使用代码
      }
    };
  2. 标记无副作用函数

    javascript 复制代码
    /*#__PURE__*/ someFunction(); // 标记为无副作用

五、验证 Tree Shaking 效果
  1. 检查打包结果

    • 使用 webpack-bundle-analyzer 分析打包文件,确认未使用代码被移除。
  2. 查看 Terser 日志

    • 启用 TerserPluginextractComments 选项,查看移除的代码。

六、注意事项
  1. 避免副作用

    • 确保模块的导入不会触发副作用(如全局变量修改)。
  2. 第三方库支持

    • 确保第三方库提供 ES 模块版本(如 lodash-es)。
  3. Babel 配置

    • 避免 Babel 将 ES 模块转换为 CommonJS(设置 modules: false):

      json 复制代码
      {
        "presets": [["@babel/preset-env", { "modules": false }]]
      }

通过以上配置和优化,可有效实现 Tree Shaking,减少打包体积,提升应用性能。

dev-server是怎么跑起来?

  1. 初始化配置

    • 读取 webpack.config.js 中的 devServer 配置(如端口、代理、静态目录等)。
    • 合并 Webpack 的默认配置和用户自定义配置。
  2. 创建本地服务器

    • 基于 Express 框架启动 HTTP 服务,托管静态资源。
    • 使用 webpack-dev-middleware 中间件将 Webpack 的编译结果写入内存(而非磁盘),提升性能。
  3. 绑定 WebSocket 通信

    • 通过 sockjs 或原生 WebSocket 建立浏览器与服务器的长连接,用于推送热更新(HMR)消息。
  4. 启动 Webpack 编译

    • 调用 Webpack 的 API 触发初次编译,生成内存中的打包文件。
    • 监听文件变化,触发增量编译。

``

基础配置

arduino 复制代码
// webpack.config.js
module.exports = {
  devServer: {
    port: 8080,              // 端口
    hot: true,               // 启用热更新
    static: './dist',        // 托管静态目录(优先使用内存文件)
    open: true,              // 自动打开浏览器
    historyApiFallback: true // 支持前端路由(如 React Router)
  }
};

核心运行原理

1. 内存资源托管

2. 热更新(HMR)机制

3.解决跨域:将特定 API 请求转发到后端服务器:

总结

Webpack Dev Server 通过内存编译 + WebSocket 通信 + HMR 运行时 的组合,实现了高效的本地开发体验。理解其原理有助于优化配置(如调整 watchOptions)和解决热更新失效等疑难问题。

babel概念及原理

babel 可以将代码转译为想要的目标代码,并且对目标环境不支持的api 自动 polyfill。而babel 实现这些功能的流程是 解析(parse)-转换(transfrom)-生产(generator),接下来我们就看看每个流程都做了啥工作

  • 解析:根据代码生成对应的AST结构

    • 进行代码分析,将代码分割成token 流(语法单元数组),再根据token 流生成对应的AST
  • 转换:遍历AST节点并生成新的AST节点

  • 生成:根据新的AST生成目标代码

SourceMap 原理(高频)

source map 是将编译打包后的代码映射回源码 可以通过devtool 配置项来设置,还可以通过SourceMapDevToolPlugin实现更加精细粒度的控制

devtool 配置项和 SourceMapDevToolPlugin不能同时使用,因为devtool选项已经内置了这些插件,如果同时使用相当于应用了两次插件

配置 devtool: 'source-map'后,在编译过程中,会生成一个 .map 文件,一般用于代码调试和错误跟踪。

  • 包含了源代码、编译后的代码、以及它们之间的映射关系。

  • 编译后的文件通常会在文件末尾添加一个注释,指向 SourceMap文件的位置。

    • // # sourceMappingURL=example.js.map
  • 当在浏览器开发者工具调试时,浏览器会读取这行注释并加载对应的 SourceMap 文件

报错时,点击跳转。即使运行的是编译后的代码,也能够追溯到原始源代码的具体位置,而不是处理经过转换或压缩后的代码,从而提高了调试效率。

模式 特点 适用场景
eval 最快,但映射信息内联在 eval 中,只能映射到转换后的代码(非原始代码)。 开发环境(快速构建)
cheap-source-map 生成单独的 .map 文件,仅映射行号(不映射列号),速度较快。 开发环境(平衡速度与精度)
source-map 完整独立的 .map 文件,包含行列精确映射,但构建速度较慢。 生产环境(需精确调试)
hidden-source-map 生成 .map 文件,但 Bundle 中不包含引用注释,需手动关联。 生产环境(保护源码隐私)
cheap-module-source-map 类似 cheap-source-map,但映射到 Loader 转换前的源码(如 Babel 前的代码)。 开发环境(需调试原始代码)

这么多的选择,那么我们应该如何使用呢,根据我的实践,我觉得比较好的设置应该是下面这样

  • 开发环境:cheap-module-eval-source-map,生产这种source map速度最快,并且由于开发环境下没有代码压缩,所以不会影响断点调试
  • 生产环境:hidden-source-map,由于进行了代码压缩,所以并不会占用多大的体积

避免在生产中使用 inline-eval- 因为它们会增加 bundle 体积大小 并且降低整体性能

选择原则
  1. 开发环境 :优先速度,选 evalcheap- 系列。
  2. 生产环境 :需调试则用 source-map,否则禁用或选 hidden-source-map
  3. 精度要求 :精确调试选含 source-map 的模式,快速构建选 evalcheap-

跟 Mainfest 的区别

  • SourceMap 主要用于调试目的,让开发者能够在压缩或转译后的代码中追踪到原始代码

  • Manifest 文件用于资源管理,用于优化资源的加载和缓存

如何对bundle体积进行监控和分析

VSCode 中有一个插件 Import Cost 可以帮助我们对引入模块的大小进行实时监测,还可以使用 webpack-bundle-analyzer 生成 bundle 的模块组成图,显示所占体积。

bundlesize 工具包可以进行自动化资源体积监控。

文件指纹是什么?怎么用?

概念

文件指纹是指文件打包后的一连串后缀,如哈希值。

作用

  • 版本管理: 在发布版本时,通过文件指纹来区分 修改的文件 和 未修改的文件
  • 使用缓存: 浏览器通过文件指纹是否改变来决定使用缓存文件还是请求新文件(浏览器可复用本地缓存,提升加载速度)。

种类

  • Hash:和整个项目的构建相关,只要项目有修改(compilation实例改变),Hash就会更新粒度最粗)
  • Contenthash:和文件的内容有关,只有内容发生改变时才会修改
  • Chunkhash:和webpack 构架的chunk有关 不同的entry 会构建出不同的chunk (不同 ChunkHash之间的变化互不影响) javascript

复制

css 复制代码
// webpack.config.js
module.exports = {
  output: {
    filename: 'js/[name].[chunkhash:8].js',      // JS 使用 chunkhash
    chunkFilename: 'js/[name].[chunkhash:8].js',
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css', // CSS 使用 contenthash
    }),
  ],
  module: {
    rules: [
      {
        test: /.(png|jpe?g|gif)$/,
        loader: 'file-loader',
        options: {
          name: 'img/[name].[hash:8].[ext]',     // 图片使用 hash
        },
      },
    ],
  },
};

如何使用

  • JS文件:使用Chunkhash
  • CSS文件:使用Contenthash
  • 图片等静态资源: 使用hash

生产环境的output 为了区分版本变动,通过Contenthash来达到清理缓存及时更新的效果,而开发环境中为了加快构建效率,一般不引入Contenthash

为什么pnpm比npm快

Pnpm 比 npm 快的原因在于其优化的文件存储方式、依赖管理方式以及并行下载能力。 以下是详细介绍:

  • Pnpm 使用基于内容寻址的文件系统来存储磁盘上的所有文件,这意味着它不会在磁盘中重复存储相同的依赖包,即使这些依赖包被不同的项目所依赖。这种存储方式使得Pnpm在安装依赖时能够更高效地利用磁盘空间,同时也减少了下载和安装的时间。

  • Pnpm 在下载和安装依赖时采用了并行下载的能力,这进一步提高了安装速度。

  • Pnpm 还具有一些其他特性,例如节省空间的硬链接和符号链接的使用,这些都有助于提高其性能。

npm run start 的整个过程

以下是 npm run start 的简明执行过程:


1. 解析命令
  • 查找脚本 :在 package.jsonscripts 字段中查找 start 命令。

    json 复制代码
    {
      "scripts": {
        "start": "react-scripts start"
      }
    }

2. 执行脚本
  • 调用命令 :运行 start 对应的命令(如 react-scripts start)。
  • 环境变量注入 :自动注入 NODE_ENV=development(开发环境)。

3. 启动开发服务器
  • 初始化构建工具:调用 Webpack/Vite 等工具,加载配置文件。
  • 编译代码:将源代码打包为浏览器可执行的文件(如 JS、CSS)。
  • 启动本地服务器:通过 Express 或 Webpack Dev Server 托管静态资源。

4. 热更新(HMR)
  • 监听文件变化:实时监控文件修改。
  • 局部更新:通过 WebSocket 推送更新内容,浏览器局部刷新。

5. 打开浏览器
  • 自动访问 :默认打开 http://localhost:3000(端口可配置)。

npm install的执行过程

详细细节copy title dp

执行过程大致如下:

  1. 读取 package.json 文件,该文件列出了项目所需要的依赖。
  2. 根据 package.json 中的依赖信息以及 node_modules 目录状态,npm 会决定哪些模块需要下载和安装。
  3. npm 会查看每个模块的可用版本,并选择符合 package.json 中指定版本范围的最新版本进行安装。
  4. 下载所需模块到本地的 node_modules 目录。
  5. 如果模块包含子模块(package.jsondependenciesdevDependencies 中的模块),则递归执行上述步骤安装这些子模块

常见问题与优化

问题 原因与解决
安装速度慢 使用国内镜像(npm config set registry https://registry.npmmirror.com)或 pnpm
node_modules 体积过大 使用 npm dedupe 减少冗余,或切换到 pnpm(硬链接节省空间)
版本冲突(Peer Deps) 根据警告手动调整版本,或使用 npm install --force 强制覆盖
锁文件冲突 禁止手动修改锁文件,始终通过 npm install 自动更新

总结

npm install 的核心流程是:解析依赖 → 下载包 → 扁平化安装 → 执行脚本 → 生成锁文件

理解这一过程有助于:

  1. 解决依赖冲突问题。
  2. 优化安装速度和体积。
  3. 保证多环境的一致性(通过锁文件)。

eslint概念以及原理

ESLint 概念

ESLint 是一个用于 JavaScript/TypeScript 的静态代码分析工具,用于检测代码中代码质量检查(如未定义变量) 和风格统一。


核心原理

  1. 解析代码为 AST

    将源代码解析为抽象语法树(AST),结构化表示代码逻辑,便于分析。

  2. 遍历 AST 应用规则

    通过预定义的规则(如变量未使用、缩进错误等)检查 AST 节点,识别问题。规则可自定义或通过插件扩展(如 Vue、React 专用规则)。

  3. 报告与修复

    标记问题位置并输出警告/错误,部分问题可通过 --fix 自动修复(如自动校正缩进)。

  4. 配置灵活

    支持全局/项目级配置(如 .eslintrc),可继承共享配置(如 eslint-config-airbnb),集成到编辑器、构建流程中实时反馈。


作用场景

  • 代码质量检查(如未定义变量)
  • 风格统一(如引号、缩进)
  • 最佳实践约束(如避免 eval()
  • 团队协作规范强制执行。

package.json文件中的devDependdencies和dependdencies对象有什么区别

总结

  • dependencies:生产环境依赖,打包时会包含。
  • devDependencies:开发环境依赖,不会打包到最终产物。

正确区分两者可以优化项目体积和构建速度。

什么是CI/CD dp

  • CI(持续集成,Continuous Integration)
    开发者频繁将代码合并到主分支,自动触发构建和测试,确保代码质量。
  • CD(持续交付/部署,Continuous Delivery/Deployent)
    将通过测试的代码自动部署测试或生产环境,快速交付新功能。

Mainfest 文件是什么,有什么用

Mainfest(更新清单),通常是一个 JSON 文件。需要配置 WebpackManifestPlugin 插件 在 Webpack 输出阶段生成,用于记录所有模块及其依赖关系的映射用来管理模块加载、优化浏览器缓存。 包含:

  • 模块标识符: 每个模块都有一个唯一标识符,这些标识符用于在运行时查找和加载模块。
  • Chunk 映射关系:包含 chunk 与包含的模块之间的映射关系,以及 chunk 之间的依赖关系。这有助于运行时确定哪些 chunk 需要被加载。
  • Hash 值: 每个输出文件的 hash 值。有助于浏览器判断文件是否有更新,从而决定是加载缓存中的资源还是重新请求新的资源。
css 复制代码
{
  "main.js": "main.1a2b3c4d5e6f7g8h9i0j.js",
  "vendor.js": "vendor.1a2b3c4d5e6f7g8h9i0j.js"
}

生成的 Manifest 文件可以用于以下场景:

  • 服务端渲染: 在服务端渲染时,可以使用 Manifest 文件来生成正确的脚本标签,确保引用最新的资源。
  • 缓存管理: 通过记录文件的哈希值,确保在文件内容变化时,客户端能够获取到最新的文件,而不是使用缓存的旧文件。
  • 动态加载: 在需要按需加载模块时,可以使用 Manifest 文件来查找模块的路径。

如何在 WebPack 中代码分割/提取一个公共模块

这里方案我们使用 SplitChunksPlugin ,这是 Webpack 的内置插件,用于将公共的依赖模块提取到单独的 chunk 中,减少代码重复、提高加载速度

在 webpack.config.js 文件中,你可以在配置 optimization.splitChunks 选项来指定如何提取公共模块

基本配置

java 复制代码
js
 代码解读
复制代码
module.exports = {
  // 其他配置...
  optimization: {
    splitChunks: {
      chunks: 'all', // 对所有模块进行优化
    }
  }
};

高级配置: 通过cacheGroups自定义分割策略

less 复制代码
js
 代码解读
复制代码
module.exports = {
  // 其他配置...
  optimization: {
    splitChunks: {
      chunks: 'all', // 对所有模块进行优化
      minSize: 20000, // 生成chunk的最小大小(以字节为单位)
      minChunks: 1, // 分割前必须共享模块的最小块数
      maxAsyncRequests: 30, // 按需加载时的最大并行请求数
      maxInitialRequests: 30, // 入口点的最大并行请求数
      automaticNameDelimiter: '~', // 默认情况下,webpack将使用块的来源和名称生成名称(例如vendors~main.js)
      
      cacheGroups: { // 缓存组可以继承或覆盖splitChunks.*的任何选项
        vendors: {
          test: /[/]node_modules[/]/, // 控制哪些模块被这个缓存组选中
          priority: -10 // 一个模块可以属于多个缓存组。优化将优先考虑具有更高优先级的缓存组
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true // 如果当前块包含已经从主束分离出的模块,则将重用它而不是生成新的块
        }
      }
    }
  }
};
  • 提取第三方库为chunk:通过 vendors 缓存组

    • 可以将 node_modules 的模块提取到单独的文件中,这对于提取大型的第三方库(如React, Vue等)特别有用。
  • 提取公共模块为chunk:通过 default 缓存组

    • Webpack 会自动提取,被多个入口共享的模块到一个或多个公共块中。
相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60614 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅5 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅5 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment6 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端
爱敲代码的小鱼6 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax