深入浅出 package.json,目测大多数人不了解它

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外:目前建有江西|湖南|湖北籍前端群,可加我微信进群。


本文经作者@yuxiaoliang 授权转载
原文链接:https://juejin.cn/post/7099041402771734559


npm是前端开发人员广泛使用的包管理工具,项目中通过package.json来管理项目中所依赖的npm包的配置。package.json就是一个json文件,除了能够描述项目的包依赖外,允许我们使用“语义化版本规则”指明你项目依赖包的版本,让你的构建更好地与其他开发者分享,便于重复使用。
本文主要从最近的实践出发,结合最新的npm和node的版本,介绍一下package.json中一些常见的配置以及如何写一个规范的package.json

  • package.json

  • package.json常用属性

  • package.json环境相关属性

  • package.json依赖相关属性

  • package.json三方属性


1package.json

1. package.json简介

在nodejs项目中,package.json是管理其依赖的配置文件,通常我们在初始化一个nodejs项目的时候会通过:

npm init

然后在你的目录下会生成3个目录/文件, node_modules, package.json和 package.lock.json。其中package.json的内容为:

{"name": "Your project name","version": "1.0.0","description": "Your project description","main": "app.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1",},"author": "Author name","license": "ISC","dependencies": {"dependency1": "^1.4.0","dependency2": "^1.5.2"}
}

上述可以看出,package.json中包含了项目本身的元数据,以及项目的子依赖信息(比如dependicies等)。

2. package-lock.json

我们发现在npm init的时候,不仅生成了package.json文件,还生成了package-lock.json文件。那么为什么存在package.json的清空下,还需要生成package-lock.json文件呢。本质上package-lock.json文件是为了锁版本,在package.json中指定的子npm包比如:react: "^16.0.0",在实际安装中,只要高于react的版本都满足package.json的要求。这样就使得根据同一个package.json文件,两次安装的子依赖版本不能保证一致。
而package-lock文件如下所示,子依赖dependency1就详细的指定了其版本。起到lock版本的作用。

{"name": "Your project name","version": "1.0.0","lockfileVersion": 1,"requires": true,"dependencies": {"dependency1": {"version": "1.4.0","resolved": 
"https://registry.npmjs.org/dependency1/-/dependency1-1.4.0.tgz","integrity": 
"sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="},"dependency2": {"version": "1.5.2","resolved": 
"https://registry.npmjs.org/dependency2/-/dependency2-1.5.2.tgz","integrity": 
"sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ=="}}
}

2package.json常用属性

本章来聊聊package.json中常用的配置属性,形如name,version等属性太过简单,不一一介绍。本章主要介绍一下script、bin和workspaces属性。

2.1 script

在npm中使用script标签来定义脚本,每当制定npm run的时候,就会自动创建一个shell脚本,这里需要注意的是,npm run新建的这个 Shell,会将本地目录的node_modules/.bin子目录加入PATH变量。
这意味着,当前目录的node_modules/.bin子目录里面的所有脚本,都可以直接用脚本名调用,而不必加上路径。比如,当前项目的依赖里面有 esbuild,只要直接写esbuild xxx 就可以了。

{// ..."scripts": {"build": "esbuild index.js",}
}
{// ..."scripts": {"build": "./node_modules/.bin/esbuild index.js" }
}

上面两种写法是等价的。

2.2 bin

bin属性用来将可执行文件加载到全局环境中,指定了bin字段的npm包,一旦在全局安装,就会被加载到全局环境中,可以通过别名来执行该文件。

比如\@bytepack/cli的npm包:
"bin": {"bytepack": "./bin/index.js"},

一旦在全局安装了@bytepack/cli,就可以直接通过bytepack来执行相应的命令,比如

bytepack -v
//显示1.11.0

如果非全局安装,那么会自动连接到项目的node_module/.bin目录中。与前面介绍的script标签中所说的一致,可以直接用别名来使用。

2.3 workspaces

在项目过大的时候,最近越来越流行monorepo。提到monorepo就绕不看workspaces,早期我们会用yarn workspaces,现在npm官方也支持了workspaces.     workspaces解决了本地文件系统中如何在一个顶层root package下管理多个子packages的问题,在workspaces声明目录下的package会软链到最上层root package的node_modules中。
直接以官网的例子来说明:

