前端工程化主要解决什么问题?

  • 它解决的是项目从开发、构建、测试、发布到监控的全流程效率和质量问题。
  • 核心目标是让团队在规模变大后仍然能稳定交付、快速迭代、可回滚、可追踪。

2026 年前端工程化面试重点有哪些?

  • 高频方向包括 Vite、Webpack、构建性能、产物优化、Monorepo、CI/CD、灰度发布、微前端和包管理。
  • 面试更看重“为什么这么做”和“线上问题如何定位”,而不只是背配置项。

Vite 的核心思想是什么?

  • 开发阶段利用浏览器原生 ESM 按需加载源码,避免每次启动都打完整包。
  • 生产阶段仍会进行打包、压缩、Tree Shaking 和资源切分,保证线上加载效率。

Vite 为什么启动快?

  • 它不需要先把整个项目 bundle 完再启动服务,而是先启动 dev server。
  • 源码模块在浏览器请求时才转换,依赖则提前预构建并缓存。

Vite 开发环境和生产环境为什么不是同一套机制?

  • 开发环境追求启动快、热更新快,所以基于 ESM 按需转换。
  • 生产环境追求资源体积、缓存命中和加载性能,所以仍需要打包优化。

Vite 的依赖预构建是什么?

  • Vite 会把第三方依赖提前转换成适合浏览器加载的 ESM。
  • 预构建还能把依赖内部大量小模块合并,减少开发环境请求数量。

Vite 为什么要把 CommonJS 依赖预构建成 ESM?

  • 浏览器原生不支持直接加载 CommonJS。
  • 转成 ESM 后,Vite 才能通过原生模块加载和 HMR 机制管理依赖。

Vite 的 optimizeDeps 有什么用?

  • 它用于控制依赖预构建,比如强制 include 某些依赖或 exclude 某些依赖。
  • 常用于解决依赖扫描不到、包格式异常、预构建缓存不符合预期等问题。

Vite 依赖预构建缓存什么时候会失效?

  • lockfile、vite 配置、NODE_ENV、补丁依赖或相关包版本变化时可能失效。
  • 也可以通过删除缓存或使用 --force 强制重新预构建。

Vite 的 HMR 为什么快?

  • Vite 能精确定位变更模块,只让浏览器重新请求受影响的 ESM 模块。
  • 框架插件还会接管组件级热更新,避免整页刷新。

Vite 的 HMR 边界是什么?

  • HMR 边界是能够独立接受热更新的模块。
  • 如果变更无法在边界内安全替换,Vite 会向上冒泡,最终可能触发整页刷新。

Vite 中 import.meta.hot 是做什么的?

  • 它是 Vite 暴露的 HMR API。
  • 自定义模块或库可以通过它接受热更新、清理副作用、保留状态。

Vite 的 index.html 为什么在项目根目录?

  • Vite 把 index.html 当成入口和模块图的一部分处理。
  • HTML 中的模块脚本、资源路径、环境变量都可以被 Vite 解析和转换。

Vite 的 public 目录有什么特点?

  • public 下的资源不会被构建工具处理,会原样复制到产物目录。
  • 适合放不需要 hash、不需要 import、必须保持固定路径的静态文件。

Vite 中 assets 和 public 应该怎么选?

  • 需要 hash、压缩、依赖追踪的资源放源码目录并通过 import 引入。
  • 需要固定 URL 或原样输出的资源放 public

Vite 的 base 配置有什么用?

  • base 用于指定部署时的公共基础路径。
  • 部署到子目录、CDN 或 GitHub Pages 项目页时经常需要配置它。

Vite 环境变量为什么必须以 VITE_ 开头?

  • 这是安全边界,避免把服务端密钥误暴露到客户端代码。
  • 只有指定前缀的变量才会注入到 import.meta.env

import.meta.env 和 process.env 有什么区别?

  • Vite 客户端代码默认使用 import.meta.env
  • process.env 是 Node 生态常见写法,直接在浏览器环境并不存在。

Vite 的 mode 和 NODE_ENV 有什么区别?

  • mode 决定加载哪个 .env.[mode] 文件,也常用于区分业务环境。
  • NODE_ENV 更多表示构建模式,比如 development 或 production。

Vite 如何配置代理?

  • 通过 server.proxy 把本地请求转发到后端服务。
  • 常配合 rewrite、changeOrigin、headers 解决跨域和接口路径问题。

Vite 代理能不能用于生产环境?

  • Vite dev server 的 proxy 只服务开发环境。
  • 生产环境需要由 Nginx、网关、BFF 或部署平台处理转发。

Vite 如何配置路径别名?

  • 使用 resolve.alias 配置,比如把 @ 指向 src
  • TypeScript 项目还要同步配置 tsconfig.jsonpaths,避免类型解析失败。

Vite 插件的本质是什么?

  • Vite 插件基于 Rollup 插件模型扩展,并补充开发服务器相关钩子。
  • 它可以处理配置、模块解析、源码转换、HMR、HTML 转换和构建输出。

