package.json配置详解

news2024/11/16 9:48:42

npm 介绍

npm 是随同 Node.js 一起安装的包管理工具,能解决 Node.js 代码部署上的很多问题,常见的使用场景有以下几种:

  • 允许用户从 NPM 服务器下载别人编写的第三方包到本地使用;
  • 许用户从 NPM 服务器下载并安装别人编写的命令行程序到本地使用;
  • 允许用户将自己编写的包或命令行程序上传到 NPM 服务器供别人使用;

在现在的前端世界里,几乎已经离不开 npm 了,其提供的依赖安装、卸载、升级、发布等一条龙服务,使我们在日常的开发效率提升了不少。

npm 制定了一个包规范,所谓规范就是一些格式和约定,比如作为一个 npm 包中根目录必须包含一个 package.json 文件,并约定从 package.json 文件里读取这个包的所有信息,包括它的名字、版本号、它依赖于哪些别的包等;

并且创建一个 node_modules 目录专门用来存放第三方依赖,Node为此提供的支持是内置的 require()方法默认会到这个目录下去检索模块,而无需手动指定路径。有了这些规范,一个包的开发、依赖安装、发布等都步骤都标准化了,省心省力。

我们接下来就让我们开始学习 npm 之旅吧!!!

packages和modules的区别

一个 packages 是一个文件,在该文件的根目录,必须包含一个 package.json 文件,通过该文件,你可以将包发布到 registry

modulesnode_modules 目录下可以被 require() 函数加载的任何文件和目录,这样的称为模块,一个 packages 也是模块,只不过是由多个模块组成的包。

为了可以通过 require() 函数加载到模块,它必须具有以下特征之一:

  • 文件夹中包含 package.json 文件,并且包含一个 main 字段作为入口文件;
  • 一个 JavaScript 文件;

image_c0ee043d.png

在上面的图中 moment.js 是一个 modules,但不是一个 packages,在外部引入可以使用。

image_6cbf064f.png

在上面的例子中,在 node_modules 目录下手动创建一个名为 moment 的文件,并且添加一个 package.json 的文件,在文件中添加 main 字段,设置 main.js 作为文件的入口。

在这里,调用 const foo = require("moment"); 实际上加载的是 moment 文件夹下的 main.js 文件,所以 foo 函数被正常调用,最终输出 hi

package.json 详解

在前面的内容中我们多次说到 package.json 的文件,那么我们应该怎么创建这个文件呢,npm 给我们提供了一个命令 npm init,在终端输入该命令,会有以下问题并要求你输入回答:

image_ece60352.png

最终会在当前路径生成一个 package.json 文件,文件内容有如下代码所示:

{
  "name": "moment",
  "version": "1.0.0",
  "description": "描述信息",
  "main": "index.js",
  "dependencies": {
    "moment": "^1.0.0",
    "axios": "^1.2.6"
  },
  "devDependencies": {},
  "scripts": {
    "test": "node ./index.js"
  },
  "repository": {
    "type": "git",
    "url": "github地址"
  },
  "keywords": [
    "react",
    "vue"
  ],
  "author": "作者",
  "license": "ISC"
}

通过 npm init -y 会生成一个默认的 package.json 文件。接下来我们对 package.json 文件中部分常见的字段进行详细的讲解。

name

如果你要发布你的包,name 字段是你的 package.json 文件中非常重要的字段,在 npm 官网搜索到的包名就是该字段的值,如果不打算发布你的包,则 name 是可选的,name 的 值遵循以下规则:

  • 必须小于或等于214个字符;
  • 不能以 '.'"_" 、大写字母、中文开头,该字段最终成为 URL、命令行上的参数和文件夹名称的一部分。因此,name 不能包含任何非url安全字符;
  • 不能使用 NOdejs 核心模块相同的名称;
  • 这个名字可能会作为参数传递给 require() 函数,所以它应该很短,但也要合理地描述;
  • 如果你需要发布包,你需要查看 npm 的注册表(registry)是否存在同名包,否则你将无法发布成功,当然你可以通过后期修改;

