DrillLab
第 02 / 09 节LESSON 02 / 09约 14 分钟~14 min

package.json 逐字段读一遍package.json, field by field

拿两个真实 assessment 的 package.json,一个字段一个字段地读懂。Take the package.json of both real exam projects and read them one field at a time.

1 个练习1 exercises地基 · 第 1 部分Foundations · Part 1
这一页有什么On this page6
学完这节你会After this lesson you can
  • 认得 name / version / private / type / main / scripts 各是干什么的Recognise what name, version, private, type, main and scripts each control
  • 知道 "type": "module" 会怎样改变 import 的写法Know how "type": "module" changes the way you write import
  • 能从一个陌生的 package.json 判断出这个项目怎么跑、用什么测试Work out from an unfamiliar package.json how the project runs and which test tool it uses
  • 知道配置也可以内嵌在 package.json 里(subgraph 的 jest 配置就是)Know that configuration can also sit inside package.json, as the jest config of the subgraph does
这在考试里考什么What the exam does with this

考场上没人会告诉你「这个项目怎么跑」。package.json 就是答案本身。看懂它,等于拿到了考场地图。In an exam nobody tells you how to run the project. package.json is the answer itself. Read it and you have the map of the exam.

这节课要看的真实文件Real files this lesson looks at2 项 · 2 个可以展开看原文2 items · 2 can be opened
react-notes-app/package.jsonReact 考试The React exam
JSONpackage.json源项目From source
1{
2 "name": "react-notes-app",
3 "private": true,
4 "version": "1.0.0",
5 "type": "module",
6 "scripts": {
7 "dev": "vite",
8 "build": "tsc && vite build",
9 "q2": "tsx q2/demo.ts"
10 },
11 "dependencies": {
12 "react": "^18.3.1",
13 "react-dom": "^18.3.1"
14 },
15 "devDependencies": {
16 "@testing-library/jest-dom": "^7.0.0",
17 "@testing-library/react": "^16.3.2",
18 "@testing-library/user-event": "^14.6.1",
19 "@types/react": "^18.3.3",
20 "@types/react-dom": "^18.3.0",
21 "@vitejs/plugin-react": "^4.3.1",
22 "jsdom": "^29.1.1",
23 "tsx": "^4.16.2",
24 "typescript": "^5.5.3",
25 "vite": "^5.4.0",
26 "vitest": "^4.1.10"
27 }
28}
Source: react-notes-app/package.json
graphql-federation-practice/node-subgraph/package.jsonFederation 考试的 Node 部分The Node half of the Federation exam
JSONpackage.json源项目From source
1{
2 "name": "order-subgraph",
3 "version": "1.0.0",
4 "description": "GraphQL Federation Subgraph for Order Management",
5 "main": "src/index.js",
6 "type": "module",
7 "scripts": {
8 "start": "node src/index.js",
9 "test": "NODE_OPTIONS=--experimental-vm-modules jest",
10 "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch"
11 },
12 "dependencies": {
13 "@apollo/server": "^4.10.0",
14 "@apollo/subgraph": "^2.7.0",
15 "graphql": "^16.8.1",
16 "graphql-tag": "^2.12.6",
17 "dataloader": "^2.2.2"
18 },
19 "devDependencies": {
20 "jest": "^29.7.0",
21 "@jest/globals": "^29.7.0"
22 },
23 "jest": {
24 "testEnvironment": "node",
25 "transform": {},
26 "testMatch": ["**/__tests__/**/*.test.js"]
27 }
28}
Source: graphql-federation-practice/node-subgraph/package.json
§01

先读 React 考试的这一份Start with the one from the React exam

整个文件只有 7 个顶层字段。逐个看。The whole file has only 7 top-level fields. Go through them one by one.

下面这份是原样从项目里拿出来的,一个字都没改:

The file below was copied verbatim out of the project. Not one character changed:

JSONpackage.json源项目From source
1{
2 "name": "react-notes-app",
3 "private": true,
4 "version": "1.0.0",
5 "type": "module",
6 "scripts": {
7 "dev": "vite",
8 "build": "tsc && vite build",
9 "q2": "tsx q2/demo.ts"
10 },
11 "dependencies": {
12 "react": "^18.3.1",
13 "react-dom": "^18.3.1"
14 },
15 "devDependencies": {
16 "@testing-library/jest-dom": "^7.0.0",
17 "@testing-library/react": "^16.3.2",
18 "@testing-library/user-event": "^14.6.1",
19 "@types/react": "^18.3.3",
20 "@types/react-dom": "^18.3.0",
21 "@vitejs/plugin-react": "^4.3.1",
22 "jsdom": "^29.1.1",
23 "tsx": "^4.16.2",
24 "typescript": "^5.5.3",
25 "vite": "^5.4.0",
26 "vitest": "^4.1.10"
27 }
28}
Source: react-notes-app/package.json
§02

