高级前端面试题:package.json 常见字段

1. package.json 是什么?里面的字段可以分成哪几类?

核心思路(一句话)

package.json 本质上就是 npm 包的配置文件,负责描述包的信息、入口、依赖以及相关工程配置。

可以从 4 个维度理解:

text 复制代码
package.json
│
├── ① 包的基本信息
│   ├── name
│   ├── version
│   ├── description
│   ├── keywords
│   ├── author
│   └── license
│
├── ② 包如何被消费
│   ├── main
│   ├── module
│   ├── browser
│   ├── types / typings
│   ├── exports
│   └── files
│
├── ③ 工程依赖与脚本
│   ├── dependencies
│   ├── devDependencies
│   ├── peerDependencies
│   ├── optionalDependencies
│   └── scripts
│
└── ④ 工具/生态扩展配置
    ├── sideEffects
    ├── browserslist
    ├── eslintConfig
    ├── prettier
    ├── rollup
    └── 其他工具自定义字段

主要矛盾

不要死记"哪些字段是标准、哪些字段是非标准"。

真正重要的是:谁读取这个字段,以及它会影响什么行为。

例如:

text 复制代码
package.json
     │
     ├── npm → 发布、安装、依赖
     │
     ├── Node.js → 模块解析
     │
     ├── TypeScript → 类型声明解析
     │
     ├── Webpack / Rollup / Vite → 模块入口、构建
     │
     └── 其他工具 → 读取自己的扩展配置

2. name、version、description 是干什么的?

核心思路(一句话)

这三个字段描述一个 npm 包"是谁、什么版本、做什么"。

json 复制代码
{
  "name": "vue",
  "version": "3.5.0",
  "description": "The progressive JavaScript framework"
}

name

包名。

bash 复制代码
npm install vue

这里的:

text 复制代码
vue

就是 name。


version

包版本,通常遵循语义化版本规范:

text 复制代码
MAJOR.MINOR.PATCH
主版本.次版本.修订版本

例如:

text 复制代码
3.5.0

description

包的描述信息,主要用于 npm 生态展示和搜索等场景。


3. main 是什么?它和 module 有什么区别?

这是最值得重点掌握的地方之一。

核心思路(一句话)

main 是传统 CommonJS 入口声明;module 是生态约定的 ES Module 入口声明,module 并不是 Node.js package.json 的标准字段。

例如:

json 复制代码
{
  "main": "dist/index.cjs",
  "module": "dist/index.js"
}

可以简单理解:

text 复制代码
消费者
   │
   └── import / require
          │
          ├── require(...)
          │
          │     └── 通常优先考虑 main
          │
          └── import ...
                │
                └── 构建工具可能优先使用 module

但这里一定要注意:

不能简单理解成"import 一定读 module,require 一定读 main"。

现代 Node.js 的模块解析主要由:

text 复制代码
exports
imports
type
main

等字段共同决定。而:

text 复制代码
module

更多是打包工具生态形成的约定。


4. module 为什么存在?

核心思路(一句话)

因为很多构建工具希望拿到 ES Module 版本,从而进行静态分析和 Tree Shaking。

假设:

json 复制代码
{
  "main": "dist/index.cjs",
  "module": "dist/index.js"
}

其中:

text 复制代码
dist/index.cjs
      ↓
CommonJS

dist/index.js
      ↓
ES Module

构建工具如果能够使用:

text 复制代码
dist/index.js

就可以更容易分析:

js 复制代码
export function foo() {}

export function bar() {}

然后:

text 复制代码
应用只使用 foo
      ↓
构建工具静态分析
      ↓
发现 bar 没被使用
      ↓
Tree Shaking
      ↓
删除 bar

所以:

module 的核心价值不是"让 import 能运行",而是给构建工具提供 ES Module 入口。


5. exports 是什么?为什么现代项目越来越重要?

这是一个高级面试重点。

核心思路(一句话)

exports 是用来规定这个包对外暴露哪些入口,以及不同调用方式或运行环境下该加载哪个文件,它还定义了 package 的公开 API 边界。

