Home > Article > Web Front-end > A brief analysis of common attributes of package.json in nodejs projects
This article will take you through the package.json configuration file in the node project, and talk about some common configuration properties, environment-related properties, dependency-related properties and third-party properties in package.json. I hope it will help Everyone helps!
npm is a package management tool widely used by front-end developers. In the project, package.json is used to manage the configuration of the npm packages that the project depends on. package.json is a json file. In addition to describing the project's package dependencies, it also allows us to use "semantic versioning rules" to indicate the versions of your project's dependent packages, allowing your builds to be better shared with other developers for easy reuse. . This article mainly starts from recent practice, combined with the latest npm and node versions, to introduce some common configurations in package.json and how to write a standardized package.json
1. Introduction to package.json
In the nodejs project, package.json is the configuration that manages its dependencies File, usually when we initialize a nodejs project, we will pass:
npm init
Then 3 directories/files will be generated in your directory, node_modules, package.json and package.lock.json. The content of package.json is:
{ "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" } }
As can be seen from the above, package.json contains the metadata of the project itself, as well as the sub-dependency information of the project (such as dependicies, etc.).
2. package-lock.json
We found that during npm init, not only the package.json file was generated, but also package-lock.json file. So why do we still need to generate the package-lock.json file when clearing package.json? Essentially, the package-lock.json file is for locking the version. The sub-npm package specified in package.json is such as: react: "^16.0.0". In actual installation, as long as the version is higher than react, package.json is satisfied. requirements. This means that according to the same package.json file, the sub-dependency versions installed twice cannot be guaranteed to be consistent.
The package-lock file is as shown below, and the sub-dependency dependency1 specifies its version in detail. Plays the role of lock version.
{ "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==" } } }
This chapter will talk about the commonly used configuration attributes in package.json. Attributes such as name and version are too simple. Not introduced one by one. This chapter mainly introduces the script, bin and workspaces properties.
2.1 script
Use the script tag in npm to define the script. Whenever npm run is specified, a shell will be automatically created. Script, what needs to be noted here is that the new Shell created by npm run will add the node_modules/.bin subdirectory of the local directory to the PATH variable.
This means that all scripts in the node_modules/.bin subdirectory of the current directory can be called directly with the script name without adding a path. For example, if the current project's dependencies include esbuild, just write esbuild xxx directly.
{ // ... "scripts": { "build": "esbuild index.js", } }
{ // ... "scripts": { "build": "./node_modules/.bin/esbuild index.js" } }
The above two ways of writing are equivalent.
2.2 bin
The bin attribute is used to load the executable file into the global environment. The npm package with the bin field is specified. Once it is If installed globally, it will be loaded into the global environment and the file can be executed through an alias.
For example, the npm package of @bytepack/cli:
"bin": { "bytepack": "./bin/index.js" },
Once @bytepack/cli is installed globally, you can directly execute the corresponding command through bytepack, such as
bytepack -v //显示1.11.0
If it is not installed globally, it will be automatically connected to the node_module/.bin directory of the project. Consistent with what was said in the script tag introduced earlier, it can be used directly with aliases.
2.3 workspaces
When the project is too large, monorepo has become more and more popular recently. When it comes to monorepo, don’t look at workspaces. In the early days, we would use yarn workspaces. Now npm officially supports workspaces. Workspaces solves the problem of how to manage multiple sub-packages under a top-level root package in the local file system. The packages in the workspaces declaration directory will be soft-linked to the node_modules of the top-level root package.
Let’s take an example from the official website to illustrate:
{ "name": "my-project", "workspaces": [ "packages/a" ] }
In an npm package named my-project, there is a directory configured by workspaces.
. +-- package.json +-- index.js `-- packages +-- a | `-- package.json
And the top-level root package named my-project has a packages/a sub-package. At this time, if we npm install, then the npm package a installed in node_modules in the root package points to the local package/a.
. +-- node_modules | `-- packages/a -> ../packages/a +-- package-lock.json +-- package.json `-- packages +-- a | `-- package.json
The above
-- packages/a -> ../packages/a
refers to the package from A soft link in node_modules that links to the local npm package
常见的环境,基本上分为浏览器browser和node环境两大类,接下来我们来看看package.json中,跟环境相关的配置属性。环境的定义可以简单理解如下:
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包的入口文件。
我们来看一下这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字段。
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后,相应的依赖就不会重新安装。
需要注意的有两点:
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"需要安装一个,但是实际上通过上述的声明,我们实现不了这种提示。
package.json中也存在很多三方属性,比如tsc中使用的types、构建工具中使用的sideEffects,git中使用的husky,eslint使用的eslintIgnore,这些扩展的配置,针对特定的开发工具是有意义的这里不一一举例。
更多node相关知识,请访问:nodejs 教程!
The above is the detailed content of A brief analysis of common attributes of package.json in nodejs projects. For more information, please follow other related articles on the PHP Chinese website!