Vite 插件常用钩子有哪些?

  • configconfigResolvedresolveIdloadtransformtransformIndexHtml 很常见。
  • 开发服务器相关的 configureServerhandleHotUpdate 也很高频。

Vite 插件的 enforce 有什么用?

  • enforce: 'pre' 表示插件尽早执行,enforce: 'post' 表示尽晚执行。
  • 常用于控制插件顺序,比如先处理宏、再交给框架插件编译。

Vite 插件的 apply 有什么用?

  • apply 可以限制插件只在 serve 或 build 阶段生效。
  • 适合开发期 mock、调试插件、生产期压缩上传等不同场景。

Vite 的 transformIndexHtml 能做什么?

  • 它可以修改 HTML 入口,比如注入脚本、meta、预加载资源。
  • 常用于性能埋点、CSP nonce、微前端入口、构建版本号注入。

Vite 的 SSR 构建要注意什么?

  • SSR 需要区分客户端产物和服务端产物。
  • 还要处理 external、noExternal、模块格式、运行时 API 和 hydration 一致性。

Vite SSR 中 noExternal 有什么用?

  • 它强制某些依赖被 Vite 处理,而不是直接作为 Node 外部依赖加载。
  • 常用于依赖源码含 ESM、CSS、非标准语法或需要插件转换的情况。

Vite Library Mode 适合什么场景?

  • 适合打包组件库、工具库、SDK 等可复用包。
  • 需要关注 external、formats、types、CSS 输出和 peerDependencies。

Vite 构建库时为什么要配置 external?

  • 避免把 React、Vue 等宿主依赖打进库里,减少体积并避免多实例问题。
  • external 的依赖通常放在 peerDependencies 中交给使用方安装。

Vite 生产构建默认做哪些优化?

  • 会进行模块打包、Tree Shaking、代码压缩、CSS 处理、资源 hash 和 chunk 拆分。
  • 具体优化效果取决于模块写法、依赖格式和 Rollup/Rolldown 的分析能力。

Vite 的 build.target 有什么影响?

  • 它决定产物语法降级到什么浏览器能力范围。
  • target 越低,兼容性越好,但转换和 polyfill 成本可能更高。

Vite 如何支持旧浏览器?

  • 可以使用官方 legacy 插件生成兼容性更强的产物。
  • 但旧浏览器支持会增加构建复杂度和资源体积,应根据业务用户占比决定。

Vite 中 manualChunks 有什么用?

  • 它可以手动控制 Rollup 分包策略。
  • 适合把稳定依赖、编辑器、图表库、低频模块拆成独立 chunk。

manualChunks 配不好会有什么问题?

  • 可能产生过多请求、重复依赖、缓存收益不明显或首屏加载变慢。
  • 分包应结合真实访问路径和构建分析结果,而不是机械按包名切。

Vite 如何做构建产物分析?

  • 可以使用 rollup visualizer、vite-bundle-visualizer 等工具查看 chunk 组成。
  • 分析重点是大依赖、重复模块、首屏 chunk、动态导入边界和 gzip/brotli 体积。

Vite 项目首屏慢怎么排查?

  • 先看 Network、Coverage、Lighthouse、Performance 和产物分析。
  • 常见优化包括路由懒加载、拆大依赖、图片优化、预加载关键资源、减少同步初始化。

Vite 开发环境页面请求特别多正常吗?

  • 正常,Vite 开发阶段基于 ESM 按需加载,模块会以单独请求出现。
  • 如果请求过多导致慢,可以关注依赖预构建、full bundle mode 方向或拆分源码结构。

Vite 7 之后有哪些值得关注的变化?

  • Node 版本要求提高,并继续推进更现代的浏览器基线。
  • Rolldown、Oxc、Environment API 等方向会让工具链更快、更统一。

Rolldown 是什么?

  • Rolldown 是 Rust 编写的打包器,目标是兼容 Rollup 生态并提供更高性能。
  • Vite 正在围绕它演进,减少开发和生产构建之间的工具链差异。

Rolldown 对 Vite 意味着什么?

  • 它有机会统一 dev 和 build 的底层打包能力。
  • 对大型项目来说,未来可能改善冷启动、热更新和生产构建的一致性。

Oxc 在前端工程化中扮演什么角色?

  • Oxc 是 Rust 生态的 JavaScript/TypeScript 工具链集合。
  • 它可用于解析、转换、压缩、Lint 等方向,目标是替代部分传统 JS 工具链瓶颈。

esbuild 在 Vite 中主要做什么?

  • 它常用于依赖预构建和快速语法转换。
  • 速度很快,但不是所有 Babel 插件能力都能完全替代。

esbuild 和 Babel 有什么区别?

  • esbuild 更偏高性能构建、转换和压缩。
  • Babel 插件生态更成熟,更适合复杂语法实验、定制转换和兼容历史项目。

SWC 和 Babel 怎么选?

  • SWC 更快,适合常规 TS/JS/React 转换。
  • Babel 更灵活,适合依赖特定 Babel 插件或复杂编译链的项目。

