【前端面试】前端工程化篇

【前端面试】HTML篇
【前端面试】CSS篇
【前端面试】JS篇
【前端面试】Vue篇
【前端面试】Git篇
【前端面试】前端性能优化篇
【前端面试】手写题篇
【前端面试】浏览器&网络篇
【前端面试】前端工程化篇

Webpack 核心概念

webpack 的作用

  • 模块化打包:将前端项目的 JS、CSS、图片等各种资源视作模块,统一打包成浏览器可用的 bundle。
  • 依赖管理:解析模块间依赖关系,按需加载,支持代码拆分(Code Splitting)和按模块更新。
  • 优化与扩展:提供 Loader/Plugin 机制,对代码做转译、压缩、Tree Shaking、热更新等优化。

bundle、chunk、module 的区别

  • module:最小构建单元,可以是 JS/TS/CSS 文件或组件,webpack 会递归解析依赖形成模块图。
  • chunk:模块集合,用于按需加载,可能包含多个模块,支持同步或异步分块。
  • bundle:最终输出文件,浏览器实际加载的文件,通常由一个或多个 chunk 打包而成。

webpack 构建过程(从 entry 到 output)

Webpack 从入口文件出发,解析依赖,应用 Loader 转码,打包成 chunk 并经过 Plugin 优化,最后输出到磁盘。

  1. 初始化 :读取配置文件,确定 entry(入口文件)、output(输出配置)、Loader、Plugin 等。
  2. 编译 :从 entry 出发,递归解析模块依赖,并对模块应用 Loader 转换代码。
  3. 打包:将所有模块整合成一个或多个 chunk,并应用 Plugin 做优化(如压缩、Tree Shaking、Code Splitting)。
  4. 输出 :将最终生成的 bundle 文件写入磁盘(output.path),完成构建。

Loader 和 Plugin 的区别

Loader 负责转换模块内容 ,Plugin 负责扩展构建功能和优化流程

  • 作用范围
    • Loader :用来处理模块 ,把文件从一种格式转换为 JS 模块,比如 babel-loader
    • Plugin :用来扩展 webpack 功能,影响整个构建过程,比如生成 HTML、压缩代码、清理目录。
  • 触发阶段
    • Loader:在模块加载和解析阶段起作用。
    • Plugin:在构建流程的各个阶段都可以挂钩(hook),更灵活。

常见 Loader 和 Plugin

常见 Loader

  1. babel-loader:JS/TS 转码,支持最新语法向下兼容。
  2. css-loader:处理 CSS 引入,支持模块化 CSS。
  3. style-loader:把 CSS 注入到页面 <style> 标签中。
  4. sass-loader / less-loader:处理 Sass 或 Less 预处理语言。
  5. file-loader / url-loader / asset 模块:处理图片、字体等资源。
  6. ts-loader:TypeScript 转 JS。

常见 Plugin

  1. HtmlWebpackPlugin:生成 HTML 并自动引入 bundle。
  2. CleanWebpackPlugin:打包前清理输出目录。
  3. MiniCssExtractPlugin:提取 CSS 为单独文件。
  4. DefinePlugin:定义全局常量(如环境变量)。
  5. HotModuleReplacementPlugin:支持 HMR 热更新。
  6. CopyWebpackPlugin:复制静态资源到输出目录。

热更新(HMR)的实现原理

Webpack HMR 通过模块依赖图,只替换变更的模块,利用 runtime 处理更新,避免整页刷新,实现高效开发。

  • 核心概念:只替换发生变化的模块,不刷新整个页面,提高开发效率。
  • 工作流程 :Webpack 编译变化模块生成补丁 → HMR runtime 接收 → 调用模块的 accept handler 更新模块。
  • 关键依赖:模块依赖图决定哪些模块需要更新,框架(React/Vue)提供热更新 API 支持。

externals / alias 配置的作用

externals 用于排除不打包的依赖,alias 用于路径别名简化导入。

  1. externals
  • 告诉 Webpack 某些依赖不需要打包,通常由外部 CDN 或全局变量提供,避免重复打包。
  1. alias
  • 为模块路径设置别名,简化导入路径,减少相对路径复杂度,提高项目可维护性。

性能优化 & 构建优化

Tree Shaking 原理、优缺点

Tree Shaking 通过静态分析 ES Module 去掉未用代码,减小体积,但对 CommonJS 或有副作用模块要注意。

  • 概念:去除未使用代码,减小打包体积。
  • 原理:基于 ES6 静态模块分析,通过 Webpack 标记未使用代码,再由 Terser 删除未用代码,减小 bundle 体积。
  • 优点:减小 bundle,提升加载性能,和 Code Splitting 配合效果更好。
  • 缺点 :只支持 ES Module;有副作用的模块需在 package.json 标注 "sideEffects": false;动态引用不一定能分析。

