逃脱长篇大论,7张脑图解读package.json配置信息!
1 基本配置
1.1 描述信息
-
npm官网上的js-md5包详细信息页:包含Name包名称、version版本、license许可证、Homepage项目主页、Repository代码地址。
-
npm官网上的js-md5搜索条主页:包含Name包名称、keysword关键字、description描述信息。
-
package.json配置:
{ "name": "vue-project-name", "version": "0.1.0", "author":"author", "description":"项目描述", "keywords":["xxx","xxx"], "contributors":[{"name":"","email":""}], "bugs":{ "url": "https://github.com/vuejs/vue/issues" }, "homepage":"XXX.com", "repository":{ "type":"git", "url":"git+https://..." }, }
1.2 文件&目录
-
package.json配置:
{ "main":"dist/index.js",// 默认项目根目录下的index.js "browser":"./browser/index.js",// 只想在web使用,不允许在server端使用,可以通过browser字段 "module":"dist/vue.runtime.esm.js",// 指定这个包被install时候有哪些文件 "files":[ "es", "lib" ], "man":, "directories":{ "lib":"./lib",// 存放 js 代码的目录 "bin":"./bin",// 若指定了bin字段,那么这个就无效了,存放可执行二进制文件的目录 "doc":"./doc",// 存放文档的目录 "example":"", ... }, "bin":{ "npm":"./cli.js", }, "workspaces":[ "packages/*" ], "man":[ "./man/npm-access.1", "./man/npm-audit.1" ], "exports":{ ".": "./main.mjs", "./foo": "./foo.js", ... } }
-
exports:最大的特点就是条件引用,比如我们可以根据不同的引用方式或者模块化类型,来指定npm包引用不同的入口文件。如果我们通过const p = require("pkg")引用的是"./main-require.cjs",如果我们通过import p from "pkg"引用的是"./main-module.cjs"。
如果存在exports属性,exports属性不仅优先级高于main,同时也高于module和browser字段
。 -
创建工作空间(workspaces):创建工作空间需要private为true时workspace才会被启用,workspaces属性的值为一个字符串数组,每一项指代一个workspace路径,支持全局匹配,这里的路径指的是
package.json所在文件夹名
。|--node_modules |--packages |--workspace-home # 工作空间workspace-home |--src |--package.json #独有的依赖,我们就可以单独安装在这个里面 |--workspace-admin |--src #我们这里可以引用share模块的, 由于定义的名字叫 @project/share, 我们引入的时候就像这样 import { xxxx } from '@project/share' |--package.json |--share |--package.json #在package.json里面要定义name属性,比如这个叫 @project/share |--package.json #公用的依赖,我们就可以安装在这个里面
注意地,工作空间中,package.json我们需要添加name属性,这是工作空间名字,不是文件名。创建工作空间我们就可以让移动端与pc端项目共存在一个文件夹中了
-
vue项目搭建工作空间:新建一个packages的目录,这个目录新建三个文件夹admin,mobile,share,
/vue-project |--packages |--admin pc端 |--public |--src |--babel.config.js |--package.json |--mobile 移动端 |--public |--src |--babel.config.js |--package.json |--share 放公用的代码 |--index.js |--package.json |--package.json
-
在对应的admin、mobile、share的package文件中定义相关脚本启动信息,以admin为例:
// admin/package.json { "name": "@project/admin", "version": "0.1.0", "scripts": { "serve": "vue-cli-service serve", "dev": "vue-cli-service serve", "build": "vue-cli-service build", "lint": "vue-cli-service lint" }, "devDependencies": { "@vue/cli-service": "~4.5.0" } }
// 根目录下package.json { "private": true, "workspaces": [ "packages/*" ], "scripts": { "lint": "yarn workspaces run lint", "build": "yarn workspaces run build", "dev:admin": "yarn --cwd packages/admin dev", "build:admin": "yarn --cwd packages/admin build", "dev:mobile": "yarn --cwd packages/mobile dev", "build:mobile": "yarn --cwd packages/mobile build" }, }
-
工作空间的相关命令:
#能够共享的包就安装到根 #工作空间独立的就单独安装到工作区 #添加到根 yarn add cross-env -D -W #删除根 yarn remove cross-env -W #如果想单独添加或者移除某个子项目的依赖,可以使用如下命令: yarn workspace <workspace_name > add <pkg_name> --dev yarn workspace <workspace_name > remove <pkg_name> #注意: workspace_name workspace_name 包名,package.json 中设置的 name,不是文件夹名 #比如 yarn workspace @project/home add swiper yarn workspace @project/admin add swiper yarn workspace @project/home add react-custom-scrollbars
1.3 发布配置
-
package.json配置:
{ "private":true, "preferGlobal":true,// 用户不把该模块安装为全局模块时,如果设置weitrue就会显示警告。 "publishConfig":{ "tag":"1.1.0" "registry":"http://registry.mddd.js.com", "access":"public",// 包的访问权限 }, "os":["darwin","linux"], "cpu":["x64","!mips"],// 适用cpu与禁用cpu "license":"MIT", }
1.4 第三方配置
-
package.json配置:
{ "gitHooks": { "pre-commit": "lint-staged" }, "lint-staged": { "*.{js,jsx,vue}": [ "vue-cli-service lint", "git add" ] } "browserlist":{ "production":[ ">0.2%", "not dead", "not op_mini all", ], "development":[ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "typings":"types/index.d.ts", "type":"module||common.js", "unpkg":"dist/vue.js", "babel": { "presets": ["@babel/preset-env"], "plugins": [...] }, "eslintConfig":{ "root": true, "env": { "node": true }, "extends": [ "plugin:vue/essential", "eslint:recommended" ], "rules": {}, "parserOptions": { "parser": "babel-eslint" }, }, "jsdelivr": "dist/vue.global.js",// 与unpkg类似 "sideEffects": [ "a.js", "b.js" ] }
-
sideEffects:格式可以为boolean或string[],为fasle,告知打包工具,当前项目无副作用,可以适用tree shaking优化。为字符串数组,告知哪些文件无副作用,可以使用tree shaking优化。
-
engines:项目运行环境的要求声明
"engines": { "node": ">=0.10.3 <15" }
2 脚本命令
2.1 script字段相关的配置字段
- config:用来配置 scripts 运行时的配置参数。
"config": { "port": 3000 }
2.2 npm run xxx发生了什么?
其实npm run 实际上是npm run-script命令得简写,当我们运行npm run xxx时,基本步骤如下(以npm run serve为例):
"serve": "vue-cli-service serve",
-
在项目的根路径找到“package.json”文件,然后在里面的“scripts”找到“xxx”命令,并执行。
-
以传给npm run 的第一个参数作为键,也就是xxx为serve,执行npm run serve就是执行vue-cli-service serve命令。
为什么不直接执行vue-cli-service serve?
因为系统并没有vue-cli-service这个命令,只有npm相关命令,而在我们下载安装依赖的时候,会在node_modules/.bin目录下创建好名为vue-cli-service的可执行文件。
-
当执行vue-cli-service serve命令时,npm会到
./node_modules/.bin
中找到可执行文件作为脚本来执行,npm 还会自动把node_modules/.bin加入$PATH 变量内,相当于执行了./node_modules/.bin/vue-cli-service serve
。依赖包里的.bin目录不是任何的npm包,其目录下文件的可执行文件都是一个个
软链接
;其余node_modules目录下的文件夹都是一个个下载下来的依赖模块
。软连接相当于是一种映射
,在执行npm run xxx的时候,就会到.bin目录找到对应的映射文件,然后再找到相对应的js文件。一般针对一个依赖模块,在npm下会有三个可执行文件,而在yarn下只有两个(没有以.ps1为后缀名的) -
通过.bin目录下的可执行文件映射到vue-cli-service.js并执行。
软链接指向哪里?指向的是对应依赖模块的js文件,如vue-cli-serve指向
node_modules/@vue/cli-service/bin/vue-cli-service.js
。怎么体现?在npm安装的时候就将bin/vue-cli-service.js
作为bin声明了。
2.3 script字段里的命令
-
脚本命令写法:一种是通过软链接映射,另一种是通过全路径指向在npm依赖包里的目标js文件。
"script":{ "serve": "vue-cli-service serve", "dev": "node node_modules/@vue/cli-service/bin/vue-cli-service serve", }
-
命令上的灵活配置:多个命令串行执行,多个命令并行执行,定义命令传参
多个命令串行执行使用&&
:前一条命令执行完才去执行后一条命令,下面例子就是在前端程序执行终端执行后端启动文件。"script":{ "server": "cd server && nodemon app.js", }
多个命令并行执行使用&
:同时执行多项命令,加上& wait的原因是保证每条命令都能执行完,因为每条命令执行时间都不一样"script":{ "lint": "npm run lint:js & npm run lint:css & npm run lint:json & npm run lint:markdown & mocha tests/ & wait", }
其实上面这种方法都不太好,有一个更好的方法就是使用
npm-run-all
,需要安装npm-run-all插件,在后面加上参数--parallel
。"script":{ "dev": "npm-run-all --parallel mock serve", "mock": "cd mock && nodemon app.js", "serve": "vue-cli-service serve", }
或者还有一种方法是安装插件concurrently进行使用。
"script":{ "dev:mock": "concurrently \"yarn:mock\" \"vue-cli-service serve\"", "mock": "cd mock && nodemon app.js", }
刚才我们看到 --parallel就是一个
命令传参
,传参一种是带值,一种是不带值(本身就代表一种值或一种模式)--prod //生产模式 --source-map // 是否允许调试时看到源代码 // 带值 --max_old_space_size=12288 // 允许增加节点的最大堆大小
-
常见脚本命令:
// 删除目录 "clean": "rm -rf dist && mkdir dist", "example": "export DEBUG=table* && babel-node ./example/example.js", "test": "export DEBUG=table && babel-node ./test/test.js", "build": "./node_modules/.bin/babel src --out-dir dist", // 可以简写成下面的形式 "build": "babel src --out-dir dist", "build:pkg": "babel bin --out-dir dist/bin --copy-files", "prepublishOnly": "npm run clean && npm run build", // 配置环境变量 "start": "export DEBUG=table* && node scripts/start.js", "build": "node ./scripts/build.js", "test": "node scripts/test.js --env=jsdom", "pub:es": "npm run clean && export BABEL_ENV=production && babel src --out-dir es --copy-files", "pub:lib": "npm run clean && export BABEL_ENV=node && babel src --out-dir lib --copy-files", "pub:um": "npm run clean:dist && export RABEL_ENV=production && webpack --config ./config/webpack.config.pub.js", "pub:optimized": "rm es/setting.js es/i18n.js es/index.local.js && rm lib.settings.js lib/i18n.js lib/index.local.js", "prepublishOnly": "npm run pub:lib && npm run pub:es && npm run pub:umd && npm run pub:optimized" // 本地搭建一个 HTTP 服务 "serve": "http-server -p 9090 dist/", // 打开浏览器 "open:dev": "opener http://localhost:9090", // 实时刷新 "livereload": "live-reload --port 9091 dist/", // 构建 HTML 文件 "build:html": "jade index.jade > dist/index.html", // 只要 CSS 文件有变动,就重新执行构建 "watch:css": "watch 'npm run build:css' assets/styles/", // 只要 HTML 文件有变动,就重新执行构建 "watch:html": "watch 'npm run build:html' assets/html", // 部署到 Amazon S3 "deploy:prod": "s3-cli sync ./dist/ s3://example-com/prod-site/", // 构建 favicon "build:favicon": "node scripts/favicon.js",
3 项目依赖
-
peerDependencies:消除重复下载依赖的问题。举个栗子:加油helloWorld项目中的package.json的dependencies中声明了packageA,有两个插件plugin1和plugin2也依赖packageA,如果在插件中使用dependencies来声明packageA,那么npm i安装完依赖后的包结构是这样的:
├── helloWorld │ └── node_modules │ ├── packageA │ ├── plugin1 │ │ └── nodule_modules │ │ └── packageA │ └── plugin2 │ │ └── nodule_modules │ │ └── packageA
从上面我们可以看到packageA被安装了三次就冗余了。所以我们需要在两个插件的package中配置peerDependencies:
//plugin1/package.json { "peerDependencies": { "packageA": "1.0.1" } } //plugin2/package.json { "peerDependencies": { "packageA": "1.0.1" } } //项目的package.json { "dependencies": { "packageA": "1.0.1" }
配置好上面的依赖package后,最后npm i 生成的文件结构如下:
├── helloWorld │ └── node_modules │ ├── packageA │ ├── plugin1 │ └── plugin2
-
bundleDependencies:用户安装了package-a后,将package-a所声明的依赖包汇总到package-a自身的node_modules下,便于用户管理,如果package-a中没有配置bundleDependencies,在安装了 package-a 的项目下 node_modules 就会长这样:
// package-a中没有配置bundleDependencies ├── node_modules ├── package-a ├── react ├── core-js └── loadsh
// package-a中配置了bundleDependencies ├── node_modules ├── package-a │ └── react │ └── core-js └── loadsh
// package-a包 { "name": "package-a", "dependencies": { "react": "^15.0.0", "core-js": "^2.0.0", "lodash": "^4.0.0" }, "bundleDependencies": [ "react", "core-js" ] }
-
optionalDependencies:可选依赖,如果有一些依赖包即使安装失败,项目仍然能够运行或者希望npm继续运行,就可以使用optionalDependencies。另外optionalDependencies会覆盖dependencies中的同名依赖包,所以不要在两个地方都写。
-
npm、yarn、pnpm三种安装依赖命令区别:
npm yarn pnpm Install all npm install yarn pnpm install Install npm install [package] yarn add [package] pnpm add [package] npm install [package] -D yarn add [package] -D pnpm add -D [package] npm install [package] -g yarn global add [package] pnpm add -g [package] Uninstall npm uninstall [package] yarn remove [package] pnpm remove [package] Update npm update [package] yarn upgrade [package] pnpm update [package]
4 依赖版本
- 先行版本:被标注在修订版之后,先加上
一个连接号再加上一连串以句点分隔的标识符
来修饰。标识符必须由ASCII字母数字和连接号组成([0-9a-zA-Z-]),如1.0.0-alpha、1.0.0-alpha.1 - 版本编译信息:标注在修订版或先行版本号之后,加上
一个加号再加上一连串以句点分割的标识符
来修饰。标识符必须由ASCII字母数字和连接号组成([0-9a-zA-Z-]),如1.0.0+190292、1.0.0-alpha+001、1.0.0-alpha+exp.001
5 参考资料
# package.json 配置完全解读 | # js-md5 | # 语义版本控制规范 | # 关于前端大管家package.json,你知道多少 |# vue项目中使用workspaces |# 一文搞懂peerDependencies |# package.json scripts 脚本使用指南 | 用 npm script 打造超溜的前端工作流 | # 当你运行npm run命令时,会发生什么?
转载自:https://juejin.cn/post/7160325877841002527