跳到主要内容

Node.js 项目结构

- · -

所有的 Node.js 生成的项目都会有一个 package.json 文件,这个文件中包含了项目的基本信息,例如项目名称、版本、作者、依赖包等。

常见的 package.json 字段如下:

1. name

项目名称,如果你项目是需要发布到 npm 上的,该字段为必填字段,且必须是唯一的,不能和 npm 中其他已名名称重复。

规则

  1. 长度必须小于等于 214 个字符
  2. 如果名称以组织名,用户名或其他作用域名称开头,可以以点或下划线开头。如果不是,不能以点或下划线开头
  3. 名称中的字母必须不能包含大写字母
  4. 名称最终会在 url、目录、命令行参数中使用,所有不能包含任何非 URL 安全的字符

一些建议

  1. 不要使用和 node 内置模块相同的名称
  2. 不在要名称中包含 nodejs 字符,因为 nodejs 包一定是用于 node 或 js 的
  3. 名称需要在 require 或 import 中使用,一般不要太长,且要有意义
  4. 在你想要封装一个包的时候,可以先在 npm 上搜索一下,看看是否已经有人封装了,如果有,可以直接使用,如果没有,可以考虑自己封装一个

2. version

项目版本号,和项目名称一样。如果你项目是需要发布到 npm 上的,该字段为必填字段。命名规则采用语义化版本控制规范(SemVer)

版本号大致规则为:

  1. 格式为:主版本号.次版本号.修订号-先行版本号+版本编译信息
  2. 软件发布后,不允许修改已发布的软件内容,任何修改都必须以新版本号发布
  3. 版本为 0.x.x 的软件处于开发阶段,不稳定,可能会有大量修改,不应该把以 0 为主版本号的软件标记为稳定版
  4. 修订号必须是在没有任何功能性更改的情况下修改问题时递增
  5. 次版本号必须是在有新功能添加,但是不破坏现有功能的情况下递增,在任何公式 API 被标记为已弃用时,也必须递增,也可以在软件内容有大量改进时(只改进实现,不变更功能)递增,在次版本号递增时,修订号必须归零
  6. 主版本号在有任何不兼容的修改时递增,主版本号递增时,次版本号和修订号必须归零

下面是一些合法的版本号示例:

# 主版本号.次版本号.修订号-先行版本号+版本编译信息
0.0.1

# 主版本号.次版本号.修订号-先行版本号
0.0.1-dev

# 主版本号.次版本号.修订号+版本编译信息
0.0.1+build.1

# 主版本号.次版本号.修订号-先行版本号+版本编译信息
0.0.1-dev+build.1

3. description

项目描述信息,一般说明软件的功能或库的用法,可以为空。

4. main

库入口文件,在其他项目引用自己的库时直接通过 import xxx from "库名称"const xxx = require("库名称") 会自动导入该文件,一般是一个 js 文件,如果没有指定,默认为 index.js。

比如库 useful-storage 的 package.json 文件内容如下:

{
"name": "useful-storage",
"description": "更好用的Storage",
"version": "1.0.1",
"main": "index.js",
"repository": "https://github.com/iamhefang/useful-storage.git",
"author": "hefang <he@hefang.link>",
"license": "MIT",
"scripts": {
"prepublishOnly": "tsc"
},
"devDependencies": {
"typescript": "^3.8.3"
}
}

导入时直接使用库名称 useful-storage,会自动导入 index.js 文件

import { setLocalStorage } from "useful-storage";

5. bin

项目提供的命令行,可以为字符串或 json 对象。为字符串是命令名称为项目名称,值为执行时调用的文件路径,为对象时键为命令名称,值为执行时调用的文件路径。如果为对象,可以定义多个命令。

比如 vue-cli 的 package.json 文件部分内容如下:

{
"name": "@vue/cli",
"version": "5.0.8",
"description": "Command line interface for rapid Vue.js development",
"bin": {
"vue": "bin/vue.js"
}
}

package.json 里面定义了一个名为 vue 的命令,执行时会自动调用 bin/vue.js 文件

6. scripts

脚本命令,可以使用 npm run <命令名称> 执行。

何方的个人小站的项目 scripts 如下

