欢迎光临
我们一直在努力

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

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

核心思路(一句话)

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

可以从 4 个维度理解:

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
└── 其他工具自定义字段

主要矛盾

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

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

例如:

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


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

核心思路(一句话)

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

{
"name": "vue",
"version": "3.5.0",
"description": "The progressive JavaScript framework"
}

name

包名。

npm install vue

这里的:

vue

就是 name。


version

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

MAJOR.MINOR.PATCH
主版本.次版本.修订版本

例如:

3.5.0


description

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


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

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

核心思路(一句话)

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

例如:

{
"main": "dist/index.cjs",
"module": "dist/index.js"
}

可以简单理解:

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

但这里一定要注意:

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

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

exports
imports
type
main

等字段共同决定。而:

module

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


4. module 为什么存在?

核心思路(一句话)

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

假设:

{
"main": "dist/index.cjs",
"module": "dist/index.js"
}

其中:

dist/index.cjs
↓
CommonJS

dist/index.js
↓
ES Module

构建工具如果能够使用:

dist/index.js

就可以更容易分析:

export function foo() {}

export function bar() {}

然后:

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

所以:

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


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

这是一个高级面试重点。

核心思路(一句话)

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

例如:

{
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.cjs"
},
"./utils": {
"import": "./dist/utils.js",
"require": "./dist/utils.cjs"
}
}
}

于是:

import xxx from "my-package";

可以映射到:

./dist/index.js

而:

const xxx = require("my-package");

可以映射到:

./dist/index.cjs

还可以:

import { xxx } from "my-package/utils";

映射:

./dist/utils.js

更重要的一点

exports 还可以限制:

用户只能访问:
my-package
my-package/utils

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

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

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


6. types / typings 是什么?

核心思路(一句话)

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

例如:

{
"main": "dist/index.js",
"types": "dist/index.d.ts"
}

代码:

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

这里要注意:

types
typings

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

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


7. files 是什么?

核心思路(一句话)

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

例如:

{
"files": [
"dist",
"index.d.ts"
]
}

执行:

npm publish

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

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

所以:

files

解决的是:

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


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

核心思路(一句话)

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

例如:

{
"files": [
"dist"
]
}

表示主要发布:

dist/

这也是为什么你:

npm install vue

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

面试重点

不要说:

files 决定 npm 上传哪些文件。

更准确地说:

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

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


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

核心思路(一句话)

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

例如:

{
"sideEffects": false
}

表示:

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

例如:

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

如果:

import { add } from "./utils.js";

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


但 sideEffects: false 不能乱写

例如:

// polyfill.js

window.foo = 'bar';

虽然没有导出:

export …

但是:

import "./polyfill.js";

依然有意义。这就是:

副作用

如果错误配置:

{
"sideEffects": false
}

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

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


10. repository 是什么?

核心思路(一句话)

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

例如:

{
"repository": {
"type": "git",
"url": "https://github.com/example/project.git"
}
}

主要用于:

npm
GitHub
开发者工具
生态平台

定位源码仓库。


11. keywords 是什么?

核心思路(一句话)

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

例如:

{
"keywords": [
"vue",
"reactivity",
"javascript",
"frontend"
]
}


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

这些属于包的元数据。

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

例如:

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

面试不需要展开太多。


13. dependencies 是什么?

核心思路(一句话)

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

例如:

{
"dependencies": {
"axios": "^1.0.0"
}
}

意思是:

我的项目运行
↓
需要 axios
↓
所以 axios 属于运行时依赖


14. devDependencies 是什么?

核心思路(一句话)

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

例如:

{
"devDependencies": {
"webpack": "^5.0.0",
"typescript": "^5.0.0",
"eslint": "^9.0.0"
}
}

典型:

Webpack
TypeScript
ESLint
Jest
测试工具
构建工具


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

这是非常高频的面试题。

核心思路(一句话)

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

例如开发一个 React 组件库:

{
"peerDependencies": {
"react": ">=18"
},
"devDependencies": {
"react": "^19.0.0",
"typescript": "^5.0.0"
}
}

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

否则可能出现:

业务项目
│
├── React A
│
└── 组件库
│
└── React B

最终可能出现:

两个 React 实例
↓
运行时问题

所以:

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

这就是 peerDependencies 的典型场景。


16. browser 是什么?

核心思路(一句话)

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

例如:

{
"main": "./dist/index.js",
"browser": "./dist/index.browser.js"
}

或者:

{
"browser": {
"fs": false
}
}

意思可以理解为:

Node 环境
↓
使用 Node 版本

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


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

核心思路(一句话)

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

例如:

{
"type": "module"
}

那么:

// index.js

import fs from "node:fs";

会按照 ECMAScript Module 解释。如果:

{
"type": "commonjs"
}

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

.mjs
.cjs

明确指定模块类型。

注意

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


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

可以直接用这张图记:

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

现代包还可以进一步:

exports
│
├── import
├── require
├── browser
├── node
├── development
└── production

因此不能简单说:

import → module
require → main

高级回答一定要把:

Node.js 原生解析
构建工具解析
TypeScript 类型解析

分开。


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

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

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 发布过程。

赞(0)
未经允许不得转载:171主机测评 » 高级前端面试题:package.json 常见字段
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址