例如:

json 复制代码
{
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "require": "./dist/index.cjs"
    },
    "./utils": {
      "import": "./dist/utils.js",
      "require": "./dist/utils.cjs"
    }
  }
}

于是:

js 复制代码
import xxx from "my-package";

可以映射到:

text 复制代码
./dist/index.js

而:

js 复制代码
const xxx = require("my-package");

可以映射到:

text 复制代码
./dist/index.cjs

还可以:

js 复制代码
import { xxx } from "my-package/utils";

映射:

text 复制代码
./dist/utils.js

更重要的一点

exports 还可以限制:

text 复制代码
用户只能访问:
my-package
my-package/utils

不能直接访问:
my-package/dist/internal.js

所以高级面试可以直接说:

exports 不只是入口映射,它还定义了 package 的公开 API 边界。


6. types / typings 是什么?

核心思路(一句话)

它告诉 TypeScript:这个 npm 包的类型声明文件在哪里。

例如:

json 复制代码
{
  "main": "dist/index.js",
  "types": "dist/index.d.ts"
}

代码:

text 复制代码
业务代码
   │
   └── import xxx from "my-package"
                  │
                  ├── 运行时
                  │     ↓
                  │   dist/index.js
                  │
                  └── 类型检查
                        ↓
                     dist/index.d.ts

这里要注意:

text 复制代码
types
typings

是 TypeScript 生态使用的字段。它不是"Node.js 运行时执行时去加载类型"。

类型声明主要服务于 TypeScript 编译器、编辑器等工具。


7. files 是什么?

核心思路(一句话)

files 控制 npm 发布包时,哪些文件会被打进最终的 npm package。

例如:

json 复制代码
{
  "files": [
    "dist",
    "index.d.ts"
  ]
}

执行:

bash 复制代码
npm publish

最终发布到 npm 的内容不会简单等于整个项目目录。可以理解成:

text 复制代码
项目源码
│
├── src
├── dist
├── test
├── docs
├── node_modules
├── .git
└── package.json
       │
       ↓
   npm publish
       │
       ↓
   根据发布规则筛选
       │
       ↓
   npm package

所以:

text 复制代码
files

解决的是:

"这个包发布出去以后,消费者能拿到哪些文件?"


8. files 和 .npmignore 有什么区别?

核心思路(一句话)

files 是"明确允许发布什么",.npmignore 是"明确排除什么",两者共同影响 npm 包最终内容。

例如:

json 复制代码
{
  "files": [
    "dist"
  ]
}

表示主要发布:

text 复制代码
dist/

这也是为什么你:

bash 复制代码
npm install vue

之后看到的包内容,和 Vue GitHub 源码仓库里的完整内容完全不同。

面试重点

不要说:

files 决定 npm 上传哪些文件。

更准确地说:

files 参与决定 npm package 中最终包含哪些文件。

因为 npm 还有默认包含/排除规则以及 .npmignore 等因素。


9. sideEffects 是什么?为什么会影响 Tree Shaking?

核心思路(一句话)

sideEffects 是给打包工具提供"模块是否存在顶层副作用"的信息,从而帮助它安全地删除未使用模块。

例如:

json 复制代码
{
  "sideEffects": false
}

表示:

这个包中的模块可以被认为没有需要保留的顶层副作用。

例如:

js 复制代码
// utils.js
export function add(a, b) {
  return a + b;
}

如果:

js 复制代码
import { add } from "./utils.js";

构建工具发现其他东西没用到,就可以删除无关代码。


但 sideEffects: false 不能乱写

例如:

js 复制代码
// polyfill.js

window.foo = 'bar';

虽然没有导出:

js 复制代码
export ...

但是:

js 复制代码
import "./polyfill.js";

依然有意义。这就是:

text 复制代码
副作用

如果错误配置:

json 复制代码
{
  "sideEffects": false
}

构建工具可能认为这个模块可以删除,导致程序行为发生变化。所以高级回答应该强调:

sideEffects 的核心是帮助构建工具判断"未被直接引用的模块能不能删",配置错误可能导致代码被错误 Tree Shaking。


