DrillLab
第 03 / 09 节LESSON 03 / 09约 13 分钟~13 min

npm scripts:命令到底跑了什么npm scripts: what the command actually runs

npm test 和 npm run test 有什么区别,以及 react-notes-app 为什么根本跑不了 npm test。How npm test differs from npm run test, and why npm test cannot run at all in react-notes-app.

2 个练习2 exercises地基 · 第 1 部分Foundations · Part 1
这一页有什么On this page6
学完这节你会After this lesson you can
  • 看懂 scripts 里每条命令实际调用了什么程序Read a line in scripts and say which program it really calls
  • 解释 npm test 和 npm run test 的区别,以及为什么有些命令不用加 runExplain how npm test differs from npm run test, and why some commands do not need run
  • 知道项目里没有 test script 时该怎么跑测试Know how to run the tests when the project has no test script
  • 拿到报错时知道先看哪一层Know which layer to look at first when you get an error
这在考试里考什么What the exam does with this

react-notes-app 的 package.json 里没有 test script —— 直接跑 npm test 会报 Missing script。判卷靠的却正是那四个测试。跑不起来测试,等于蒙着眼睛答题。The package.json of react-notes-app has no test script, so npm test reports Missing script. Yet your work is graded by exactly those four tests. If you cannot run them, you are answering without being able to check anything.

这节课要看的真实文件Real files this lesson looks at2 项 · 2 个可以展开看原文2 items · 2 can be opened
react-notes-app/package.json只有 dev / build / q2 三个 scriptOnly three scripts: dev, build and q2
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.json有 start / test / test:watchHas start, test and test:watch
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

npm run 做的事情比你想的简单npm run does less than you might think

它就是在 node_modules/.bin 加进 PATH 之后,执行你写的那行字符串。It adds node_modules/.bin to PATH, then runs the line of text you wrote.

"dev": "vite" 的意思不是「npm 认识 vite」, 而是:npm 把 node_modules/.bin 临时加进 PATH, 然后执行 vite 这个命令。而 node_modules/.bin/vite正是 npm install 时,vite 这个包自己放进去的可执行文件。

所以「命令找不到」几乎总是意味着两件事之一:依赖没装,或者你在错误的目录里跑(比如在仓库根目录跑本该在 node-subgraph/ 里跑的命令)。

"dev": "vite" does not mean “npm knows about vite”. It means: npm temporarily adds node_modules/.bin to PATH, then runs the command vite. And node_modules/.bin/vite is exactly the executable the vite package dropped in there during npm install.

So “command not found” nearly always means one of two things: dependencies were never installed, or you are running it in the wrong directory (say, at the repo root when the command belongs inside node-subgraph/).

Terminal源项目From source
1# react-notes-app 的三条 script,展开后实际执行的是:
2npm run dev # → vite 起开发服务器
3npm run build # → tsc && vite build 先类型检查,过了再打包
4npm run q2 # → tsx q2/demo.ts 用 tsx 直接跑 TypeScript 文件
1# the three scripts of react-notes-app, and what each really runs:
2npm run dev # → vite start the dev server
3npm run build # → tsc && vite build type-check first, bundle after it passes
4npm run q2 # → tsx q2/demo.ts run a TypeScript file directly with tsx
Source: react-notes-app/package.json
§02

npm test 和 npm run test:为什么有的能省掉 runnpm test and npm run test: why run can be left out for some names

npm 给少数几个名字开了后门,可以省掉 run: teststartstoprestart。所以 npm testnpm run test, npm startnpm run start

其他名字都必须写 runnpm build 不会跑你的 build script —— 实测它直接报 Unknown command: "build", 下面还跟一句 Did you mean this? npm run build。 npm 把答案告诉你了,照着写 npm run build 就行。 这是新手最常见的困惑之一。

但「能省掉 run」不代表「这个 script 一定存在」。这就是下一段的坑。

npm keeps a back door open for a handful of names, where you can drop the run: test, start, stop, restart. So npm test npm run test, and npm start npm run start.

Every other name needs run. npm build will not run your build script — measured, it prints Unknown command: "build" followed by Did you mean this? npm run build. npm hands you the answer; write npm run build as it says. This is one of the most common beginner confusions.

But “you can drop the run” does not mean “that script exists”. Which is the trap in the next section.

§03

实测:react-notes-app 跑不了 npm testTried for real: npm test does not work in react-notes-app

这不是你的错,是这个项目的 scripts 里真的没有 test。This is not your mistake. The scripts of this project really have no test entry.

回头看它的 scripts:只有 devbuildq2没有 test。但项目里明明有 src/NoteManager.test.tsx, vite.config.ts 里也明明配了 vitest。

那怎么跑?两条路:

  • npx vitest run —— npx 会去node_modules/.bin 里找 vitest 并执行。run 子命令表示「跑一遍就退出」,不加它会进 watch 模式一直挂着。
  • 自己往 package.json 里加一条"test": "vitest run"。 考试时要谨慎 —— 除非题目允许你改配置,否则用 npx 更安全。

Look at its scripts again: only dev, build, q2. No test. And yet the project plainly has src/NoteManager.test.tsx, and vite.config.ts plainly configures vitest.