Rollup 和 Webpack 的核心差异是什么?

  • Rollup 更偏 ESM 库打包和静态分析,产物通常更干净。
  • Webpack 更偏应用打包,生态成熟,对复杂资源和运行时能力支持丰富。

Vite 和 Webpack 最大的区别是什么?

  • Vite 开发阶段是 ESM 按需服务,Webpack 传统开发模式通常需要先构建 bundle。
  • Webpack 配置能力更强,Vite 默认体验更轻,迁移时要关注插件和产物差异。

Webpack 的核心流程是什么?

  • 从 entry 出发递归建立依赖图,对不同模块应用 loader 转换。
  • 然后通过 plugin 扩展编译流程,最终输出 chunk 和 asset。

Webpack 的 entry 是什么?

  • entry 是构建依赖图的起点。
  • 多入口项目会生成多个入口 chunk,适合多页面应用或独立业务入口。

Webpack 的 output 常配置什么?

  • 常配置 pathfilenamechunkFilenamepublicPath 和 clean。
  • 其中 publicPath 决定运行时加载异步资源的基础路径。

Webpack 的 loader 是什么?

  • loader 是模块转换器,让 Webpack 能处理 CSS、图片、字体、TS、Vue、Markdown 等非标准 JS 资源。
  • 多个 loader 按从右到左、从下到上的顺序执行。

Webpack 的 plugin 是什么?

  • plugin 通过 Tapable 钩子介入编译生命周期。
  • 它能做资源生成、HTML 注入、环境变量替换、压缩、上传、分析等更广泛的事情。

Loader 和 Plugin 的区别?

  • loader 主要处理“单个模块如何转换”。
  • plugin 主要处理“构建流程如何扩展”和“产物如何加工”。

Webpack 的 Tapable 是什么?

  • Tapable 是 Webpack 的事件流和插件机制基础。
  • Compiler、Compilation 等对象通过钩子让插件在不同阶段执行逻辑。

Compiler 和 Compilation 有什么区别?

  • Compiler 代表一次完整的 Webpack 配置和生命周期。
  • Compilation 代表一次具体构建过程,watch 模式下每次变更都会产生新的 Compilation。

Webpack 的 module、chunk、bundle 有什么区别?

  • module 是源码里的单个模块,chunk 是若干模块组合后的代码块。
  • bundle 通常指最终输出到磁盘、浏览器可加载的文件。

Webpack 的依赖图是什么?

  • Webpack 从入口开始递归分析 import、require 和资源引用,形成模块依赖关系。
  • 依赖图决定哪些模块会被打进哪些 chunk。

Webpack 的 runtime 是什么?

  • runtime 是 Webpack 注入到产物中的模块加载和 chunk 管理代码。
  • 动态 import、模块缓存、异步 chunk 加载都依赖 runtime。

Webpack 的 manifest 是什么?

  • manifest 记录模块、chunk、文件名之间的映射关系。
  • 它会影响长期缓存,因为映射变化可能导致 runtime 或入口 hash 改变。

Webpack 中 hash、chunkhash、contenthash 有什么区别?

  • hash 受整个构建影响,chunkhash 受 chunk 内容影响,contenthash 更偏文件内容。
  • 静态资源长期缓存通常优先使用 contenthash。

Webpack 如何做长期缓存?

  • 使用 contenthash、runtimeChunk、splitChunks 和稳定 moduleIds/chunkIds。
  • 目标是业务代码变化不影响稳定依赖文件的缓存。

Webpack 5 持久化缓存是什么?

  • cache: { type: 'filesystem' } 会把构建缓存写入磁盘。
  • 二次构建可复用解析、转换和依赖信息,大幅提升构建速度。

Webpack 持久化缓存要注意什么?

  • 要正确配置 buildDependencies,让配置文件、环境变化能触发缓存失效。
  • CI 中要权衡缓存恢复成本、依赖安装缓存和构建缓存收益。

Webpack 的 resolve 配置影响什么?

  • 它影响模块路径如何解析,比如 alias、extensions、mainFields、conditionNames。
  • 配置不当会增加查找成本或引入错误版本的包。

resolve.extensions 为什么不宜太多?

  • 每个缺省后缀都会增加文件系统尝试次数。
  • 大项目中应保持必要后缀,避免过度宽泛。

resolve.alias 有什么价值?

  • 它能简化路径引用,也能强制多个包使用同一份依赖。
  • 在解决 React/Vue 多实例、Monorepo 依赖重复时很常见。

Webpack 的 noParse 有什么用?

  • 对确定没有模块化依赖的大文件跳过解析。
  • 可以减少构建耗时,但不能用于包含 import、require 的模块。

Webpack 的 externals 是什么?

  • externals 表示某些依赖不打包进产物,由运行环境或 CDN 提供。
  • 适合 React、Vue、lodash 等稳定公共依赖,但要保证版本和加载顺序。

Webpack 的 Asset Modules 是什么?

  • Webpack 5 内置资源模块能力,可替代 file-loader、url-loader、raw-loader 的许多场景。
  • 常见类型有 asset/resourceasset/inlineasset/sourceasset

