npm包讨论的n件事

128 阅读4分钟

一、前言

在日常的开发中,我们经常会遇到这样的场景:

  • 有些可复用的工具包或组件,可抽象成公共代码,供小组内部成员共同维护和使用
  • 业务组件需要提供给外部合作方使用
  • .....

npm包即以上需求的通用解决方案之一。npm作为Node.js平台的默认包管理工具,可以实现安装、共享、分发代码。(通常不同公司内部有私有的npm服务器)

本文记录本人在开发一个npm包时,会遇到的一些常见问题。

二、n件事

package.json

命名

name字段:遵循semantic规范 详情

正式版本:1(major).0(minor).0(patch),预览版本:1.0.0-prefix.x

patch:错误修复,可向后兼容

minor:次要版本,新功能,可向后兼容

major:大版本迭代,不兼容的更改

导出相关

  • main字段->node.js消费,指定加载文件入口;

  • module字段-> bundler打包器消费,esm版本,支持tree-shaking;

  • types-> 供ts 以及 ide消费;

  • exports:定义模块的导出,import路径 与 产物路径 的对应关系

    •   与main若共存,优先使用exports
  • files:字段是一个用于指定在发布npm包时应该包含哪些文件或目录的数组

main字段指向的文件应该在files指定的文件范围内。如果main指向的文件不在files指定的文件中,当这个包被安装到其他项目时,可能会出现找不到入口文件的情

files字段可以用来确保只发布必要的文件,并且可以通过配置确保main所依赖的其他文件(如辅助函数文件、配置文件等,如果它们在main文件中被引用)也被包含在发布的包中。例如,如果main文件lib/index.js依赖于lib/utils.js,那么可以通过"files":["lib/*"]确保这两个文件都被发布。

依赖相关

与依赖相关的不同字段的区别:

  • dependencies:生产环境必需的依赖,如express作为服务器请求库;
  • devDependencies:开发环境所需的依赖,在项目运行中不需要,如测试框架jest,构建工具webpack等;
  • peerDependencies:可由包的使用者或宿主环境提供的依赖,避免依赖的重复安装,如react,react-dom,一般在组件库的使用项目中,已安装对应依赖;
  • resolutions:主要用于解决依赖冲突的问题,当不同的依赖包依赖同一个库的不同版本时,使用resolutions指定版本,避免版本冲突
  • 依赖版本号:参考

    • ~/^

    • ~ 从右往左匹配非0

    • ^ 从左往右开始匹配非0

bin

  • bin:指定可执行的命令脚本,当你的项目被全局安装(npm install -g)或者本地安装后在node_modules/.bin下被调用时,bin字段定义的命令就可以被执行。常用来做自动化工具。

脚本文件:路径 ./bin/index.js

开发包 @package/utils-cli

#!/usr/bin/env node
import '../dist/es/index.js';

在bin字段中注册命令

"bin": {
    "utils-cli": "./bin/index.js"
  },

使用:

  • 局部安装:在使用方的package.json下安装依赖+注册脚本
{
  "name": "utils-mono",
  "private": true,
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    ......
    "create": "utils-cli init"
  },
  ......
  "devDependencies": {
     对应工具依赖
    "@package/utils-cli": "0.0.0-feat-test-20240825022141",
  },

}
  • 全局安装:

命令行直接输入 utils-cli init

编译

参考:cloud.tencent.com/developer/a…

将一种语言编写的源代码转换为另一种语言的过程。

  • 现有编译工具:

    • babel:新版本js->旧版本(浏览器兼容),ts->js等
    • tsc:ts官方编译器,ts->js
    • swc
    • esbuild

构建打包

将开发环境的代码,转换为生产环境的代码,通常通过合并,压缩,转换(存在高级语法),使得转换后的源码可在不同环境中使用。

  • 现有模块打包工具:

    • webpack:静态模块打包工具,从一个或多个入口点构建一个依赖图;
    • esbuild:用go编写,快;
    • rollup
    • Parcel
    • Vite
    • ......
  • 方案:bundle 与bundleless

    • bundle:传统的编译打包方案,常用工具有webpack,rollup等。

    • bundleless:无构建形式,常用工具有vite,snowpack等。

      • 出现bundleless的背景:
        • 由于项目资源增长与代码膨胀,构建的速度越来越慢,项目本地启动缓慢,更新缓慢,影响开发体验;

        • 浏览器原生支持esm模块,type="module",可实现、直接获取文件在浏览器上运行;

monorepo下的包版本管理

  • 解决问题:多包管理,各包之间互相依赖

    •   npm link的作用:将当前某个具体包在全局文件夹下创建一个符号链接,在其他使用方包下,再创建一个从全局链接到当前node_module的符号链接。
    •   缺点:两步操作,多个子包操作复杂性,有依赖关系时,需要确定执行命令的先后顺序;版本更新麻烦。
  • 现有工具:juejin.cn/post/722068…

    • lerna
    • npm/yarn/pnpm +changeset
    •   changeset 版本管理和发布,包含在分支与commit山的改动信息的markdown文件, init->add->version->publish

发包

  • 传统发包流程:

原始:npm init 生成 npm模版, 编写代码,commit,手动变更版本号 , npm publish,git push

辅助npm工具:

npm version 版本升级,自动打tag

conventional-changelog 根据规范commit自动生成版本变更内容CHANGELOG.md

standard-version 取代npm version命令,根据commit message自动决定下一个版本号

semantic-release CI发包