{"name": "my-project","workspaces": ["packages/a"]
}

在一个npm包名为my-project的npm包中,存在workspaces配置的目录。

.
+-- package.json
+-- index.js
`-- packages+-- a|  `-- package.json

并且该最上层的名为my-project的root包,有packages/a子包。此时,我们如果npm install,那么在root package中node_modules中安装的npm包a,指向的是本地的package/a.

.
+-- node_modules
|  `-- packages/a -> ../packages/a
+-- package-lock.json
+-- package.json
`-- packages+-- a|   `-- package.json

上述的

-- packages/a -> ../packages/a

指的就是从node_modules中a链接到本地npm包的软链

3package.json环境相关属性

常见的环境,基本上分为浏览器browser和node环境两大类,接下来我们来看看package.json中,跟环境相关的配置属性。环境的定义可以简单理解如下:

  • browser环境:比如存在一些只有在浏览器中才会存在的全局变量等,比如window,Document等

  • node环境: npm包的源文件中存在只有在node环境中才会有的一些变量和内置包,内置函数等。

3.1 type

js的模块化规范包含了commonjs、CMD、UMD、AMD和ES module等,最早先在node中支持的仅仅是commonjs字段,但是从node13.2.0开始后,node正式支持了ES module规范,在package.json中可以通过type字段来声明npm包遵循的模块化规范。

//package.json
{name: "some package",type: "module"||"commonjs" 
}

需要注意的是:

  • 不指定type的时候,type的默认值是commonjs,不过建议npm包都指定一下type

  • 当type字段指定值为module则采用ESModule规范

  • 当type字段指定时,目录下的所有.js后缀结尾的文件,都遵循type所指定的模块化规范

  • 除了type可以指定模块化规范外,通过文件的后缀来指定文件所遵循的模块化规范,以.mjs结尾的文件就是使用的ESModule规范,以.cjs结尾的遵循的是commonjs规范

3.2 main & module & browser

除了type外,package.json中还有main,module和browser 3个字段来定义npm包的入口文件。

  • main : 定义了 npm 包的入口文件,browser 环境和 node 环境均可使用

  • module : 定义 npm 包的 ESM 规范的入口文件,browser 环境和 node - 环境均可使用

  • browser : 定义 npm 包在 browser 环境下的入口文件

我们来看一下这3个字段的使用场景,以及同时存在这3个字段时的优先级。我们假设有一个npm包为demo1,

----- dist|-- index.browser.js|-- index.browser.mjs|-- index.js|-- index.mjs

其package.json中同时指定了main,module和browser这3个字段,

"main": "dist/index.js",  // main "module": "dist/index.mjs", // module// browser 可定义成和 main/module 字段一一对应的映射对象,也可以直接定义为字符串"browser": {"./dist/index.js": "./dist/index.browser.js", // browser+cjs"./dist/index.mjs": "./dist/index.browser.mjs"  // browser+mjs},// "browser": "./dist/index.browser.js" // browser

默认构建和使用,比如我们在项目中引用这个npm包:

import demo from 'demo'

通过构建工具构建上述代码后,模块的加载循序为:_browser+mjs > module > browser+cjs > main_这个加载顺序是大部分构建工具默认的加载顺序,比如webapck、esbuild等等。可以通过相应的配置修改这个加载顺序,不过大部分场景,我们还是会遵循默认的加载顺序。

3.3 exports

如果在package.json中定义了exports字段,那么这个字段所定义的内容就是该npm包的真实和全部的导出,优先级会高于main和file等字段。举例来说:

{"name": "pkg","exports": {".": "./main.mjs","./foo": "./foo.js"}
}
import { something } from "pkg"; // from "pkg/main.mjs"
const { something } = require("pkg/foo"); // require("pkg/foo.js")

从上述的例子来看,exports可以定义不同path的导出。如果存在exports后,以前正常生效的file目录到处会失效,比如require('pkg/package.json'),因为在exports中没有指定,就会报错。    exports还有一个最大的特点,就是条件引用,比如我们可以根据不同的引用方式或者模块化类型,来指定npm包引用不同的入口文件。

// package.json
{ "name":"pkg","main": "./main-require.cjs","exports": {"import": "./main-module.js","require": "./main-require.cjs"},"type": "module"
}

上述的例子中,如果我们通过

const p = require('pkg')

引用的就是"./main-require.cjs"。如果通过:

import p from 'pkg'

引用的就是"./main-module.js"最后需要注意的是 :如果存在exports属性,exports属性不仅优先级高于main,同时也高于module和browser字段。

4package.json依赖相关属性

package.json中跟依赖相关的配置属性包含了dependencies、devDependencies、peerDependencies和peerDependenciesMeta等。

dependencies是项目的依赖,而devDependencies是开发所需要的模块,所以我们可以在开发过程中需要的安装上去,来提高我们的开发效率。这里需要注意的时,在自己的项目中尽量的规范使用,形如webpack、babel等是开发依赖,而不是项目本身的依赖,不要放在dependencies中。

dependencies除了dependencies和devDependencies,本文重点介绍的是peerDependencies和peerDependenciesMeta。

3.1 peerDependencies

peerDependencies是package.json中的依赖项,可以解决核心库被下载多次,以及统一核心库版本的问题。

//package/pkg
----- node_modules|-- npm-a -> 依赖了react,react-dom|-- npm-b -> 依赖了react,react-dom|-- index.js

比如上述的例子中如果子npm包a,b都以来了react和react-dom,此时如果我们在子npm包a,b的package.json中声明了PeerDependicies后,相应的依赖就不会重新安装。需要注意的有两点:

  • 对于子npm包a,在npm7中,如果单独安装子npm a,其peerDependicies中的包,会被安装下来。但是npm7之前是不会的。

  • 请规范和详细的指定PeerDependicies的配置,笔者在看到有些react组件库,不在PeerDependicies中指定react和react-dom,或者将react和react-dom放到了dependicies中,这两种不规范的指定都会存在一些问题。

  • 其二,正确的指定PeerDependicies中npm包的版本,react-focus-lock\@2.8.1[1],peerDependicies指定的是:"react": "^16.8.0 || ^17.0.0 || ^18.0.0",但实际上,这个react-focus-lock并不支持18.x的react

3.2 peerDependenciesMeta

看到“Meta”就有元数据的意思,这里的peerDependenciesMeta就是详细修饰了peerDependicies,比如在react-redux这个npm包中的package.json中有这么一段:

"peerDependencies": {"react": "^16.8.3 || ^17 || ^18"},"peerDependenciesMeta": {"react-dom": {"optional": true},"react-native": {"optional": true}}

这里指定了"react-dom","react-native"在peerDependenciesMeta中,且为可选项,因此如果项目中检测没有安装"react-dom"和"react-native"都不会报错。

值得注意的是,通过peerDependenciesMeta我们确实是取消了限制,但是这里经常存在非A即B的场景,比如上述例子中,我们需要的是“react-dom”和"react-native"需要安装一个,但是实际上通过上述的声明,我们实现不了这种提示。

5package.json三方属性

package.json中也存在很多三方属性,比如tsc中使用的types、构建工具中使用的sideEffects,git中使用的husky,eslint使用的eslintIgnore,这些扩展的配置,针对特定的开发工具是有意义的这里不一一举例。

参考资料

[1]

mailto:react-focus-lock@2.8.1: https://link.juejin.cn?target=mailto%3Areact-focus-lock%402.8.1

cee5082d2e0d6735f39eee9f766217b9.gif

················· 若川简介 ·················

你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》20余篇,在知乎、掘金收获超百万阅读。
从2014年起,每年都会写一篇年度总结,已经坚持写了8年,点击查看年度总结。
同时,最近组织了源码共读活动,帮助4000+前端人学会看源码。公众号愿景:帮助5年内前端人走向前列。

24f6d5ff0e2661e9de1f9b1e19f18497.png

扫码加我微信 ruochuan02、拉你进源码共读

今日话题

目前建有江西|湖南|湖北 籍 前端群,想进群的可以加我微信 ruochuan12 进群。分享、收藏、点赞、在看我的文章就是对我最大的支持~

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

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

相关文章

鲸鱼网络连接_登陆鲸鱼:在网络上读书,第1部分

鲸鱼网络连接I don’t know when it was I started using the text of Moby Dick in my workshops and talks. Likely it dates back to some of my earliest explorations of web typography. Since it’s out of copyright, it’s one those texts you can find online in va…

2022年值得使用的 Node.js 框架

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

更改apk安装包对android系统等级要求

此篇文章解决的为问题: █问题1.系统等级与apk等级不匹配. █问题2.更改api等级后的签名问题. 1.工具准备: 解压缩tool.zip文件夹: 2.开始反编译apk安装包 3.切换目录到tool目录下: 4.反编译: apktool.bat d 待编译apk目录名 存放编译后的文件目录 apktool.bat d Onenote_v14.…

推荐一个前端技术选型神器!真好用~

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

静态原型设计 加载中_见解1:原型设计有助于填补静态设计留下的空白。

静态原型设计 加载中In April 2015, I joined the Disney Parks creative team to design mobile experiences for the happiest place on Earth. I learned a lot from a diverse group of humble, creative, and smart people.2015年4月,我加入了迪士尼公园创意团…

最优资产组合步骤_重新设计投资组合网站之前,请按照以下5个步骤进行操作

最优资产组合步骤The portfolio website is one of the most important assets for a designer. Without it, it can be tough to find your next job or client.作品集网站是设计师最重要的资产之一。 没有它,很难找到下一份工作或客户。 The temptation is high …

裁员潮之下,13次面试拿下字节前端岗offer!

|前言很多粉丝私信,这两个月求职没有往年那么好跳,还有不少粉丝已经收到公司的“优化”通知下面分享一位粉丝的最近的面试经历,在疫情裁员潮的环境下,经历了成长、膨胀、闭关打磨等一系列的跌宕起伏,最终拿下字节总包5…

hdu 1754/zstu 3121 I Hate It(线段树)

http://acm.hdu.edu.cn/showproblem.php?pid1754 http://acm.zstu.edu.cn:8080/JudgeOnline/showproblem?problem_id3121 (1)线段树的基本操作:建树,查询,更新。 (2)重新写一遍时,…

sketch放入app组件_使用Sketch App设计CSS网格

sketch放入app组件首先定义您的网格 (Start by defining your grid) Sketch has 2 built-in layout features — Layout and Grid. In most cases, layout is a great way to organize content on a typical website utilizing a 12 column grid. However for this exercise we…

鲜为人知的CSS实用技巧

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

猎鹰spacex_我如何重新创建SpaceX仪表板UI

猎鹰spacexA couple of weeks ago, SpaceX Crew Dragon launched from Kennedy Space Center to transport astronauts Robert L. Behnken and Douglas G. Hurley to the ISS. Lots of things were revolutionary about this launch, but the one that caught my attention was…

Base64 编码原来这么简单

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

spring事物 设计模式_是什么使事物变得美丽,以及如何在设计中使用它

spring事物 设计模式What do you think about the phrase “beautiful design”? You like it, don’t care or does it make you wince?w ^帽子你想想那句“美丽的设计”? 您喜欢它,不在乎还是让自己畏缩了? For many, “beautiful” is …

历时一个月!50+Vue经典面试题详解,值得收藏!

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

页面滚动时触发图片逐帧播放_如何在滚动效果上创建逐帧运动图像

页面滚动时触发图片逐帧播放A step by step guide on how to create that dynamic image background you see everywhere.有关如何创建随处可见的动态图像背景的逐步指南。 内容 (Content) Introduction 介绍 Result demo 结果演示 Prerequisite 先决条件 Step by step guide …

前端监控的搭建步骤,别再一头雾水了!

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

1812:网格_指导设计:网格的历史

1812:网格The grid has long played a central role in the development of art and design due to its organizational nature; acting as a matrix for controlling the placement of elements. In art: Foreground and background. In design: Image and type. And so on.网…

HDU ACM 1728 逃离迷宫 (广搜BFS)

http://acm.hdu.edu.cn/showproblem.php?pid1728 题意:给出一张图,转弯数k,起点(x1,y1),(x2,y2)判断能不能最多只转k个弯时从起点走到终点 输入时注意起点与终点是先y后x的 思路:用point[4][2]表示方向向量,每次遍历遍历一行或者一列,遍历时要注意遇到遍历过的点要跳过去,继续…

Element使用的async-validator表单校验库源码超详细解析

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

从零手写 Vue 之响应式系统

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…