组件库开发系列 - package.json 认识

712 阅读6分钟

虽然我们使用 node 环境,但是对于 package.json 并不一定那么熟悉,这篇讲一下里面一些字段的含义,包托管 到 npmjs

目录

  • npm 配置

  • 搞懂 CommonJS、AMD、CMD、UMD、ES6 模块化

  • package.json 字段

nvm 使用

nvm就是可以让你电脑使用多个nodejs版本,要使用哪个版本时切换即可。

如果已经安装过nodejs了,先卸载掉吧

1、下载nvm

https://github.com/coreybutler/nvm-windows/releases

2、使用镜像地址

打开nvm安装目录 setting.txt,把下面两句放到里面

node_mirror: https://npm.taobao.org/mirrors/node/
npm_mirror: https://npm.taobao.org/mirrors/npm/

3、常用命令

nvm list // 查看当前系统已安装过的node版本
nvm list available // 查看服务器可用node版本,完整查看 https://nodejs.org/en/download/releases/
nvm install v12.22.0  // 安装12.22.0版本
nvm use 12.22.0 // 切换到12.22.0版本

4、nvm切换不成功

exit status 5: �ܾ����ʡ�  exit status 1: ���ļ��Ѵ���ʱ���޷��������ļ���

nvm切换不成功

切换为管理员模式,重新切换。

npm 配置

  • 创建空白文件
npm init -y
  • npm源

设置

// 淘宝源
npm config set registry https://registry.npm.taobao.org  

// npmjs
npm config set registry https://registry.npmjs.org

查看所有配置项

// 看所有
npm config list -l     

// 看源
npm config get registry

一次性安装指定源

npm install --registry https://registry.npm.taobao.org

搞懂 CommonJS、AMD、CMD、UMD、ES6 模块化

前端在之前都使用script引用js脚本,随后各大社区便于出现模块化引用的解决方案,便于代码复用等

  • CommonJS 即 CJS ,运行于 服务端只能同步加载 nodejs 使用 require,module.exports 引用/导出模块

      可写 require |exports , exportsmodule.exports的引用
    
// B.js
module.exports.b = 2  或者  exports.b = 2
// C.js
const B from './B.js'
console.log(B.b)
  • AMD 和 CMD 运行于 客户端异步加载,浏览器需要异步加载,而CommonJS只有同步加载,于是这是为了兼容CommonJS在浏览器端的方案

  • UMD 就是结合 CommonJS、AMD、CMD,即 支持服务端 也 支持客户端,组件库一般都是导出这个格式,就达到了跨平台的解决方案。

      1、先判断是否支持AMD(define是否存在),存在用AMD模块的方式加载模块
      
      2、再判断是否支持NodeJS的模块(exports是否存在),存在用NodeJS模块的方式,
      
      3、否则挂在window上,当全局变量使用。
      
      这也是目前很多插件头部的写法,就是用来兼容各种不同模块化的写法。
    
(function(window, factory) {
    //amd
    if (typeof define === 'function' && define.amd) {
        define(factory);
    } 
    //cjs
    else if (typeof exports === 'object') { 
        module.exports = factory();
    } 
    else {
        window.jeDate = factory();
    }
})(this, function() {  
    ...module..code...
})
  • ES6 即 ESM, 使用 importexportexport default 引用/导出模块,ES6 有望成为浏览器和服务器通用的模块解决方案,但还需要Webpack等工具转换为CommonJS
// B.js
export const b = 2 或者 export default { b: 2 }
// C.js
import B from './B.js'
console.log(B.b)

注意:

  • CommonJS 输出的是值的拷贝,ES6 输出的是值的引用,于是值的变化对CommonJS没影响,但是对ES6就有影响

  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口

      CommonJS 加载的是一个对象,即module.exports对象,该对象只在运行时生成;而ES6模块不是对象,
      对外接口只是一种静态定义,在代码静态解析阶段就会生成
    
  • CommonJS 默认导出对象 module.exports 是 {} 空对象,ES6 默认到处 export default 是 undefined,所以循环引用时,两者表现不一致

结论:

  • 目前三种规范 esm 、cjs 、umd 占据主流,其中:

  • esm :现代 ECMA 规范,摇树(tree shaking)性能好,首推使用

  • cjs :node 使用的 require 规范,无摇树

  • umd :支持 cjs 和 amd 规范,自动挂载导出到 global ,一般用在浏览器中

  • 最好不要使用 browser 字段,永远使用 module 字段支持摇树,如果必须支持 umd ,可以添加至 umd 到 main 字段

package.json 字段

name