{
"scripts": {
"start": "docusaurus start --host=0.0.0.0",
"build": "docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "scripts/deploys/build.sh",
"clear": "docusaurus clear",
"serve": "docusaurus serve",
"typecheck": "tsc",
"commit": "bash scripts/deploys/auto-commit.sh",
"commit-deploy": "yarn run commit && yarn run deploy",
"merge": "bash scripts/deploys/merge2master.sh",
"merge-deploy": "yarn run merge && yarn run deploy"
}
}

如果我的网站内容更新需要部署,只需要执行 yarn run merge-deploy 命令即可,该命令会自动提交代码,合并到 master 分支并自动部署到服务器。

7. author

项目作者,可以为下面两种格式:

1. 字符串

author 为字符串时格式一般如下,其中邮箱和网站为可选字段

名称 <邮箱> (网站)

2. json 对象

{
"name": "名称, 必填",
"email": "邮箱, 可选",
"url": "网站, 可选"
}

8. license

软件或库的许可证,该值是一个字符串。可以直接指定单个许可证名称。

{
"license": "BSD-3-Clause"
}

或指定多个许可证名称。

{
"license": "(ISC OR GPL-3.0)"
}

还可以指定许可证所在的文件路径

{
"license": "SEE LICENSE IN <文件路径>"
}

一些老的包中可能会有下面的用法

// 现在不要这样用了,替换成"ISC"
{
"license" : {
"type" : "ISC",
"url" : "https://opensource.org/licenses/ISC"
}
}

// 现在不要这样用了,替换成"(ISC OR GPL-3.0)"
{
"licenses" : [
{
"type": "MIT",
"url": "https://www.opensource.org/licenses/mit-license.php"
},
{
"type": "Apache-2.0",
"url": "https://opensource.org/licenses/apache2.0.php"
}
]
}

8.1 如何选择许可证

对于商业软件来说,在使用库时,一定要注意库使用的许可证,如果使用的许可证不允许闭源,那么你的软件也必须是开源的,否则会有法律风险。下面是一些常见的许可证,可以根据自己的需求选择。

上图来自 https://www.ruanyifeng.com/blog/2011/05/how_to_choose_free_software_licenses.html

9. dependencies

项目在运行时依赖的包,该字段为一个 json 对象,键为依赖的包名称,值为依赖的版本号。

{
"dependencies": {
"vue": "^2.6.11",
"vue-router": "^3.1.6"
}
}

版本号可以是下面几种形式:

  • version 写死主版本号、次版本号和修订号
  • >version 必须大于指定的版本号
  • >=version 必须大于或等于指定的版本号
  • <version 必须小于指定的版本号
  • <=version 必须小于或等于指定的版本号
  • ~version 比如 ~1.2.3,必须大于等于 1.2.3 且小于 1.3.0
  • ^version 比如 ^1.2.3,必须大于等于 1.2.3 且小于 2.0.0
  • 1.2.x 必须大于等于 1.2.0 且小于 1.3.0
  • http://... See 'URLs as Dependencies' below
  • * 匹配所有版本
  • "" (空字符串)和 * 效果一样
  • version1 - version2 必须大于等于 version1 且小于等于 version2
  • range1 || range2 对多个版本范围取或
  • git... 使用 git 地址,下面是一些合法的 git 地址
  • user/repo 使用 Github 上的包,比如iamhefang/useful-storage,会自动从 https://github.com/iamhefang/useful-storage 下载包
  • tag 包的标签名称,比如 npm i useful-storage@latest,latest 就是一个标签
  • path/path/path 使用本地路径

9.1 devDependencies

该字段的格式和 dependencies 一样。

项目开发时依赖的包,比如你在开发时使用了 webpack 来打包代码,但是项目运行时并不需要 webpack,那么就可以把 webpack 放到 devDependencies 中。这样别人安装你的包时就不会把 webpack 安装进去了。

9.2 optionalDependencies

该字段的格式和 dependencies 一样。

可选的依赖包,在别人依赖你的项目时,这些包可以安装也可以不安装,可以做为插件或特性使用。

9.3 peerDependencies

该字段的格式和 dependencies 一样。