字段逐条解释Every field, one by one

字段这份文件里的值它在管什么
name"react-notes-app"包名。发布到 npm 时是唯一标识;不发布的话只是个名字。
privatetrue「这个包不许被发布到 npm」。手滑跑了 npm publish 会被拦下来。练习/考试项目基本都会写它。
version"1.0.0"本项目自己的版本号。不发布的话没什么实际作用,但字段得在。
type"module"关键字段。告诉 Node「本项目的 .js 文件按 ES Module 解析」,于是能用 import / export,不能用 require
scriptsdev / build / q2可以用 npm run <名字> 跑的快捷命令。下一节专门讲。
dependenciesreact、react-dom产品运行时需要的包。
devDependencies11 个开发、构建、测试用的包。

只看这 7 个字段,你已经能推出一堆事实:这是个用 Vite 打包的React 18 + TypeScript 项目,测试用Vitest + Testing Library,DOM 环境靠jsdom 模拟,另外还有一个用 tsx 直接跑 TypeScript 的独立小题(q2)。

FieldValue in this fileWhat it controls
name"react-notes-app"The package name. A unique identity if you publish to npm; just a name if you do not.
privatetrue“This package must not be published to npm.” A slip of the finger running npm publish gets blocked. Practice and exam projects almost always set it.
version"1.0.0"This project’s own version number. It does nothing much if you never publish, but the field has to be there.
type"module"The field that matters. It tells Node “parse this project’s .js files as ES Modules”, so import / export work and require does not.
scriptsdev / build / q2Shortcut commands you can run with npm run <name>. The next lesson is all about these.
dependenciesreact, react-domPackages the product needs at runtime.
devDependencies11 of themPackages for developing, building and testing.

From those 6 fields alone you can already work out a pile of facts: this is a React 18 + TypeScript project bundled by Vite, tested with Vitest + Testing Library, with the DOM faked by jsdom, plus one standalone side question (q2) that runs TypeScript directly through tsx.

§03

再读 Federation 考试那一份Now the one from the Federation exam

同样的读法,但多了两个新东西:main 和内嵌配置。Read it the same way. Two things are new here: main, and configuration kept inside the file.

这一份多出 main(包的入口文件)、description, 以及最要紧的一处:jest 的配置直接内嵌在 package.json 里, 没有单独的 jest.config.js

这一点很容易踩坑 —— 你在项目里翻半天找不到测试配置文件, 以为项目没配好,其实它就在 package.json 的最后几行。 很多工具(jest、eslint、prettier、babel)都支持这种内嵌写法。

This one adds main (the package entry file) and description, plus the part most worth staring at: the jest config is embedded straight into package.json. There is no separate jest.config.js.

That trips people up — you dig through the project for a test config file, find nothing, decide the project was never set up properly, and it was sitting in the last few lines of package.json the whole time. Plenty of tools (jest, eslint, prettier, babel) accept this embedded form.

JSONnode-subgraph/package.json源项目From source
1{
2 "name": "order-subgraph",
3 "version": "1.0.0",
4 "description": "GraphQL Federation Subgraph for Order Management",
5 "main": "src/index.js",
6 "type": "module",
7 "scripts": {
8 "start": "node src/index.js",
9 "test": "NODE_OPTIONS=--experimental-vm-modules jest",
10 "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch"
11 },
12 "dependencies": {
13 "@apollo/server": "^4.10.0",
14 "@apollo/subgraph": "^2.7.0",
15 "graphql": "^16.8.1",
16 "graphql-tag": "^2.12.6",
17 "dataloader": "^2.2.2"
18 },
19 "devDependencies": {
20 "jest": "^29.7.0",
21 "@jest/globals": "^29.7.0"
22 },
23 "jest": {
24 "testEnvironment": "node",
25 "transform": {},
26 "testMatch": ["**/__tests__/**/*.test.js"]
27 }
28}
Source: graphql-federation-practice/node-subgraph/package.json
§04

拿到陌生 package.json 的三步读法Three steps for reading a package.json you have never seen

  1. 先看 scripts。这决定了你能跑什么命令。 有 dev 就说明能起开发服务器,有 test就说明能跑测试,没有 test 就得自己想办法(下一节讲)。
  2. 再看 dependencies。看见 react 就知道是前端; 看见 @apollo/server + @apollo/subgraph就知道是 GraphQL 联邦的一个 subgraph;看见 dataloader就知道这题大概会考批量加载。
  3. 最后看 type 和内嵌配置。"type": "module" 决定 import 的写法, 内嵌的 jest/eslint 配置决定测试怎么被发现。