10. repository 是什么?

核心思路(一句话)

repository 描述这个 npm 包对应的源码仓库地址。

例如:

json 复制代码
{
  "repository": {
    "type": "git",
    "url": "https://github.com/example/project.git"
  }
}

主要用于:

text 复制代码
npm
GitHub
开发者工具
生态平台

定位源码仓库。


11. keywords 是什么?

核心思路(一句话)

keywords 是 npm 包的搜索关键词,帮助用户发现这个包。

例如:

json 复制代码
{
  "keywords": [
    "vue",
    "reactivity",
    "javascript",
    "frontend"
  ]
}

12. author、license、bugs、homepage 是什么?

这些属于包的元数据。

字段 作用
author 作者信息
license 开源许可证
bugs Bug 反馈地址
homepage 项目主页

例如:

json 复制代码
{
  "author": "xxx",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/example/project/issues"
  },
  "homepage": "https://example.com"
}

面试不需要展开太多。


13. dependencies 是什么?

核心思路(一句话)

dependencies 是运行这个包所需要的依赖。

例如:

json 复制代码
{
  "dependencies": {
    "axios": "^1.0.0"
  }
}

意思是:

text 复制代码
我的项目运行
   ↓
需要 axios
   ↓
所以 axios 属于运行时依赖

14. devDependencies 是什么?

核心思路(一句话)

devDependencies 是开发、测试、构建过程中需要,但通常不是这个包运行时直接需要的依赖。

例如:

json 复制代码
{
  "devDependencies": {
    "webpack": "^5.0.0",
    "typescript": "^5.0.0",
    "eslint": "^9.0.0"
  }
}

典型:

text 复制代码
Webpack
TypeScript
ESLint
Jest
测试工具
构建工具

15. dependencies、devDependencies、peerDependencies 怎么区分?

这是非常高频的面试题。

核心思路(一句话)

dependencies 是"我运行需要它",devDependencies 是"我开发需要它",peerDependencies 是"我要求使用我的人提供兼容版本"。

例如开发一个 React 组件库:

json 复制代码
{
  "peerDependencies": {
    "react": ">=18"
  },
  "devDependencies": {
    "react": "^19.0.0",
    "typescript": "^5.0.0"
  }
}

为什么 React 放 peerDependencies?因为组件库通常不应该自己再带一份 React。

否则可能出现:

text 复制代码
业务项目
 │
 ├── React A
 │
 └── 组件库
       │
       └── React B

最终可能出现:

text 复制代码
两个 React 实例
       ↓
运行时问题

所以:

组件库需要 React,但 React 应该由宿主项目提供。

这就是 peerDependencies 的典型场景。


16. browser 是什么?

核心思路(一句话)

browser 是一个生态约定字段,用于告诉某些构建工具:当这个包运行在浏览器环境时,应该使用哪个入口或替换哪些 Node.js 模块。

例如:

json 复制代码
{
  "main": "./dist/index.js",
  "browser": "./dist/index.browser.js"
}

或者:

json 复制代码
{
  "browser": {
    "fs": false
  }
}

意思可以理解为:

text 复制代码
Node 环境
   ↓
使用 Node 版本

浏览器环境
   ↓
使用 browser 对应版本

17. type 是什么?为什么它很重要?

核心思路(一句话)

type 决定 .js 文件在 Node.js 中默认按照 CJS 还是 ESM 解释。

例如:

json 复制代码
{
  "type": "module"
}

那么:

js 复制代码
// index.js

import fs from "node:fs";

会按照 ECMAScript Module 解释。如果:

json 复制代码
{
  "type": "commonjs"
}

则 .js 默认按照 CommonJS 解释。还可以通过:

text 复制代码
.mjs
.cjs

明确指定模块类型。

注意

type 主要影响 Node.js 对 .js 文件模块类型的解释;它不是简单地决定所有工具的模块解析策略。


18. module、types、exports 的定位不能混为一谈

可以直接用这张图记:

