工程化专题之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 会自动提取,被多个入口共享的模块到一个或多个公共块中。
相关推荐
冴羽3 分钟前
SvelteKit 最新中文文档教程(3)—— 数据加载
前端·javascript·svelte
百万蹄蹄向前冲20 分钟前
组建百万前端梦之队-计算机大学生竞赛发展蓝图
前端·vue.js·掘金社区
云隙阳光i33 分钟前
实现手机手势签字功能
前端·javascript·vue.js
imkaifan1 小时前
vue2升级Vue3--native、对inheritAttrs作用做以解释、声明的prop属性和未声明prop的属性
前端·vue.js·native修饰符·inheritattrs作用·声明的prop属性·未声明prop的属性
觉醒法师1 小时前
HarmonyOS NEXT - 电商App实例三( 网络请求axios)
前端·华为·typescript·axios·harmonyos·ark-ts
Danta1 小时前
HTTP协议版本演进:从HTTP/0.9到HTTP/3的高分面试回答
前端·网络协议·面试
柠檬树^-^2 小时前
app.config.globalProperties
前端·javascript·vue.js
太阳花ˉ2 小时前
react(一):特点-基本使用-JSX语法
前端·react.js
赵大仁2 小时前
深入解析 React Diff 算法:原理、优化与实践
前端·react.js·前端框架
1024小神2 小时前
vue/react/vite前端项目打包的时候加上时间最简单版本,防止后端扯皮
前端·vue.js·react.js