asset/resource 和 asset/inline 有什么区别?

  • asset/resource 输出独立文件并返回 URL。
  • asset/inline 把资源转成 data URL 内联进 JS 或 CSS。

Webpack 的 SplitChunksPlugin 做什么?

  • 它用于抽离公共模块和第三方依赖,减少重复打包。
  • 常用于 vendors、common、异步 chunk 分离和缓存优化。

SplitChunks 配置看哪些指标?

  • 关注 chunks、minSize、minChunks、cacheGroups、priority、reuseExistingChunk。
  • 配置目标是减少重复、优化缓存,而不是盲目拆得越细越好。

Webpack 动态 import 的原理是什么?

  • 构建时把动态导入模块拆成异步 chunk。
  • 运行时通过插入 script 标签或对应加载机制拉取 chunk。

prefetch 和 preload 有什么区别?

  • preload 是当前导航很快会用到的高优先级资源提示。
  • prefetch 是未来可能用到的低优先级预取,适合下一屏或下一路由。

Webpack 的 Tree Shaking 依赖什么?

  • 主要依赖 ESM 的静态结构、sideEffects 标记和压缩器删除无用代码。
  • CommonJS 动态特性强,通常更难被精确 Tree Shaking。

package.json 的 sideEffects 有什么用?

  • 它告诉打包器哪些文件可以被认为没有副作用。
  • 配错可能误删 CSS、polyfill、全局注册等必要代码。

Webpack 中 usedExports 是什么?

  • 它用于标记模块中哪些导出被使用。
  • 真正删除未使用代码通常还依赖 Terser 等压缩阶段。

为什么 CommonJS 不利于 Tree Shaking?

  • CommonJS 的 require 和 exports 可以动态执行,静态分析难度更高。
  • ESM 的 import/export 是静态结构,更适合构建期分析。

Webpack 的 mode 有什么作用?

  • development 会偏向调试体验,production 会默认开启优化和压缩。
  • none 则关闭默认优化,适合完全自定义。

devtool 应该怎么选?

  • 开发环境优先选择构建快、定位够用的 source map。
  • 生产环境要在错误定位、源码泄露和构建体积之间权衡。

source map 线上要不要上传?

  • 可以上传到 Sentry 等监控平台用于定位错误,但不一定公开给用户访问。
  • 生产 source map 要控制访问权限,避免泄露源码。

webpack-dev-server 和 webpack-dev-middleware 有什么区别?

  • dev-server 是开箱即用的开发服务器。
  • dev-middleware 更适合嵌入 Express、Koa 等自定义 Node 服务。

Webpack 的 HMR 原理是什么?

  • dev server 通知浏览器哪些模块发生变化。
  • 浏览器拉取 hot update 文件后,由运行时代码替换模块并触发 accept 回调。

HMR 为什么有时会变成整页刷新?

  • 模块没有声明可接受热更新,或变更影响到无法安全替换的边界。
  • 框架插件处理失败、状态不可保留时也可能触发 full reload。

Webpack 的 Module Federation 是什么?

  • 它允许多个独立构建在运行时互相加载模块。
  • 常用于微前端,也可用于大型应用拆分和跨团队模块共享。

Module Federation 的 remote 和 host 是什么?

  • host 是消费远程模块的一方。
  • remote 是暴露模块给其他应用加载的一方。

Module Federation 的 shared 有什么用?

  • shared 用于共享 React、Vue、基础库等依赖,减少重复加载。
  • 要谨慎配置 singleton、requiredVersion、eager,避免版本冲突和运行时错误。

Module Federation 的 singleton 有什么风险?

  • 它能保证某依赖尽量只加载一份,但版本不兼容时可能导致运行时问题。
  • React、Vue 这类框架通常需要 singleton,但要配合版本治理。

Module Federation 为什么远程模块加载是异步的?

  • remote 不在当前构建产物里,需要运行时从远程容器加载。
  • 因此通常要通过动态 import、Suspense 或路由懒加载承接异步过程。

微前端一定要用 Module Federation 吗?

  • 不一定,还可以用 iframe、Web Components、single-spa、qiankun、路由分发等方案。
  • 选择取决于隔离要求、技术栈差异、部署模式和团队协作方式。

Vite 项目如何做微前端?

  • 可以使用 Module Federation 插件、single-spa、qiankun 或 Web Components。
  • 重点是处理共享依赖、样式隔离、路由隔离、构建产物格式和部署版本。

Webpack 项目迁移到 Vite 要评估什么?

  • 评估 loader/plugin 替代方案、环境变量、别名、静态资源、动态导入和代理配置。
  • 还要检查 CommonJS 依赖、Node polyfill、CSS 预处理、测试工具和 CI 构建脚本。

为什么 Vite 迁移时可能遇到 Node polyfill 问题?

  • Vite 面向浏览器原生 ESM,不会默认注入大量 Node 核心模块 polyfill。
  • 依赖如果在浏览器端使用 path、crypto、buffer 等 Node API,需要替换或手动兼容。

