前端工程化主要解决什么问题?
- 它解决的是项目从开发、构建、测试、发布到监控的全流程效率和质量问题。
- 核心目标是让团队在规模变大后仍然能稳定交付、快速迭代、可回滚、可追踪。
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.json的paths,避免类型解析失败。
Vite 插件的本质是什么?
- Vite 插件基于 Rollup 插件模型扩展,并补充开发服务器相关钩子。
- 它可以处理配置、模块解析、源码转换、HMR、HTML 转换和构建输出。
Vite 插件常用钩子有哪些?
config、configResolved、resolveId、load、transform、transformIndexHtml很常见。- 开发服务器相关的
configureServer、handleHotUpdate也很高频。
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 常配置什么?
- 常配置
path、filename、chunkFilename、publicPath和 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/resource、asset/inline、asset/source、asset。
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 耗时、发布频率、回滚耗时。
- 质量稳定性:线上错误率、性能指标、失败构建率、依赖风险和测试覆盖关键路径。