在实际的开发中,很多项目都不需要发布到 npm 上,所以这个 name 在这里并不是那么重要,不会影响项目正常运作,可以忽略。

version

name 一样,如果要发布你的包,这个字段很重要,如果不需要,这个字段则显得不是那么重要了。

version 必须可以被 node-semver 解析,node-semver 作为依赖项与 npm 捆绑在一起。

semver 的版本规范是 X.Y.Z:

  • X 为主版本号(major): 通常在涉及重大功能更新,产生了破坏性变更时会更新此版本号;
  • Y 为次版本号(Minor): 在引入了新功能,但并未产生破坏性变更,依然向下兼容时更新此版本号;
  • Z 为修订号(Patch): 在修复了一些问题,但未产生破坏性变更时会更新此版本号;

除了 X.Y.Z 这样的版本号,还有 premajor | preminor | prepatch | prerelease 这样的版本号,这些属于测试版本,很多时候一些新改动,并不能直接发布到稳定版本上,这是可以发布一个预发布版本,不会影响到稳定版本。

可以通过以下命令来查看 npm 包的版本信息,如想要查看的react的:

  • 查看最新版本
npm view react version
  • 查看所有版本
npm view react versions

我们可以通过 child_process 执行该命令以获取某的包的版本,这个方法将在后面的脚手架中用到,具体操作请看以下代码:

const cp = require("child_process");

cp.exec("npm view react version", (err, stdout, stderr) => {
  console.log(stdout); // 18.2.0
});

description

description 字段用来描述这个包,它可以是一个字符串,也可以是中文,在搜索的时候可以看到该包的描述,并且该描述也可以作为搜索的关键词。

例如 react 中的 description 字段的值为 React is a JavaScript library for building user interfaces.,通过搜索 "React is" 能显示会有以下结果:

image_4deb4f40.png

keywords

keywords 字段在里面放关键字,好的关键词可以帮助开发者在 npm 官网上更好的搜索到此项目,增加曝光率。例如 axioskeywords 如下:

"keywords": [
  "xhr",
  "http",
  "ajax",
  "promise",
  "node"
],

homepage

项目主页的链接,通常是项目 github 链接,项目官网或者文档首页,如果是 npm 包,会在这里显示:

image_d1cd442b.png

bugs

bugs 字段表示项目提交问题的地址,该字段是一个字符串也可以是一个对象,最常见的 bugsgithub 的issue,例如 react 中的 bugs 是这样的:

"bugs": "https://github.com/facebook/react/issues"

license

license 字段表示项目的开源许可证,你应该为你的包指定一个许可证,方便其他开发者知道如何允许他们使用它,以及你对他施加的任何限制,例如:

"license": "ISC"

repository

repository 字段用于指定代码所在的位置,通常是 github,如果是 npm 包,则会在包的首页中显示:

image_0d3235ce.png

files

files 字段是一个数组,当需要项目进行 npm 发布时,可以通过 files 字段指定哪些文件需要发布到 registry 来控制 npm 包大小,如果指定的是文件夹,那么该文件夹下面的所有文件都会被提交,例如 react 的配置是这样的,如下代码所示:

"files": [
  "LICENSE",
  "README.md",
  "index.js",
  "cjs/",
  "umd/",
  "jsx-runtime.js",
  "jsx-dev-runtime.js",
  "react.shared-subset.js"
]

main和browser

main 字段用来指定包的入口入口文件,在上面的内容就忽略不讲了,如果不设置,则默认使用包的根目录中的 index.js 文件作为入口。

main 字段可以在 browser 环境和 Nodejs 环境都可以使用,如果 使用 browser 字段,则表明只能在浏览器环境下使用,不能用于服务端。

type

type 字段表示在 Node 环境中可以使用的模块化方式,默认是 CommonJs,另外还可以选择 EsModule