Webpack 5 为什么不再自动 polyfill Node 核心模块?

  • 自动 polyfill 会让浏览器包意外变大,也掩盖依赖使用 Node API 的问题。
  • Webpack 5 更倾向让开发者显式决定是否引入 polyfill。

构建慢应该怎么系统排查?

  • 先区分是依赖安装慢、类型检查慢、转译慢、打包慢、压缩慢还是上传慢。
  • 再用 profile、stats、插件耗时、CI 日志和缓存命中率定位瓶颈。

如何优化 Webpack 构建速度?

  • 缩小 loader 范围、开启 filesystem cache、减少 resolve 尝试、避免重型 sourcemap。
  • 对 TS 类型检查、压缩、Lint 等步骤按需并行或移到独立流程。

如何优化 Vite 构建速度?

  • 减少重型插件、优化依赖格式、合理 external、拆分大型页面、升级 Node 和工具链。
  • 对库模式和 SSR 场景,重点排查 Rollup 插件耗时和大依赖处理。

TypeScript 类型检查应该放在构建里吗?

  • 小项目可以放一起,大项目建议转译和类型检查分离。
  • CI 中必须有类型检查,本地开发可用增量检查或 IDE 承担一部分反馈。

为什么 ts-loader 有时比 babel-loader 或 swc 慢?

  • ts-loader 如果同时做类型检查,会承担更多编译成本。
  • 大项目常用 swc/esbuild/Babel 转译,再用 tsc --noEmit 或 fork-ts-checker 做类型检查。

前端项目为什么要锁包?

  • 锁包文件保证团队、CI、生产构建使用一致的依赖版本。
  • 没有 lockfile 可能出现“我本地正常,线上构建失败”的问题。

npm、yarn、pnpm 的核心区别是什么?

  • npm 是 Node 默认包管理器,生态兼容性好。
  • pnpm 通过内容寻址和硬链接节省空间,并更严格处理幽灵依赖;yarn 在工作区和约束能力上也有成熟方案。

pnpm 为什么能避免幽灵依赖?

  • pnpm 的 node_modules 结构不会让项目随意访问未声明依赖。
  • 代码引用未写入 package.json 的包时,更容易在本地暴露问题。

什么是幽灵依赖?

  • 代码使用了 package.json 没声明的依赖,但由于依赖被其他包间接安装而暂时可用。
  • 它会导致换包管理器、升级依赖或 CI 环境后突然失败。

dependencies、devDependencies、peerDependencies 怎么区分?

  • dependencies 是运行时依赖,devDependencies 是开发和构建依赖。
  • peerDependencies 表示希望由宿主项目提供的同伴依赖,常见于组件库和插件。

peerDependencies 配错会有什么问题?

  • 可能导致重复安装框架、版本冲突或运行时多实例。
  • 组件库应把 React、Vue 等宿主框架放 peerDependencies。

package.json 的 exports 有什么用?

  • 它声明包对外可访问的入口和条件导出。
  • 能限制私有文件被随意引用,也能区分 import、require、browser、types 等入口。

main、module、exports 怎么理解?

  • main 常指 CommonJS 入口,module 常指 ESM 入口。
  • exports 是更现代、更精确的入口声明方式,优先级通常更高。

条件导出是什么?

  • 条件导出允许同一个包根据 import、require、browser、node、development 等条件返回不同文件。
  • 配置错误会导致打包器、Node、测试环境解析到不同实现。

Monorepo 适合什么场景?

  • 多个应用、组件库、工具包共享代码并需要统一版本治理时适合。
  • 如果团队很小、包关系简单,Monorepo 反而可能增加工具复杂度。

Monorepo 的核心收益是什么?

  • 共享配置、统一依赖、原子提交、跨包重构更方便。
  • 配合缓存和任务编排,可以只构建受影响的包。

Monorepo 的风险是什么?

  • 依赖边界容易混乱,CI 配置更复杂,仓库体积和权限管理也更难。
  • 需要约束包依赖方向、发布流程和代码所有权。

Turborepo 和 Nx 解决什么问题?

  • 它们主要做任务编排、缓存、依赖图分析和增量构建。
  • 大型 Monorepo 中能显著减少重复测试、重复构建和 CI 时间。

Monorepo 中 affected build 是什么?

  • 它根据 Git diff 和包依赖图计算哪些项目受影响。
  • CI 只构建和测试受影响范围,提升反馈速度。

组件库工程化要关注哪些点?

  • 关注多格式产物、类型声明、样式输出、按需引入、文档、测试和版本发布。
  • 还要处理 peerDependencies、Tree Shaking、主题定制和兼容性策略。

组件库为什么要输出 ESM 和 CJS?

  • ESM 适合现代打包器 Tree Shaking。
  • CJS 仍可能被 Node、老工具链或部分测试环境使用。

组件库如何保证按需引入?

  • 输出保留模块结构的 ESM,并正确配置 sideEffects。
  • 样式也要支持按需加载,避免引入一个组件打进全量 CSS。