第 2 步尤其重要:依赖清单本身就在泄题。subgraph 的 dependencies 里明摆着一个 dataloader, 而 starter 代码里正好有个 TODO 写着「用 DataLoader 防 N+1」—— 这不是巧合。

  1. Read scripts first. It decides which commands you can run. A dev entry means there is a dev server; a test entry means you can run tests; no test entry means you have to work something out yourself (next lesson).
  2. Then read dependencies. Spot react and you know it is frontend; spot @apollo/server + @apollo/subgraph and you know it is one subgraph of a GraphQL federation; spot dataloader and you can bet batch loading is on the test.
  3. Read type and the embedded config last. "type": "module" decides how imports get written, and an embedded jest/eslint config decides how tests get found.

Step 2 matters most: the dependency list leaks the questions. The subgraph has dataloader sitting right there in dependencies, and the starter code happens to carry a TODO saying “use DataLoader to avoid N+1” — that is no coincidence.

练习Practice

动手做Get your hands on it

填空只是过渡。真正掌握的标准,是在没有答案的时候从头写出来 —— 所以做完 L2 之后一定要往 L3、L4 走。Filling blanks is a stepping stone. The real bar is writing it from nothing, so once L2 is comfortable, push on to L3 and L4.

L2填空Fill the blanks补全 subgraph 的 package.json 关键字段Fill in the key fields of the subgraph package.json

下面是 node-subgraph/package.json 的骨架,挖掉了三个决定项目行为的值。 照真实文件补回来。

Below is the skeleton of node-subgraph/package.json with three values removed. Each one decides how the project behaves. Put them back the way the real file has them.

JSONnode-subgraph/package.json3 个空3 blanks
1{
2 "name": "order-subgraph",
3 "main": "src/index.js",
4 "type": "",
5 "scripts": {
6 "start": "node src/index.js",
7 "test": "NODE_OPTIONS=--experimental-vm-modules "
8 },
9 "dependencies": {
10 "@apollo/server": "^4.10.0",
11 "@apollo/subgraph": "^2.7.0",
12 "graphql": "^16.8.1",
13 "graphql-tag": "^2.12.6",
14 "": "^2.2.2"
15 }
16}
把 3 个空都填上才能检查(还差 3 个)Fill all 3 blanks to check (3 to go)
迁移Transfer

换一道题也能用Works on other problems too

考试不会原题重考。真正能带走的是「看到这种信号 → 伸手去拿这个解法」。The exam will not reuse the same question. What you take away is the reflex: see this signal, reach for that solution.

不知道项目怎么跑You do not know how to run the project
读 package.json 的 scriptsRead the scripts field in package.json
不知道这题要考什么You do not know what a question is testing
读 dependencies,特殊的包就是考点Read dependencies. An unusual package is the topic
找不到 jest / eslint 配置文件You cannot find a jest or eslint config file
看 package.json 里有没有同名内嵌字段Check package.json for a field with the same name
import 报 Cannot use import statementimport fails with Cannot use import statement
检查 "type": "module"Check "type": "module"
这节的要点What to take away
  1. package.json 的 scripts 决定你能跑什么命令,是拿到项目第一个要读的字段。The scripts in package.json decide which commands you can run. It is the first field to read.
  2. "type": "module" 决定源码用 ESM 还是 CommonJS,直接影响 import 能不能写。"type": "module" decides whether the source uses ESM or CommonJS, so it decides whether you can write import.
  3. private: true 只是防止误发布,与能不能跑无关。private: true only stops the package from being published by mistake. It has nothing to do with running it.
  4. 配置可以内嵌:subgraph 的 jest 配置就在 package.json 里,不在单独文件。Configuration can live inside package.json. The jest config of the subgraph is there, not in a separate file.
  5. dependencies 里出现 dataloader 这种特征包,基本等于告诉你考点在哪。A telling package such as dataloader in dependencies almost always shows you what the exam will test.

接下来What next

  1. 把这一节的练习做掉Do this lesson’s exercises1 个,就在这一页上面 —— 别攒着最后一起做1 of them, further up this page — do not save them for later
    回到练习 ↑Back up to them ↑
  2. 接着看下一节Continue to the next lessonnpm scripts:命令到底跑了什么npm scripts: what the command actually runs
    下一节Next lesson
读完并且做过上面的练习了吗?Read it and worked through the exercises above?
上一节:Previous: Node.js、npm、node_modules 和 lockfileNode.js, npm, node_modules and the lockfile