Code Splitting

Code Splitting 就是把代码拆成多个可按需加载的 chunk,优化加载性能和首屏速度。

  • 概念
    • 将应用代码拆分成多个 chunk,按需加载,而不是一次性打包成一个大文件。
  • 目的
    • 减少初始加载体积,提高页面首屏加载速度。
    • 支持按需加载和懒加载,提高性能和用户体验。
  • 实现方式
    • Entry Points:多个入口文件生成不同 bundle。
    • 动态 import :使用 import() 动态加载模块。
    • SplitChunksPlugin:Webpack 内置插件,提取公共模块。

Source Map 的概念与生成方式

Source Map 是压缩/打包后代码和源代码的映射表,方便调试和追踪错误,通过 Webpack 的 devtool 配置生成。

  • 概念:把压缩或打包后的代码映射回源代码,方便调试。
  • 作用:浏览器调试时能看到原始代码,生产报错也能追踪到源代码位置。
  • 生成方式 :Webpack 通过 devtool 配置生成 .map 文件,开发和生产模式可选不同类型(如 evalsource-map)。

提高打包速度的策略

  • 缓存缓存 loader 或模块结果 ,减少重复编译,Webpack 5 提供 persistent caching,下次构建只重新编译变动模块。
  • DLL / 预构建依赖:第三方库打包成独立 bundle,减少重复编译。
  • 多线程/进程(thread-loader / HappyPack :对 babel-loaderts-loader 等耗时 loader 使用多线程。
  • 减少无用 loader/plugin:精简不必要操作。
  • 按需编译 / Code Splitting:只编译变动模块或懒加载。
  • 优化模块解析 :合理配置 resolve.extensionsalias,减少查找耗时。

减少打包体积

  • Tree Shaking:移除未使用的 ES Module 导出。
  • Code Splitting:拆分成多个 chunk,实现按需加载。
  • 压缩TerserPlugin 压缩 JS,css-minimizer-webpack-plugin 压缩 CSS。
  • 排除不必要依赖 :如通过 externals 排除 CDN 加载的库。
  • 按需引入:避免全量导入第三方库(如 lodash)。

Webpack 对比/升级

Webpack 5 对比 Webpack 4 优化点

Webpack 5 相比 4,提升构建速度(持久化缓存)、优化 bundle 体积(Tree Shaking、Scope Hoisting)、支持微前端(模块联邦)、改进输出管理,并增强现代技术兼容性。

  1. 持久化缓存:构建速度大幅提升,下次构建只重新编译变动模块。
  2. 模块联邦:支持微前端模块按需共享和加载,降低重复代码和版本冲突。
  3. 自动 Tree Shaking:默认启用 Tree Shaking,优化 bundle 体积和运行性能。
  4. 默认支持 WebAssembly、ES Module:更好地支持现代前端技术栈。
  5. 改进的输出与优化 :内置优化:自动生成 runtime chunk、优化 splitChunks、内置 asset 模块管理(无需 file-loader/url-loader)。
  6. 更严格的依赖管理:Module resolution 更严格,减少潜在冲突和错误。
  7. 移除/替换部分过时插件 :移除 UglifyJsPluginCommonsChunkPlugin,使用内置 TerserPluginSplitChunksPlugin

hash、chunkhash、contenthash 的区别

hash 是整个构建唯一标识,chunkhash 根据 chunk 内容生成,contenthash 根据文件内容生成,越精细越利于缓存优化。

  1. hash
    • 作用:整个编译过程的唯一标识,每次构建都会改变。
    • 特点:只要项目重新打包,不论文件是否改动,hash 都会变化。
    • 用途:适合整个项目打包的版本号,但不适合缓存优化。
  2. chunkhash
    • 作用 :根据 chunk 内容 生成 hash。
    • 特点:同一个 chunk 内容不变时 hash 不变,不同 chunk hash 不同。
    • 用途:用于区分不同入口或代码分块的 bundle,配合缓存优化。
  3. contenthash
    • 作用 :根据 文件内容 生成 hash(通常用于 CSS、JS 文件)。
    • 特点:只有文件内容改变时 hash 才变,最精细化的缓存控制。
    • 用途:配合长期缓存(长期 CDN 缓存)最有效。

前端新工具对比

Webpack vs Vite 区别

  • 构建方式:Webpack 会先打包所有模块,Vite 开发模式下按需加载 ES Module。
  • 启动和热更新:Webpack 项目大时启动慢,热更新基于 bundle;Vite 启动快,热更新即时。
  • 生产构建:Webpack 和开发模式一致打包,Vite 生产模式用 Rollup,体积小、性能高。
  • 生态与适用场景:Webpack 插件丰富,适合复杂工程;Vite 更适合现代前端快速开发。

Vite 如何处理 CommonJS

Vite 开发模式下用 esbuild 把 CommonJS 转成 ESM,生产模式用 Rollup + CommonJS 插件打包,保证浏览器可以按模块加载。

esbuild 与 webpack 的区别

  • 定位不同
    • Webpack 是完整打包工具,负责模块解析、打包、优化、Loader/Plugin 扩展。
    • esbuild 是高性能构建工具,核心是 超快的 JS/TS 编译和打包,功能比 Webpack 简单。
  • 性能差异
    • Webpack 用 JS 实现,构建大项目较慢。
    • esbuild 用 Go 语言实现,速度非常快,尤其是依赖预构建和转码。
  • 生态与扩展
    • Webpack 插件和 Loader 丰富,适合复杂工程化需求。
    • esbuild 插件生态简单,但可以用于 Vite 等工具的高速构建。

Vite 的依赖预构建(pre-bundling)机制

Vite 的依赖预构建是用 esbuild 将第三方依赖转换为 ESM 并缓存,提升冷启动和热更新速度,同时兼容 CommonJS 模块。

  1. 概念
    • Vite 会在开发环境启动时 预先构建依赖(尤其是 npm 包),生成优化后的 ESM 模块,以提升页面热更新和模块加载速度。
  2. 原理
    • 使用 esbuild 将依赖库从 CommonJS/UMD 等格式转换为 ESM。
    • 构建后的依赖会被缓存,下次启动或修改依赖时无需重复构建。
  3. 作用
    • 加快冷启动 :浏览器只加载已优化的 ESM 依赖,无需动态解析整个 node_modules
    • 提高 HMR 效率:依赖模块已经是 ESM,模块热更新更快。
    • 兼容 CommonJS:通过预构建将 CommonJS 转为 ESM,解决浏览器直接加载问题。

esbuild 的 transform 与 bundle 原理

transform 是单文件语法转换,不处理依赖,bundle 是依赖分析后打包成最终文件,二者都利用 esbuild 高速编译器实现快速处理。

  1. transform
    • 概念:对单个文件进行语法转换,如 TypeScript → JavaScript、ESNext → ES5。
    • 原理 :使用 高速的 Go 语言编译器解析文件成 AST,然后转换语法并生成新的 JS 代码,不处理依赖。
    • 特点:速度极快,适合处理单文件转换或 loader 场景。
  2. bundle
    • 概念:将多个模块及其依赖打包成一个或多个文件。
    • 原理:esbuild 会从入口文件出发,递归解析依赖、构建模块图(module graph),然后将模块组合成一个 bundle,支持代码分割和 tree shaking。
    • 特点:兼顾转换和打包,输出最终可直接运行的文件。

工程化与工具链

Babel 的概念与原理

Babel 是把现代 JS/JSX/TypeScript 转换为向后兼容的代码的编译工具,通过解析 AST → 转换 AST → 生成代码实现语法兼容和扩展功能。

  1. 概念
    • Babel 是一个 JS 编译工具 ,用于将 ES6+ 或未来标准语法 转换为 向后兼容的 ES5 代码,让旧版浏览器也能运行现代 JS。
    • 同时可以处理 JSX、TypeScript 等扩展语法。
  2. 原理
    Babel 的核心流程分为三步:
    1. 解析(Parse):将源代码转成 AST(抽象语法树)。
    2. 转换(Transform):对 AST 进行修改,如把箭头函数、类、模板字符串等转换为兼容写法。
    3. 生成(Generate):把转换后的 AST 生成新的 JS 代码。
  3. 作用
    • 兼容性:支持旧浏览器运行现代 JS。
    • 语法扩展:支持 JSX、TypeScript、实验性语法等。
    • 与构建工具集成:通常结合 Webpack、Rollup、Vite 使用,提高前端开发效率。

CSS 工程化理解

CSS 工程化就是用规范、模块化和自动化管理样式,提高可维护性、复用性,减少冲突,并结合构建工具和组件化实现高效开发。

  1. 概念
    • CSS 工程化是指通过 规范、模块化和自动化 管理 CSS,使大型项目的样式可维护、可复用、可扩展。
  2. 目的
    • 提高 可维护性:样式结构清晰、命名规范。
    • 减少 冲突:通过模块化或命名空间避免样式污染。
    • 提升 复用性:组件级样式可在不同项目或模块复用。
    • 提高 自动化和效率:使用构建工具自动处理前缀、压缩、合并等。
  3. 实践方式
    • CSS 预处理器:Sass、Less,支持变量、嵌套、Mixin。
    • CSS 模块化:CSS Modules、BEM 命名规范、原子化 CSS(Tailwind)等。
    • 构建工具集成:PostCSS、Autoprefixer、cssnano,自动加前缀和压缩。
    • 组件化管理:与前端组件框架(React/Vue)结合,样式随组件封装。

CSS Module / CSS in JS / PostCSS / Tailwind 等的优劣

技术 优点 缺点 / 注意事项
CSS Modules - 样式局部化,避免全局冲突 - 与组件绑定,复用性高 - 对全局样式支持有限 - 配置依赖构建工具(Webpack/Vite)
CSS-in-JS (如 styled-components) - 样式与组件紧密绑定,动态样式灵活 - 支持 JS 逻辑控制样式 - 运行时性能略差,增加 bundle 体积 - 学习成本高,调试相对复杂
PostCSS - 自动加前缀(Autoprefixer)、压缩、优化 - 可扩展插件生态丰富 - 主要是样式处理工具,不解决模块化问题 - 需要构建工具支持
Tailwind CSS - 原子类快速开发,提高开发效率 - 易于维护大型项目样式 - 类名过多可读性差 - 需要设计规范和团队约定

Monorepo 理解

Monorepo 把多个项目或包放在同一仓库,便于共享代码和统一管理,但仓库大、版本管理复杂,需要合适的工具链支持。

  1. 概念
    • Monorepo 是指 多个项目或包维护在同一个代码仓库,而不是为每个项目单独建仓。
    • 每个项目可以是独立应用,也可以是共享的库/模块。
  2. 优点
    • 统一管理:依赖、版本、CI/CD 配置统一管理,减少重复配置。
    • 共享代码:库或工具模块可以在不同项目间直接复用。
    • 跨项目改动可见:修改共享模块时,仓库内其他项目可以即时测试兼容性。
  3. 缺点 / 挑战
    • 仓库体积大,可能影响 git 操作和 CI/CD 构建速度。
    • 版本控制复杂,不同包可能有不同依赖版本。
    • 工具链要求高 ,需要 pnpm workspaceLernaYarn Workspaces 等配合管理。
  4. 常用工具
    • pnpm workspace / Yarn Workspaces / Lerna,管理依赖和子包构建。
  5. 适用场景
    • 大型前端或全栈项目,有多个应用或共享组件库。
    • 团队希望统一版本管理和构建流程。

pnpm 比 npm 快的原因

pnpm 通过全局存储+硬链接、严格依赖树、并行下载和缓存机制,避免重复安装和下载,速度比 npm 快很多。

  1. 独特的存储方式
    • pnpm 使用 全局内容寻址存储 ,不同项目共享依赖的硬链接,而不是每个项目都复制一份 node_modules
    • 节省磁盘空间,也减少安装重复依赖的时间。
  2. 严格的依赖树
    • pnpm 构建的是 非扁平化、严格的依赖树,避免重复安装依赖,提升解析速度。
  3. 并行安装
    • pnpm 会 最大化并行下载依赖,提高安装速度。
  4. 增量安装 / 缓存
    • 已下载过的包会被缓存,下次安装时直接复用,不用重复下载。

整理不易,有回答错误之处欢迎在评论区指正交流~

相关推荐
亿元程序员2 小时前
微信小游戏包体限制4M,一个字体就11.24M,怎么玩?
前端
涔溪2 小时前
vue中预览pdf文件
前端·vue.js·pdf
绝无仅有2 小时前
大厂某里电商平台的面试及技术问题解析
后端·面试·架构
天若有情6732 小时前
从零实现轻量级C++ Web框架:SimpleHttpServer入门指南
开发语言·前端·c++·后端·mvc·web应用
绝无仅有2 小时前
某里电商大厂 MySQL 面试题解析
后端·面试·架构
摇滚侠2 小时前
css,控制超出部分隐藏,显示... css,控制超出部分不隐藏,换行
前端·css
hygge9992 小时前
JVM 内存结构、堆细分、对象生命周期、内存模型全解析
java·开发语言·jvm·经验分享·面试
IT_陈寒2 小时前
Python 3.12 新特性实战:10个让你代码更优雅的隐藏技巧
前端·人工智能·后端
hygge9992 小时前
类加载机制、生命周期、类加载器层次、JVM的类加载方式
java·开发语言·jvm·经验分享·面试