被忽视的 npm init

1,626 阅读3分钟

前言

前阵子在 Vite 文档 看到快速构建 Vite 工程的命令:

npm create vite@latest

第一次见过 npm create 命令,查阅后发现是 npm init 的别名,上面的命令等效于:

npm init vite@latest

不过,我之前也没见过 npm init 的这种用法。上面的命令猜测应该是下载并执行了 Vite 工程里的项目创建命令,这种执行远程命令的方式,我只知道 npx,比如 React 项目创建:

npx create-react-app my-app

看来,是我小看 npm init 了。于是,翻阅了一下文档,做个总结。

创建一个简单的 npm 包

执行命令

npm init

会询问用户几个问题,npm 根据用户的回答生成一个 package.json 文件。带有 package.json 文件的目录是一个 npm 包,这个命令也就是用于创建一个 npm 包。

选项 -y/--yes 可以跳过问题,使用默认值生成 package.json

如果你喜欢,手动创建 package.json 也是一样的效果。

指定初始化命令创建定制化包

在 npm 提供了 npx 之后,也拓展了 npm init 的能力:可以通过指定命令,创建一些特定结构的包。

npm init <initializer>

需要注意的一点是,<initializer> 指定的包名是 create-<initializer>。npm 会自动去找 create-<initializer> 包,如果本地不存在,就会从远程下载,并执行其 bin 目录下的主命令,这个命令一般用于修改当前这个包的结构和配置,即初始化操作。

仍然以 npm init vite 为例,执行命令,可以看到提示:

Need to install the following packages:
  create-vite@3.2.0
Ok to proceed? (y)

它会下载 create-vite 并执行其中的命令,这个命令为我们创建一个 Vite 应用。

类似,可以这样使用 create-react-app:

npm init react-app my-app
# 同 npx create-react-app my-app

init 命令语义更简洁一点,不过也提出了一个限制:这类包名必须以 create- 开头。像 typescript-starter 这种包不得不使用 npx 了。

对命名空间下的包,解析规则稍有不同:

npm init @foo   # npx @foo/create
npm init @foo/bar  # npx @foo/create-bar

此外,yarn init 也支持同样的功能。

并非空目录下才能使用 npm init

最后纠正一个大部分人可能有的误解,npm init 并不是只有在项目初始化时才能使用。即使是在一个已有的包,你也可以使用它。

对于不指定包的 npm init,文档的说明是:

It is strictly additive, so it will keep any fields and values that were already set.(它是添加性操作,所以已有的字段和值都会保留下来)

如果指定了用于初始化的命令,就取决于包的作者了。比如, @eslint/create-config 就是增量式的修改。

利用这点,一些软件工具的作者可以让用户很方便地引入自己的软件。比如,ESLint 的首页就有一个快速开始的命令:

npm init @eslint/config

看到这里,你应该对这个命令很了解了。用户可以使用它快速引入 ESlint,即使这并不是一个新项目。

总结

  • 简单的 npm init 可以用于创建一个 npm 包,它会在当前目录下生成一个 package.json 文件。
  • npm init <initializer> 会执行 create-<initializer> 包中的命令作为初始化操作,可以用于创建具有特定结构的 npm 包。
  • npm init 可以在已有的包中执行,引入增量内容。