文章目录

牛客字节基础架构前端暑期实习面经整理(pnpm / Monorepo / 构建)(十九)

收录日期:2026-05-06
关键词:前端、工程化、pnpm、yarn/npm、Monorepo、依赖管理、打包流程、React Hooks

1. npm 生命周期是什么?常见钩子有哪些?

参考答案

  • 生命周期是指在 pnpm/npm/yarn 执行 install、publish、version 等阶段会触发的一系列脚本钩子。
  • 常见:
    • preinstall/install/postinstall
    • prepare(常用于构建产物、husky 安装;对本地和 git 安装都可能触发)
    • prepublishOnly(发布前)
  • 风险:postinstall 易引入供应链风险与不可重复构建;尽量最小化。

2. pnpm 和 yarn/npm 的核心差异?

参考答案

  • pnpm 使用 content-addressable store(全局内容寻址)+ 硬链接/符号链接,节省磁盘与安装时间。
  • 默认更“严格”(non-flat):
    • 依赖不会被无脑提升到顶层,能更早暴露“幽灵依赖”问题。
  • workspace/monorepo 体验好:link-workspace-packages、filter、hoist 策略可控。

3. Monorepo 下 package 引用方式是什么?node_modules 里会出现吗?

参考答案

  • workspace 包引用通常写成:
    • "@scope/pkg": "workspace:*"(或 workspace:^ 等)
  • 安装后:
    • pnpm 会把 workspace 包以链接的形式挂到依赖树中;node_modules 里看到的是链接/虚拟 store 结构,不是传统扁平展开。
  • 关键点:保证 TS path、构建产物(types/exports)、以及包的 exports 字段正确。

4. pnpm 如何管理依赖版本?出现不同依赖组合怎么办?

参考答案

  • 锁文件:pnpm-lock.yaml 固化解析结果,确保可复现。
  • 多版本共存:pnpm 允许在不同子树安装不同版本(隔离),避免互相覆盖。
  • 版本统一策略:
    • overrides 统一某些依赖版本;
    • 用 workspace 约束(例如统一 react/react-dom);
    • CI 校验(duplicate/semver drift)。

5. 依赖存在多个版本都会打包吗?运行时会冲突吗?

参考答案

  • “会不会打包”取决于打包器的依赖解析与最终引用路径:
    • 若不同子包各自引用了不同版本且都被打入同一产物,可能出现重复代码。
  • “会不会冲突”取决于包类型:
    • 单例要求强(react、vue、一些 runtime 单例库)多版本常会出问题(Hooks 失效、上下文不共享)。
    • 工具库(lodash、dayjs)多版本一般只是包体增大。
  • 实践:把单例依赖提升为根依赖并锁定版本;对外部依赖用 peerDependencies + bundler external(库开发场景)。

6. 如何锁定依赖版本?

参考答案

  • 使用锁文件提交到仓库;CI 强制 --frozen-lockfile
  • 精确版本(不使用 ^/~)或配合 pnpm config 控制。
  • 对关键依赖用 overrides/resolutions(yarn)做强制对齐。

7. 构建工具打包的过程(高层)?

参考答案

  • 入口解析 → 模块图构建(解析 import/require)→ 转译(TS/JSX)→ 依赖收集与 tree-shaking → code splitting → 产物生成(chunk)→ 压缩与 sourcemap → 输出到 dist。
  • Vite 开发阶段偏“按需加载 + 快速转译”,生产阶段仍以 Rollup 打包为主。

8. 适合 pnpm 的分包/拆包策略?

参考答案

  • 应用侧:路由级拆包 + 大组件懒加载;公共依赖拆 vendor(注意缓存与更新频率)。
  • Monorepo:按领域拆 package(ui/data/utils),明确依赖方向(避免循环)。
  • 约束:对单例依赖统一版本;对可选依赖避免在多个包重复引入导致体积膨胀。

9. 写一个 usePrevious Hook,并解释原理

参考答案

思路:用 useRef 存“上一次值”,在 useEffect 里更新。

  • useRef.current 跨渲染持久,但更新不会触发重新渲染。
  • useEffect 在 commit 后执行,因此能在下一次 render 前保存“上一次”的值。