扁平化依赖包,多用于插件开发。比如你有一个 react hooks 的库。你的库依赖了 react,但是你不想把 react 打包进你的库,而是让使用你的库的人自己安装 react,这时你就可以把 react 放到 peerDependencies 中。

9.4. bundledDependencies

项目在使用 npm pack 打包时依赖的包

该字段可以为一个数组,数组中的每一项为依赖的包名称。

{
// 把 vue 和 vue-router 打包进去
"bundledDependencies": ["vue", "vue-router"]
}

也可以为一个 bool 值,为 true 时把 dependencies 中所有包打包进去,为 false 时不打包任何包,默认为 false

10. engines

该字段是一个 json 对象,可以指定项目运行所需的 node 版本和 npm 版本。

{
"engines": {
"node": ">=10.0.0",
"npm": ">=6.0.0"
}
}

11. os

该字段是一个字符串数组,表示项目支持的操作系统。值为支持的操作系统,比如 darwinlinuxwin32 等。

可选值为 process.platform 的值,常见的值有:'aix'、'android'、'darwin'、'freebsd'、'haiku'、'linux'、'openbsd'、'sunos'、'win32'、'cygwin'、'netbsd'。

{
// 只支持 mac 和 windows
"os": ["darwin", "win32"]
}

也可以使用 ! 表示不支持的操作系统。

{
// 不支持 linux
"os": ["!linux"]
}

12. cpu

该字段类型和用法和 os 一样,表示支持的 CPU 架构。可选值为 process.arch 的值,常见的值有:'arm'、'arm64'、'ia32'、'mips'、'mipsel'、'ppc'、'ppc64'、's390'、's390x'、'x64'。

{
// 只支持 x64 和 arm64
"cpu": ["x64", "arm64"]
}

同样可以使用 ! 表示不支持的 CPU 架构。

{
// 不支持 ia32
"cpu": ["!ia32"]
}

13. publish

nfig: 发布配置

14. private

bool 类型,表示项目是否私有。如果你的项目是一个公开的库,那么该字段必须为 false 或者不填,如果你的项目是一个私有项目,那么该字段为 true

15. workspaces

字符串数组,所示项目中的工作区。在使用 node 开发包含前端、后端、手机端等各个端的完整项目时,可以使用该字段来管理各个端的项目。

比如你有一个完整的项目,包含前端、后端、手机端,你可以把这三个项目放到一个目录下,然后在根目录下创建一个 package.json 文件,内容如下:

{
"name": "my-project",
"workspaces": ["packages/frontend", "packages/backend", "packages/mobile"]
}

可以直接指定各个目录,也可以使用通配符。

{
"name": "my-project",
// 匹配 packages 目录下的所有目录
"workspaces": ["packages/*"]
}

16. repository

仓库地址可以是字符串或 json 对象,表示本项目的代码仓库地址。

{
"repository": {
"type": "git",
"url": "https://github.com/iamhefang/useful-storage"
}
}

如果 git 仓库是一个多工作区项目,还可以指定目录

{
"repository": {
"type": "git",
"url": "https://github.com/facebook/react.git",
"directory": "packages/react-dom"
}
}

如果你的项目代码是在 GitHub, GitHub gist, Bitbucket, 或 GitLab,还可以使用下面的简写方式

{
"repository": "npm/npm",
"repository": "github:user/repo",
"repository": "gist:11081aaa281",
"repository": "bitbucket:user/repo",
"repository": "gitlab:user/repo"
}

17. bugs

项目的缺陷地址,可以是字符串或 json 对象,表示项目的缺陷地址。

{
"bugs": {
"url": "https://github.com/owner/project/issues",
"email": "project@hostname.com"
}
}

如果指定了 url,执行 npm bugs 命令时会自动打开该地址。

18. homepage

项目的主页,是一个字符串 url,如果你的项目有自己的官网,直接把官网地址放到这里即可,如果没有官网,一般放项目仓库地址的 readme 链接。

{
"name": "hefang-note",
"homepage": "https://note.hefang.app"
}

参考文档

  1. package.json | npm Docs
  2. 语义化版本 2.0.0
该内容为何方原创,转载请注明本页地址
https://iamhefang.cn/tutorials/nodejs/project-structure