前端 SDK 打包要注意什么?

  • 要控制体积、避免污染全局、兼容宿主环境、提供稳定 API。
  • 同时要关注异常隔离、埋点采样、版本回滚和 source map 管理。

CI/CD 在前端项目中做什么?

  • CI 负责安装、Lint、类型检查、测试、构建和安全扫描。
  • CD 负责部署、灰度、缓存刷新、版本记录和回滚。

前端 CI 为什么要缓存依赖?

  • 依赖安装通常是 CI 耗时大头。
  • 缓存 lockfile 对应的包管理器缓存,比缓存 node_modules 更稳定。

CI 缓存为什么不能只看 package.json?

  • package.json 允许 semver 范围,真实安装版本由 lockfile 决定。
  • 缓存 key 应优先绑定 lockfile、Node 版本和包管理器版本。

前端发布为什么要保留构建版本号?

  • 版本号能帮助定位线上代码、错误日志、source map 和 Git commit。
  • 灰度、回滚和问题追踪都依赖明确的构建身份。

蓝绿发布和灰度发布有什么区别?

  • 蓝绿发布是在两套环境间整体切换。
  • 灰度发布是按用户、流量、地区或规则逐步放量。

前端静态资源发布为什么要先上传资源再切 HTML?

  • HTML 会引用带 hash 的 JS/CSS,如果先切 HTML,用户可能请求到还没上传的资源。
  • 正确顺序通常是先上传静态资源,再发布 HTML 或入口配置。

前端资源为什么要加 contenthash?

  • 内容不变时文件名不变,浏览器和 CDN 可以长期缓存。
  • 内容变化时 hash 改变,能自动避开旧缓存。

HTML 为什么通常不做强缓存?

  • HTML 是应用入口,必须尽快拿到最新资源引用。
  • 一般会对 HTML 使用协商缓存或较短缓存,对带 hash 的静态资源使用强缓存。

CDN 缓存更新要注意什么?

  • 带 hash 资源尽量不覆盖,旧版本保留一段时间。
  • HTML、manifest、remoteEntry 等入口资源要有明确刷新策略。

remoteEntry 为什么不适合长期强缓存?

  • 微前端 remoteEntry 通常记录远程模块和 chunk 的映射。
  • 如果缓存过久,host 可能加载旧映射导致资源 404 或版本不一致。

前端回滚为什么不只是重新发旧代码?

  • 还要确认旧 HTML 引用的静态资源仍然存在。
  • 如果接口、数据结构或配置也变了,回滚需要跨端协同。

构建产物 404 怎么排查?

  • 检查 publicPath/base、资源上传路径、CDN 缓存、HTML 引用和部署顺序。
  • 动态 chunk 404 还要看是否存在用户长时间停留旧页面后加载新 chunk 的情况。

ChunkLoadError 常见原因是什么?

  • 新版本发布后旧页面尝试加载已经删除的旧 chunk。
  • CDN 缓存不一致、publicPath 错误、网络失败也会触发。

ChunkLoadError 怎么处理?

  • 保留旧版本静态资源一段时间,入口发布与资源上传顺序正确。
  • 前端可捕获 chunk 加载失败后提示刷新或自动 reload,但要避免死循环。

前端如何做错误监控?

  • 捕获 JS 错误、Promise 未处理异常、资源加载错误和接口异常。
  • 上报时带版本号、路由、用户环境、source map 映射和关键上下文。

Source Map 上传到监控平台要注意什么?

  • 上传时要绑定 release 和构建产物路径。
  • 不建议把完整 source map 公开暴露在 CDN 上。

前端性能指标有哪些?

  • 常见指标包括 FCP、LCP、CLS、INP、TTFB、TTI、资源体积和长任务。
  • 面试中要能说明指标含义、采集方式和优化手段。

LCP 慢通常怎么优化?

  • 优化首屏大图、服务端响应、关键 CSS、字体、资源优先级和阻塞脚本。
  • 对 SPA 还要减少首屏 JS 体积和同步初始化逻辑。

INP 差通常说明什么?

  • 说明用户交互响应慢,常见原因是主线程长任务、事件处理过重或渲染阻塞。
  • 可以拆任务、延迟非关键逻辑、使用 Web Worker、减少重渲染。

CLS 高怎么排查?

  • 看图片、广告、字体、异步组件、骨架屏是否导致布局突然变化。
  • 给媒体元素预留尺寸,避免动态插入内容推挤页面。

构建层面如何减少首屏 JS?

  • 路由懒加载、组件异步加载、Tree Shaking、拆分重依赖、减少 polyfill。
  • 对非首屏逻辑延迟加载,对低频功能独立 chunk。

CSS 工程化要关注什么?

  • 关注作用域隔离、主题变量、按需加载、压缩、兼容性和关键 CSS。
  • 大项目还要治理全局样式污染和样式优先级失控。

CSS Modules 和 scoped CSS 有什么区别?

  • CSS Modules 通过类名映射实现局部作用域。
  • Vue scoped CSS 通过属性选择器隔离组件样式。

