package.json疑难字段说明

626 阅读3分钟

一、字段说明

// 必须,长度必须小于或等于214个字符,不能以“.”和“_”开头,不能包含大写字母
// 最终会作为URL使用,所以不能包含非URL安全字符
"name": "vuex",
// npm包项目的主要入口文件,必须的
"main": "dist/vue.runtime.common.js",
// node17版本的新字段,可以根据模块指定不同的引用入口
// 参考:https://nodejs.org/api/packages.html#packages_conditional_exports
"exports": {
  ".": {
    "module": "./dist/vuex.esm.js",
    "require": "./dist/vuex.common.js",
    "import": "./dist/vuex.mjs"
  },
  "./*": "./*",
  "./": "./"
},
// 打包工具支持es的时候的引用入口
"module": "dist/vue.runtime.esm.js",
// npm 上所有的文件都开启 cdn 服务地址
"unpkg": "dist/vue.js",
// jsdelivr cdn公共库
"jsdelivr": "dist/vue.js",
// TypeScript 的入口文件
"typings": "types/index.d.ts",
// 当你发布package时,具体那些文件会发布上去
"files": [
  "src",
  "dist/*.js",
  "types/*.d.ts"
],
// 声明该模块是否包含 sideEffects(副作用),从而可以为 tree-shaking 提供更大的优化空间。
"sideEffects": false,
// 指明了该项目所需要的node.js版本
"engines": {
  "node": ">=8.9.1",
  "npm": ">=5.5.1",
  "yarn": ">=1.3.2"
},
// 版本号格式为:主版本号.次版本号.修订号
// 依赖存在以下情况:
// 1. 固定版本:react-scripts的版本4.0.3就是固定版本,安装时只安装这个指定的版本;
// 2. 波浪号:比如~4.0.3,表示安装4.0.x的最新版本(不低于4.0.3),也就是说安装时不会改
// 变主版本号和次版本号;
// 3. 插入号: 比如 react 的版本^17.0.2,表示安装17.x.x的最新版本(不低于17.0.2),
// 也就是说安装时不会改变主版本号。如果主版本号为0,那么插入号和波浪号的行为是一致的;
// 4. latest:安装最新的版本
"dependencies": {
  "react": "^17.0.2",
  "react-dom": "^17.0.2",
  "react-scripts": "4.0.3",
},
// 前置依赖
"peerDependencies": {
  "chai": "1.x"
}

其他字段比较简单,在此不再赘述。

二、module

接下来对比下modulemain在实践中的差异,下面是package.json的一种配置:

{
  "main": "dist/dist.js",
  "module": "dist/dist.es.js"
}

相当于在一个包内同时发布了两种模块规范的版本。

当打包工具遇到我们的模块时:

  • 如果它已经支持 module 字段则会优先使用 ES6 模块规范的版本,这样可以启用 Tree Shaking 机制。
  • 如果它还不识别 module 字段则会使用我们已经编译成 CommonJS 规范的版本,也不会阻碍打包流程。

试验

我们可以做个Demo测试下是否优先引用module地址,其次才是main

新建一个项目,用rollup打包。rollup.config.js的配置如下:

import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs'
import babel from '@rollup/plugin-babel'
import json from '@rollup/plugin-json'

export default [{
  input: ['./src/index.js'],
  output: {
    file: './dist/bundle.js',
    format: 'umd',
    name: 'mybundle'
  },
  plugins: [resolve(),commonjs(), babel(), json()],
  external: ['axios']
}]

node_modules下新建文件夹,随便起个名字比如test-module,然后创建以下文件夹和文件:

- dist
  - dist.js
  - dist.es.js 
- package.json

node_modules/test-module/package.json中设置如下:

{
  "main": "dist/dist.js",
  "module": "dist/dist.es.js"
}

node_modules/test-module/dist/dist.js中定义变量a为1,并导出:

var a = 1;
module.exports = { a }

node_modules/test-module/dist/dist.es.js中定义变量a为2,并导出:

export const a = 2;

然后在外层的项目src/index.js中引入测试模块test-module,然后打印a的值:

import a from 'test-module'

console.log('a')

然后执行rollup -c,在打包后的文件中查看:

// ...

const a = 1;

// ...

去掉node_modules/test-module/package.json中的module字段,再次打包一次后查看:

// ...

var index_cjs = {
  a: 2
};

// ...

可知对于rollup这种可以识别es6语法的打包器来说,确实会优先引入package.jsonmodule字段对应的文件,其次是main字段,验证了上面的说法。

三、相关资料

  1. nodejs17文档
  2. npm package.json
  3. 你真的了解package.json吗?来看看吧,这可能是最全的package解析
  4. 关于前端大管家 package.json,你知道多少?
  5. package.json中的exports
  6. 聊聊 package.json 文件中的 module 字段