项目名

  • 发布到 npmjs 的 name 需要全网唯一

  • name必须是字符串,不能以.或_开头,不能有大写字母,因为名称最终成为URL的一部分因此不能包含任何非URL安全字符

  • 包含组织时,如 @vue/cli 时,vue表示组织名,需要在 npmjs 上先在账号下创建 vue 这个组织,cli名在该组织下唯一即可

version

版本号

  • 通常三段式 遵循 大版本major.次要版本minor.小版本patch 的格式规定

  • devDependencies 和 dependencies

    1、指定版本 ^3.3.4表示主版本固定的最大版本3.x.x

    2、指定版本 ~3.3.4表示主版本和次版本固定的最大版本3.3.x

    3、指定版本 3.3.4表示所有版本固定3.3.4

files

是字符串数组,表示允许推送到 npmjs 上的文件或者目录

  • files 存在,则只推送包含的文件或目录,同时表示安装时这个包时会有这些文件存在
  • files 不存在,则项目所有文件全部推送,但是 npmjs 限制项目最大 100M

main 、browser 、module

这是指明当前包的入口文件地址,回顾前面 【搞懂 CommonJS、AMD、CMD、UMD、ES6 模块化】 这段结论里说清楚了,需要生成ES6(ESM)、CommonJS(CJS)、UMD格式的模块文件,所以main 、browser 、module这三个字段的作用就是指明不同导出格式文件的路径。

一般情况下他们在 package.json 中的对应字段如下:

字段规范
maincjs
moduleesm
browserumd

这里最大的问题在于:

对于一个库来说 cjs 和 umd 是需要连带第三方依赖一同打包的,因为很多配置都会默认排除 node_modules ( 比 如 babel ),导致库得不到 polyfill ,特别是 webpack 5 已经去除了自动添加 polyfill 的特性后,对 cjs和 umd 的包更要格外注意,如果依赖中含有 es6 语法,最后得到的产物可能仍未被转换。

这个问题告诉我们 cjs 和 umd 以后必须要连同 polyfill 和第三方依赖一同打进来,这样才能保证兼容,也就是说丢失了摇树性能,整个库要用其中一个函数就需要都引入。

对 webpack 的影响

但 webpack 的 Resolve 机制会默认优先识别 browser 也就是 umd 规范,这就使得你只要使用了该库任何功能都会被整个库打包进来( 配置字段 resolve.aliasFields ),当无 browser 字段时优先使用 module 字段(支持摇树)。

总结

所以毫无疑问,在用户不知情的情况下,永远都不要使用 browser 字段,永远使用 module 字段支持摇树,如果必须支持 umd ,可以添加至 umd 到 main 字段( 详见 Specifying builds in package.json)。

bin

bin 字段用于全局命令,详情看我前面系列 脚手架原理篇

简单说,

  • 全局安装时,mybuild会成为命令行可识别命令,会执行全局 mybuild.js 文件
  • 项目中安装时 npx mybuild,会执行项目包中 mybuild.js文件
"bin": { 
    "mybuild": "./bin/mybuild.js" 
}

scripts

可执行 npm run xxx 命令

"bin": { 
    "serve": "vue-cli-service serve",
}

devDependencies 、 dependencies 、peerDependencies

安装依赖包

devDependencies 是 npm i webpack -D 安装的,只出现在打包阶段,最终发布文件中不存在

dependencies 是 npm i axios 安装的,在最终发布文件中存在

peerDependencies 是 让宿主环境去安装满足插件peerDependencies所指定依赖的包。

    当我们开发一个模块的时候,如果当前模块与所依赖的模块同时依赖一个第三方模块,
    并且依赖的是两个不兼容的版本时就会出现问题,最终解决插件与所依赖包不一致的问题。
    从npm 3.0版开始,peerDependencies不再会默认安装了
    

engines

指明了该模块运行的平台,比如Node``的某个版本,或者npm的某个版本或者浏览器。

"engines": {
    "node" : ">=8.9.0 <12.x", 
    "npm" : "~6.14.12" 
}

private

指明该项目是否能发布到npmjs上,详情看在 脚手架系列 - lerna和yarn配合单体包

简单说,一般没有这个字段,如果设置 true ,则不能推送到npmjs上

browserslist

代表这个项目的浏览器兼容情况

browserslist 是一个开源项目,具体的影响到前端工具的编译情况,比如 Autoprefixer 可以给css加兼容性前缀 babel-preset-env , eslint-plugin-compat, stylelint-no-unsupported-browser-features 和 postcss-normalize

 "browserslist": [
    "> 1%",
    "last 2 versions",
    "Android >= 3.2", 
    "Firefox >= 20", 
    "iOS 7"
  ]

sideEffects

副作用字段,文件数组,因为tree shaking时,会把没用到的文件移除,sideEffects字段的作用就是告诉webpack,依然要保留这些文件