PostCSS 在工程中做什么?

  • 它是 CSS 转换工具,可以配合插件做 autoprefixer、px 转换、压缩、语法增强。
  • Tailwind CSS、兼容性处理和移动端适配经常依赖它。

Autoprefixer 依赖什么决定前缀?

  • 它依赖 Browserslist 配置判断目标浏览器。
  • Browserslist 配错会导致兼容性不足或产物冗余。

Browserslist 影响哪些工具?

  • 它会影响 Babel、Autoprefixer、Vite、Webpack 生态中的兼容转换。
  • 统一配置能避免 JS 和 CSS 兼容目标不一致。

Babel preset-env 做什么?

  • 它根据目标环境决定语法转换和 polyfill 策略。
  • 配合 core-js 时要注意 polyfill 注入方式和污染全局的问题。

polyfill 和 transform 有什么区别?

  • transform 转换语法,比如把新语法降级。
  • polyfill 补运行时 API,比如 Promise、Array.from、URLSearchParams。

core-js 的 useBuiltIns 有什么用?

  • entry 基于入口统一注入 polyfill,usage 按代码使用情况注入。
  • 现代项目要结合目标浏览器、包体积和第三方依赖兼容性判断。

Web Worker 在工程化里适合做什么?

  • 适合处理大计算、解析、压缩、加密、图像处理等主线程重任务。
  • 要注意通信成本、数据复制、错误处理和打包器 worker 语法支持。

WASM 在前端工程中适合什么场景?

  • 适合计算密集型任务,比如图像、音视频、压缩、编解码和复杂算法。
  • 不适合所有业务逻辑,加载成本和 JS/WASM 通信成本也要评估。

前端安全工程化包括哪些内容?

  • 包括依赖安全、XSS 防护、CSP、SRI、权限控制、密钥管理和供应链安全。
  • CI 中可以加入依赖审计、许可证检查和敏感信息扫描。

为什么不能把密钥放进前端环境变量?

  • 前端代码最终会发到用户浏览器,变量会被打进产物。
  • 真正的密钥必须放服务端,通过接口或临时凭证间接使用。

CSP 能解决什么问题?

  • CSP 通过限制脚本、样式、图片等资源来源降低 XSS 风险。
  • 工程上要处理 nonce、hash、第三方脚本白名单和监控上报。

SRI 是什么?

  • Subresource Integrity 用资源哈希校验 CDN 文件是否被篡改。
  • 适合外链脚本和样式,但资源更新时必须同步更新 integrity。

依赖供应链风险怎么降低?

  • 锁定版本、审计依赖、限制 install scripts、使用可信 registry、定期升级。
  • 对核心依赖要关注维护状态、下载源、许可证和安全公告。

为什么要做 Bundle Budget?

  • 它给 JS/CSS/图片体积设置上限,防止性能在迭代中慢慢变差。
  • 可以在 CI 中结合构建分析和阈值检查阻断异常膨胀。

为什么要做工程规范自动化?

  • 依赖人工 review 很难长期稳定执行。
  • ESLint、Prettier、Stylelint、commitlint、lint-staged 能把规范前移到提交前和 CI。

ESLint 和 Prettier 的边界是什么?

  • ESLint 主要处理代码质量、潜在错误和部分风格规则。
  • Prettier 专注格式化,二者冲突时通常让 Prettier 接管格式。

lint-staged 有什么用?

  • 它只对暂存区文件运行 lint 或格式化。
  • 相比全量检查更快,适合 pre-commit 阶段。

commitlint 有什么用?

  • 它规范提交信息格式,方便生成 changelog 和自动发布版本。
  • 常和 Conventional Commits、semantic-release、changesets 配合。

changesets 适合什么场景?

  • 适合 Monorepo 或组件库的版本管理和 changelog 生成。
  • 它能记录每个包的变更类型,并在发布时统一计算版本。

semantic-release 的核心思路是什么?

  • 根据提交信息自动决定版本号、生成 changelog、打 tag 并发布。
  • 它适合流程规范成熟、提交信息严格的项目。

前端自动化测试分哪几层?

  • 单元测试验证函数和组件细节,集成测试验证模块协作。
  • E2E 测试验证真实用户路径,视觉回归测试验证 UI 变化。

Vitest 相比 Jest 的优势是什么?

  • Vitest 和 Vite 生态集成更自然,启动和转换速度通常更快。
  • 对 Vite 项目可以复用别名、插件和环境配置。

Playwright 适合测什么?

  • 适合端到端流程、跨浏览器行为、截图对比、可访问性和复杂交互。
  • 它更接近真实用户环境,但成本高于单元测试。

测试金字塔怎么理解?

  • 底部应有较多快速单元测试,中间是集成测试,顶部是少量关键 E2E。
  • 过多 E2E 会导致慢和不稳定,过少集成测试又容易漏业务链路问题。

Mock Service Worker 有什么价值?

  • MSW 可以在浏览器或测试环境拦截网络请求。
  • 它让本地开发、组件测试和 E2E 更接近真实接口行为。