So how do you run them? Two ways:

  • npx vitest runnpx goes into node_modules/.bin, finds vitest and runs it. The run subcommand means “go once and exit”; leave it off and you land in watch mode, hanging around.
  • Add a line to package.json yourself: "test": "vitest run". Be careful during an exam — unless the task says you may edit config, npx is safer.
Terminal本机实测输出Output measured on this machine已跑通Verified
1$ npm test
2npm error Missing script: "test"
3npm error
4npm error To see a list of scripts, run:
5npm error npm run
6
7$ npx vitest run
8 RUN v4.1.10 react-notes-app
9
10 Test Files 1 passed (1)
11 Tests 4 passed (4)
12 Duration 1.19s
注意 npm 自己给了台阶:「运行 npm run 看有哪些 script」。这条提示值得记住 —— 任何项目里,光跑 npm run(不带名字)就会列出所有可用命令。Notice that npm offers the way out itself: run npm run to see which scripts exist. That is worth remembering — in any project, npm run with no name lists every available command.
§04

script 报错了,先看哪一层A script failed: which layer to check first

一条 script 失败,报错可能来自三层。按顺序排除:

  1. npm 层。「Missing script」「ENOENT: no such file or directory package.json」—— 这说明命令根本没开始跑。检查:名字打对了吗?在对的目录吗?
  2. 工具层。「command not found: vite」「Cannot find module 'jest'」—— 工具本身没装好。检查:npm install 跑过吗?
  3. 你的代码层。「TS2304: Cannot find name 'expect'」「TypeError: x is not a function」—— 这层才是真的在说你的代码(或者项目自带配置)有问题。

新手最容易犯的错是看到红字就开始改业务代码, 而错误其实在第 1 层或第 2 层。先分层,再动手。

When a script fails, the error can come from three layers. Rule them out in order:

  1. The npm layer.“Missing script”, “ENOENT: no such file or directory package.json” — the command never started. Check: did you spell the name right? Are you in the right directory?
  2. The tool layer.“command not found: vite”, “Cannot find module 'jest'” — the tool itself is not installed properly. Check: did npm install actually run?
  3. Your code layer.“TS2304: Cannot find name 'expect'”, “TypeError: x is not a function” — this layer is the first one really telling you something is wrong with your code (or with the config the project shipped).

The beginner mistake is seeing red text and going straight to the business code when the error was in layer 1 or layer 2. Sort the layer first, then touch anything.

练习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.

L1认出来Spot it怎么跑 react-notes-app 的测试How to run the tests of react-notes-app

你在 react-notes-app/ 目录下,想跑那 4 个判卷测试。 package.json 的 scripts 只有 devbuildq2。下面哪个命令能跑起来?

You are inside react-notes-app/ and want to run those 4 grading tests. The scripts in package.json are only dev, build and q2. Which command works?

先选一个选项Pick an option first
L1排顺序Order itscript 报错了,按什么顺序排查A script failed: in what order do you check things

把排查顺序排对。从最外层(还没开始跑)到最里层(你的代码)。

Put the checks in order, from the outermost layer (nothing has started yet) to the innermost one (your own code).

1读报错里的具体类型/文件/行号,判断是业务代码还是项目配置Read the exact type, file and line number in the error, and decide whether it is your code or the project config
2确认命令名和当前目录对不对(npm run 列一下)Check the command name and the current directory (run npm run to list them)
3确认 npm install 跑过、node_modules 在Check that npm install has run and node_modules exists
迁移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.

Missing script: "test"Missing script: "test"
npx <工具> 或先跑 npm run 看清单Run npx <tool>, or run npm run first to list the scripts
command not found: vitecommand not found: vite
先 npm install,再确认目录Run npm install, then check you are in the right directory
npm build 报 Unknown commandnpm build says Unknown command
只有 test/start/stop/restart 能省 run,其余都要写 npm run <名字>Only test, start, stop and restart may drop run. Everything else needs npm run <name>
build 失败但 dev 正常build fails but dev works
大概是类型检查(tsc)那一步,不是打包Probably the type-checking step (tsc), not the bundling step
这节的要点What to take away
  1. npm run <名字> = 把 node_modules/.bin 加进 PATH 后执行那行字符串。npm run <name> adds node_modules/.bin to PATH, then runs that line of text.
  2. 只有 test/start/stop/restart 能省掉 run,其他都要写 npm run。Only test, start, stop and restart can drop run. Everything else needs npm run.
  3. 跑 npm run 不带名字,会列出这个项目所有可用命令。Running npm run with no name lists every command this project offers.
  4. react-notes-app 没有 test script,要用 npx vitest run。react-notes-app has no test script. Use npx vitest run instead.
  5. 报错先分层:npm 层 → 工具层 → 代码层。别一看红字就改业务代码。Sort an error into a layer first: npm, then the tool, then your code. Do not edit your own code the moment you see red text.

接下来What next

  1. 把这一节的练习做掉Do this lesson’s exercises2 个,就在这一页上面 —— 别攒着最后一起做2 of them, further up this page — do not save them for later
    回到练习 ↑Back up to them ↑
  2. 接着看下一节Continue to the next lesson两个考试项目的目录,逐个说明The directory layout of both exam projects
    下一节Next lesson
读完并且做过上面的练习了吗?Read it and worked through the exercises above?
上一节:Previous: package.json 逐字段读一遍package.json, field by field