bin

一些包的作者希望包可以作为命令行工具使用,配置好 bin 字段之后,通过 npm install package_name -g 命令可以将脚本添加到执行路径中,之后可以在命令行中直接执行。

bin 字段的主要作用可以看 在终端里输入 npm start 后都发生了啥😮😮😮 这篇文章。

exports

exports 字段可以配置不同环境对应的模块入口文件,并且当他存在时,它的优先级最高,当 package.json 文件中存在 exports 字段,设置的 main 字段会失效,在 react 中的 package.json 文件中的 exports 字段有如下配置:

"exports": {
  ".": {
    "react-server": "./react.shared-subset.js",
    "default": "./index.js"
  },
  "./package.json": "./package.json",
  "./jsx-runtime": "./jsx-runtime.js",
  "./jsx-dev-runtime": "./jsx-dev-runtime.js",
  "./src/*": "./src/*"
},

这个配置相当于 weboack 中的 resolve.alies 配置路径别名,请看下面的例子,在 node_modules 文件夹下创建一个 moment 文件,并且添加 package.json 文件让其作为一个 npm 模块,通过 require('moment') 会查找到当前文件夹,并通过 main 字段或者 exports 字段查找当前字段的入口,请看如下代码所示:

"exports": {
".":{
  "require":"./test.js"
}

在上面的代码中,使用 require('moment') 则表示会自动导入 moment 包中的 test.js 文件,所以在自己的项目中导入会有以下输出:

// moment包中的 test.js 
function foo() {
    return 'test'
}

module.exports=foo

const foo = require("moment");

console.log(foo()); // test

再在 package.json 中的 exports 字段中添加这行代码:

"./src": {
  "require": "./src/moment.js"
}

当在自己的项目中使用 require('moment/src') 进行导入时,实际上导入的是 moment/src 目录下的 moment.js 文件,默认情况下会 require('moment/src') 会加载 index.js,因为按照 require 规则会先查找 index.js,具体示例如下代码所示:

// moment/src/moment.js

function bar(params) {
  return "moment.js";
}

module.exports = bar;

// moment/src/index.js

function bar(params) {
  return "index.js";
}

module.exports = bar;


const bar = require("moment/src");

console.log(bar()); // moment.js

在自己的项目中使用 require('moment/src') 最终会输出 moment.js,如果将 exports 字段删除会输出 index.js,更多 require 细节可以参考 深入浅出CommonJs 这篇文章。

config

config 字段用于设置 script 字段里的脚本运行时的参数,例如设置 prot 为3000:

"config": {
  "port": "8080"
}

并且在 script 字段下添加 dev属性,值设置为 nodemon index.js,终端运行 npm run dev

"scripts": {
  "dev": "nodemon index.js"
},

在执行脚本的时候,我们可以通过 process.env.npm_package_config_port 这个变量访问到 3000

console.log(process.env.npm_package_config_port); // 3000

dependencies

dependencies 字段表示运行依赖,也就是项目中生产环境下需要用到的依赖,例如 reactvueaxiosnpm 包,使用 npn install <packagename> 或者 npm install <packagename> --save 时,会被自动插入到该字段中:

"dependencies": {
    "axios": "^1.2.6",
    "react": "^18.2.0",
    "shelljs": "^0.8.5"
  },

devDependencies

devDependencies 字段表示开发阶段时需要的依赖包,例如 webpackeslintsass,该依赖用于提升开发速度,和 dependencies 不同的是,该字段只需要在开发阶段中使用,不需要在生产环境中使用,要使依赖安装到 devDependencies 字段上,可以使用 npm install <packagename> --save-dev 或者 npm install <packagename> -D

dependencies扩展

在依赖包中后面的参数就是版本,这些版本信息有以下规则:

  • version: 表示确定的版本号;
  • >version: 大于当前版本;
  • ~version: 表示主版本 X 和次版本 Y 保持不变,修订号 Z 永远安装最新的版本;
  • ^version: 表示主版本 X 保持不变,次版本 Y 和修订号 Z 永远安装最新的版本;
  • 1.2.x: 表示该版本中的 x 可以是任何符合规范的值;
  • *"": 表示匹配任何版本;
  • version1 - version2: 表示 version<= x >= version;
  • version1 || version2: 表示只要其中一个符合即可;
  • latest: 代表最新版本;
  • path/path/path: 提供到包含包的本地目录的路径,本地路径可以使用 npm install 保存,该文件会被保存在 node_modules 目录下,例如,在根目录创建一个 bar 的文件并且在 package.json 中添加以下字段:
"dependencies": {
  "bar": "file:./bar"
},

bar 的文件中创建 index.js 文件,并编写以下代码:

function foo() {
  return "hi";
}

module.exports = foo;

通过执行 npm install 会把该文件链接到 node_modules 目录文件下,在根目录中编写以下代码:

const bar = require("bar");

console.log(bar());

执行命令 node .\index.js,你会发现 hi 会被正常输出了。

private

private 字段可以防止我们意外地将私有库发布到 registry,只需将 private 字段设置为 true 即可:

"private": true

@ 作用域

已知所有的 npm 包都有一个名字,但是随着用户量的增大,npm 包的包名就出现了被占用的问题,占用后其他人就不能使用了,当然 npm 也官方不是闲着,他们提供了一个作用域的概念,该作用域遵循包名的通常规则,即 url 安全字符,在包名使用时,在作用域前面添加一个 @ 符号,表示这个是一个作用域,在后面加一个斜杠,例如:

@somescope/somepackagename

每个 npm 用户或者组织都有自己的作用域,它可以是你的用户名、自己创建的组织名,只有你可以在你的作用域中添加包,这就意味着你不必担心别人会抢在你前面取你的包名,类似于你的 github,你可以取任何的仓库名称,只需名称合法且在你自己的仓库中不存在同名仓库。

作用域包通过在 npm install 中引用它的名称(前面加@符号)来安装:

npm install @myorg/mypackage

package.json 中有以下的形式:

"dependencies": { "@myorg/mypackage": "^1.3.0" }

因为作用域包安装在作用域文件夹中,所以在代码中需要它们时,必须包含作用域的名称:

require('@myorg/mypackage')

script

script 字段支持许多内置脚本和它们的预设生命周期事件以及任意脚本,这些你都可以使用 npm run <stage> 来执行,例如当你要执行 npm run dev 命令,具有匹配名称的 PrePost 命令也就作为这些命令一起执行,执行顺序为 predev - dev - postdev,例如在 package.json 文件中有如下定义:

"scripts": {
  "dev": "node index.js",
  "predev": "node pre.js",
  "postdev": "node post.js"
},

当执行 npm run dev,会首先执行 pre.js 文件,然后执行 index.js 文件,再最后执行 post.js 文件。

更多关于 scirpt 字段的细节将会在另一篇文章中讲解,敬请期待。

参考文章

  • 书籍: 深入浅出Nodejs;
  • npm官网
  • 字节跳动技术团队

结尾

整个系列会比较长,如果想阅读后续的推文,可以点赞+关注😁😁😁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/195874.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【云原生 | Docker 高级篇】11、Docker 私有镜像仓库 Harbor 安装及使用教程

目录 一、Harbor 介绍 二、Harbor 的优势 三、Harbor 部署安装 3.1 部署环境 3.2 为 Harbor 自签发证书 3.3 安装 Harbor 3.4 设置开机自启 四、Harbor 图像化界面使用说明 4.1 修改本地 hosts 文件 4.2 访问 harbor 4.3 创建项目 五、测试使用 harbor 私有镜像仓库…

form 表单只有一个input 时,回车自动提交表单造成页面刷新效果

现象&#xff1a;el-form 中仅有一个input&#xff0c;input上设置了回车响应事件&#xff0c;首次按回车键后&#xff0c;页面刷新&#xff0c;再次按回车才执行了响应事件 <el-form ref"form" submit.native.prevent><el-form-item><el-input keyu…

C#学习记录——【实例】C#实现OPC Client

最近学习测试用C#开发OPC客户端连接OPC服务器&#xff0c;防止遗忘&#xff0c;记录学习测试结果。 1、OPC基础知识 1.1、OPC概述 OPC是Object Linking and Embedding&#xff08;OLE&#xff09;for Process Control 的缩写&#xff0c;它是微软公司的对象链接和嵌入技术在…

【JavaEE】认识HTTP协议

✨哈喽&#xff0c;进来的小伙伴们&#xff0c;你们好耶&#xff01;✨ &#x1f6f0;️&#x1f6f0;️系列专栏:【JavaEE】 ✈️✈️本篇内容:认识HTTP协议、请求。 &#x1f680;&#x1f680;代码存放仓库github&#xff1a;JavaEE仓库&#xff01; ⛵⛵作者简介&#xff1…

Golang 提取视频中音频,存为MP3格式 | Golang工具

目录 前言 环境依赖 代码 总结 前言 本文提供将视频中音频提取出来存为mp3格式&#xff0c;一如既往的实用主义。 主要也是学习一下golang使用ffmpeg工具的方式。 环境依赖 ffmpeg环境安装&#xff0c;可以参考我的另一篇文章&#xff1a;windows ffmpeg安装部署_阿良的博…

Delphi复制HID、ID门禁卡源码

T5557卡是美国Atmel公司生产的多功能非接触式射频芯片卡&#xff0c;属于125KHz的低频卡&#xff0c;在国内有广大的应用市场&#xff0c;如很多酒店的门禁卡都是使用T5557卡。该芯片共有330bit(比特)的EPROM(分布为10个区块, 每个区块33bit)。0页的块0是被保留用于设置T5557操…

模电学习3. MCU接三极管开关电路简单分析

模电学习3. MCU接三极管开关电路简单分析一、说明二、使用NPN型三极管工作状态分析1. 饱和状态基本要求2. 计算限流电阻R23. IbI_bIb​4. 计算 RbR_bRb​5. 下拉电阻三、使用PNP型三极管工作状态分析1. 示例原理图2. IO输出低电平3. IO输出高电平一、说明 本文演示了一个使用M…

adb调试工具-笔记

adb调试工具adb工具可以在电脑通过终端命令操作安卓手机/模拟器命令&#xff1a;adb shell dumpsys window windows | findstr mFocusedApp该命令是查找程序的包名和界面名让我们打开夜神模拟器&#xff0c;并打开设置界面然后在电脑打开命令行&#xff0c;输入上述查询命令传送…

小红书数据分析网站:2023年如何产出爆文(纯干货分享)

导语&#xff1a; 不懂小红书最近火热的赛道、总是错过爆款打造的节奏……2023年了&#xff0c;相信不少人会发现关于小红书营销种草投放&#xff0c;入门容易&#xff0c;做好难。本文将借助第三方工具为品牌锚定赛道&#xff0c;寻找新风向。 1、行业流量大盘 —— 实时掌握…

Android 进程保活(一)

最近公司项目需求&#xff0c;需要给应用加入进程保活。 这里简述一下需求&#xff0c;由于App应用对接了蓝牙接收实时数据&#xff0c;并且数据量很大&#xff1b; 用户在操作App获取实时数据的时候&#xff0c;不可能一直看着手机屏幕&#xff0c; 这时候手机一般会有黑屏或者…

freertos学习之路1-裸机和rtos的区别

写在最前 由于工作需要&#xff0c;需要开始学习freertos的相关知识&#xff0c;本专题主要记录freertos的相关内容 参考&#xff1a; https://www.bilibili.com/video/BV19g411p7UT 正点原子视频 1. 裸机和rtos的多任务处理 试想一种场景&#xff0c;我们正在打游戏&#xff0…

java基础巩固-宇宙第一AiYWM:为了维持生计,大数据之ElasticSearch【ElasticSearch的概念、关于文档、索引的命令】~整起

ElasticSearch一、ElasticSearch基本概念1.ElasticSearch是什么&#xff1f;从哪来、来干啥&#xff1f;2.ElasticSearch与Solr的对比与选型&#xff1a;3.ES核心概念及相关操作4.ELK&#xff1a;拆箱即用的技术&#xff0c;解压完成就能用5.IK分词器6.ElasticSearch与SpringBo…

字节跳动青训营--前端day6

文章目录前言一、React的历史和应用二、React的设计思路1. ui编程痛点 & 对React的期望2. 组件化3.状态归属问题4. 生命周期三、React&#xff08;hooks&#xff09;1.Virtual DOM(虚拟 DOM)&#xff1a;2. diff算法四、React状态管理库五、应用级框架科普前言 仅以此文章…

spark 内存管理机制与相关参数调优

spark 内存管理 文章目录spark 内存管理spark 1.6 内存管理机制spark 2.0 内存管理机制spark 3.3.1 官方文档spark 内存相关参数调优spark 1.6 内存管理机制 https://0x0fff.com/spark-memory-management 统一内存管理 Spark 1.6 之后引入的统一内存管理机制&#xff0c;与静…

SpringbootAdmin:轻量级的Springboot监控组件,用过的都说好

简介 Springboot Admin是一个管理和监控Springboot项目的组件&#xff0c;分为服务端和客户端&#xff0c;两端通过http进行通信。由于其轻量级的特性&#xff0c;所以特别适合中小项目使用。 其效果图如下&#xff1a; 服务端配置 1&#xff0c;引入Springboot admin和Spri…

3.5 异常

1.概述 异常是一些用来封装错误信息的对象 它由异常的类型、提示信息、报错的行号提示三部分组成 2.异常的继承结构 3.异常的处理方式 当程序中遇到了异常,通常有两种处理方式:捕获或者向上抛出 当一个方法抛出异常,调用位置可以不做处理继续向上抛出,也可以捕获处理异常 大…

简单使用OpenGauss数据库

1 参考网站 # OpenGauss官网 https://opengauss.org/zh/2 Docker安装OpenGauss 下载OpenGauss docker pull enmotech/opengauss:3.0.0安装OpenGauss 容器参数说明&#xff1a; GS_PASSWORD&#xff1a;必须设置该参数&#xff0c;该参数设置了openGauss数据库的超级用户omm…

LeetCode 刷题系列 -- 1110. 删点成林

给出二叉树的根节点 root&#xff0c;树上每个节点都有一个不同的值。如果节点值在 to_delete 中出现&#xff0c;我们就把该节点从树上删去&#xff0c;最后得到一个森林&#xff08;一些不相交的树构成的集合&#xff09;。返回森林中的每棵树。你可以按任意顺序组织答案。示…

多域(跨域)计算「起势」,智能汽车赛道迎来新拐点

多域&#xff08;跨域&#xff09;计算平台正在成为新一轮市场争夺战的焦点。 就在今年CES展上&#xff0c;采埃孚推出多域功能版本的ProAI高性能计算平台&#xff0c;可以在不同的单板上支持基于域的ADAS、信息娱乐以及车身控制功能&#xff0c;并适配不同供应商的系统芯片以及…

前后端分离的陷阱

不管你设计的系统架构是怎么样&#xff0c;最后都是你的组织内的沟通结构胜出。这个观点一直在组织内不断地被证明&#xff0c;但也不断地被忽略。 前后端分离的利与弊 近几年&#xff0c;随着微服务架构风格的引入、前后端生态的快速发展、多端产品化的出现&#xff0c;前后…