text 复制代码
                     package.json
                          │
       ┌──────────────────┼──────────────────┐
       ↓                  ↓                  ↓
    Node.js            构建工具            TypeScript
       │                  │                  │
       │                  │                  │
   exports/main        module/browser      types
       │                  │                  │
       ↓                  ↓                  ↓
  运行时模块入口       构建时模块入口       类型声明

现代包还可以进一步:

text 复制代码
exports
   │
   ├── import
   ├── require
   ├── browser
   ├── node
   ├── development
   └── production

因此不能简单说:

text 复制代码
import → module
require → main

高级回答一定要把:

text 复制代码
Node.js 原生解析
构建工具解析
TypeScript 类型解析

分开。


19. package.json 字段到底应该怎么记?

不要按照顺序死记。建议按照"谁读取、解决什么问题"记。

text 复制代码
package.json
│
├── 包是谁
│   ├── name
│   ├── version
│   └── description
│
├── 包怎么被使用
│   ├── exports      ← 现代核心入口/导出边界
│   ├── main         ← 传统入口
│   ├── module       ← 构建工具生态约定
│   ├── browser      ← 浏览器环境约定
│   ├── types        ← TypeScript 类型入口
│   └── type         ← Node.js 模块类型
│
├── 发布什么
│   └── files
│
├── 如何优化构建
│   └── sideEffects
│
├── 依赖什么
│   ├── dependencies
│   ├── devDependencies
│   ├── peerDependencies
│   └── optionalDependencies
│
└── 项目元数据
    ├── keywords
    ├── author
    ├── license
    ├── repository
    ├── bugs
    └── homepage

20. 面试满分答案

面试官:你对 package.json 了解多少?

package.json 可以理解成一个 npm 包的"说明书和入口配置",它不仅描述包的基本信息,还会影响包怎么被发布、怎么被 Node.js 和构建工具解析,以及它有哪些依赖。

我一般把它分成四类来看。

第一类是包的基本信息 ,比如 name、version、description、keywords、author、license、repository 等。

第二类是模块入口和导出规则 ,这是前端工程里比较重要的一部分。传统上有 main 指定 CommonJS 等场景下的入口,module 是构建工具生态中约定的 ES Module 入口,types 或 typings 指定 TypeScript 类型声明。现代 npm 包更重要的是 exports,它不仅可以根据 import、require、浏览器、Node.js 等条件选择不同入口,还可以限制包对外暴露的模块边界。

第三类是发布和构建相关配置 。files 控制 npm 包发布时哪些文件进入最终 package;sideEffects 则给 Webpack、Rollup 等构建工具提供副作用信息,帮助 Tree Shaking 判断哪些模块可以安全删除。

第四类是依赖管理 。dependencies 是运行时依赖,devDependencies 是开发、测试和构建依赖,peerDependencies 则表示这个包要求宿主项目提供兼容版本,组件库依赖 React、Vue 这类宿主框架时非常常见。

所以我认为理解 package.json 最重要的不是背字段,而是知道每个字段是谁读取、解决什么问题,以及它最终影响的是运行时、构建时、类型检查还是 npm 发布过程。

相关推荐
CappuccinoRose1 小时前
输入事件进阶
前端·javascript·输入事件
liangshanbo12153 小时前
面试题:前端工程化中 Tree Shaking的原理是什么?
前端·treeshaking
补码缩写3 小时前
视频跳转触发了seeked,画面就到位了吗
前端
库拉镜像AI牛牛4 小时前
漫剧工作室量产方案:依托知漫剧 AI 短剧降本增效
大数据·服务器·前端·人工智能·语音识别
不可能片场4 小时前
内容运营自动化 用相似度拦住撞车选题
前端·electron
静默回滚4 小时前
视频进度条跳回去,先别改事件监听
前端
Lank_M4 小时前
MP4和WebM导出后为何起播与拖动不同
前端
用户5508492902564 小时前
前端本地存储怎么选:Cookie、localStorage、sessionStorage、IndexedDB 的取舍
前端
用户5508492902564 小时前
Git 日常命令与分支协作流程:从提交到合并的实战梳理
前端