Docker 在前端工程中有什么用?

  • 可以固定 Node、包管理器和系统依赖,减少环境差异。
  • 也常用于构建静态资源、运行 SSR 服务或生成 Nginx 镜像。

前端 Docker 镜像如何减小体积?

  • 使用多阶段构建,构建阶段安装依赖,运行阶段只保留产物和必要服务。
  • 清理缓存、选择合适基础镜像、避免把 node_modules 带到静态站点镜像。

Nginx 部署 SPA 要注意什么?

  • 需要把未知路由回退到 index.html,否则刷新二级路由会 404。
  • 同时要正确配置静态资源缓存、gzip/brotli、代理和安全头。

Vite 部署到子路径为什么会白屏?

  • 常见原因是 base 配错,导致 JS/CSS 请求路径错误。
  • 还要检查路由 base、CDN 路径和 HTML 中静态资源引用。

Webpack 部署到 CDN 为什么要关注 publicPath?

  • 异步 chunk 运行时加载路径由 publicPath 决定。
  • 配错会导致首屏正常但切路由或懒加载模块时报 404。

前端国际化工程要关注什么?

  • 关注语言包拆分、懒加载、默认语言、回退策略、日期货币格式和翻译缺失检测。
  • 大型项目还要考虑文案提取、翻译平台同步和构建时校验。

多环境配置如何设计?

  • 区分构建时变量和运行时变量。
  • 不频繁变化的可在构建时注入,部署后需要切换的应通过接口、HTML 配置或环境文件运行时读取。

构建时配置和运行时配置有什么区别?

  • 构建时配置会被打进产物,修改后必须重新构建。
  • 运行时配置可在部署环境改变,适合 API 域名、灰度开关、租户配置等。

Feature Flag 在前端工程中有什么用?

  • 它可以控制功能灰度、A/B 实验、紧急开关和按用户放量。
  • 要注意默认值、缓存、权限校验和服务端兜底。

前端埋点工程化要关注什么?

  • 关注自动采集、手动埋点、曝光计算、去重、采样、离线缓存和上报时机。
  • 还要保证埋点不阻塞主流程,并能按版本追踪数据变化。

sourcemap 定位不到源码怎么办?

  • 检查 release 是否一致、文件路径是否匹配、sourceRoot 是否正确。
  • 还要确认构建产物没有被二次压缩或上传时改名。

前端项目如何做依赖升级?

  • 先看 changelog 和 breaking changes,再小步升级核心依赖。
  • 配合自动测试、构建验证、灰度发布和回滚方案降低风险。

Vite 大版本升级要重点看什么?

  • 看 Node 版本要求、默认浏览器 target、插件兼容、废弃 API 和构建产物变化。
  • 框架插件、测试工具、SSR 框架也要一起确认兼容性。

Webpack 大版本升级要重点看什么?

  • 看 loader/plugin 兼容、Node polyfill、缓存配置、废弃配置和产物 hash 变化。
  • 升级前后要对比构建耗时、包体积、source map 和关键页面行为。

为什么构建产物需要可复现?

  • 可复现构建能保证同一份源码和依赖生成一致产物。
  • 它对回滚、审计、问题定位和供应链安全都很重要。

如何提高构建可复现性?

  • 固定 Node 和包管理器版本,提交 lockfile,避免构建时依赖不稳定远程资源。
  • 记录 commit、环境变量、构建镜像和工具版本。

前端工程中的制品是什么?

  • 制品是构建后可发布或可复用的产物,比如静态资源、npm 包、Docker 镜像。
  • 制品应带版本、校验信息和来源 commit。

为什么不建议在服务器上直接 npm install 后构建?

  • 服务器环境不可控,依赖安装和构建结果可能不可复现。
  • 更推荐在 CI 中构建制品,再把制品部署到目标环境。

前端工程如何做权限和环境隔离?

  • 代码仓库、CI 密钥、部署权限、生产配置都应最小权限管理。
  • 生产发布最好有审批、审计和回滚记录。

线上白屏如何排查?

  • 先看控制台错误、Network 资源状态、HTML 是否最新、JS/CSS 是否 404。
  • 再看接口、兼容性、环境变量、路由 base、CDN 缓存和最近发布记录。

本地正常线上异常通常有哪些原因?

  • 环境变量不同、base/publicPath 不同、依赖版本不同、接口跨域或缓存不一致。
  • 也可能是构建压缩触发问题、大小写路径在不同系统表现不同。

大小写路径为什么会导致线上问题?

  • macOS 默认文件系统可能大小写不敏感,而 Linux CI/服务器通常大小写敏感。
  • import 路径大小写不一致会导致本地正常、CI 或线上失败。

为什么要在 CI 中跑 build?

  • build 能发现类型、依赖、路径、产物和构建配置问题。
  • 只跑本地构建不可靠,CI 才能提供统一环境下的准入门槛。

前端工程负责人最应该关注哪些指标?

  • 交付效率:构建耗时、CI 耗时、发布频率、回滚耗时。
  • 质量稳定性:线上错误率、性能指标、失败构建率、依赖风险和测试覆盖关键路径。