自定义NPM包
环境初始化
mkdir npm-log
cd npm-log
npm init -y
入口文件
自定义依赖模块:
模块是在
package.json
里通过main
字段定义这个包对外暴露的入口;- 模块起源于
node
,语法默认支持commonjs
规范 - 模块若使用
ES Module
语法书写,通过module
字段定义入口(需要打包工具配合使用)
- 模块起源于
自定义命令行:
- 如果是提供命令行工具,则需要通过
pkg#bin
字段来定义暴露的命令名称与实际执行的文件
- 如果是提供命令行工具,则需要通过
这篇文章讲述自定义依赖模块的声明,后续会有专门篇幅进行自定义命令行的讲述。
声明示例
创建
lib/index.js
const Noop = () => {} class Logmi { errorHandler = Noop successHandler = Noop static create (options) { return new Logmi(options) } constructor (options = {}) { console.log('---------create------', options) } log (msg, level) { console.log('log: start', msg, level) } } module.exports = Logmi
更新
package.json
"main": "lib/index.js"
开发环境
- [ ] 自动日志
- [ ] 版本更新
npm install husky --save-dev npx husky install
配置
run-script
:安装依赖后自动启动Git hooks
"prepare": "husky install"
追加测试钩子
# Unix系统可用 npx husky add .husky/pre-commit "npm run test" # Windows通过以下命令创建文件(引号在windows下不是正确的语法) npx husky add .husky/pre-commit # Windows去新建的文件中指定命令 #!/bin/sh . "$(dirname "$0")/_/husky.sh" npm run test
commitlint
commitlint
提交信息校验工具- 需要和校验规范配合使用,官网默认规范
@commitlint/config-conventional
—— 可自定义。 commitlint
绑定@commitlint/config-conventional
npm i -D commitlint @commitlint/config-conventional # Unix echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js # Windows echo module.exports = {extends: ['@commitlint/config-conventional']} > commitlint.config.js
配置
Git hook
:在提交commit msg
进行参数校验 —— 写在run-script
中无效# Unix系统可用 npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1" # Windows通过以下命令创建文件(引号在windows下不是正确的语法) npx husky add .husky/commit-msg # Windows去新建的文件中指定命令 #!/bin/sh . "$(dirname "$0")/_/husky.sh" npx --no-install commitlint --edit $1
standard-version
npm i --save-dev standard-version
配置
run-script
:发布前自动升级版本号 + 生成日志"prepublishOnly": "standard-version"
注意:这里不要使用
prepublish
钩子,该钩子在npm i
时运行,而不是npm publish
时运行。
调试
进入本地
NPM
包npm link
创建软链接到全局node
环境中
进入依赖包的项目A中
npm link <packageName>
建立软链接依赖
在项目A需要调用的文件中
# 调用 import Logmi from "log"; const LogmiInstance = Logmi.create({ url: 'http://localhost:3000' }) LogmiInstance.log(`paste: ${JSON.stringify(paste)}`, 1)
- 启动项目A,即可调试
开发
NPM
包是commonJS
语法,使用require()
,而非import...from...
引入依赖。
实例化参数
- 工厂函数
参数默认值
const Noop = () => {}
:空语句
传参校验
- 参数数据实体类型
校验警告
- 参数合并
DTO
- 校验DTO组成结构参数
ParamChecker
- 统一结构
ContentWrapper
- 校验DTO组成结构参数
配置信息统一分类处理
module.exports = { EXCEED_TRY_TIMES: 'Exceed try times', }
打包发布
打包需要引入webpack
,这里的package.json
修改入口文件:
"main": "dist/logmi.js",
"module": "lib/index.js",
其中,main
是暴露打包后的入口文件;module
是webpack
环境下暴露的入口文件;
package.json
{
"name": "log",
"version": "1.0.0",
"description": "",
"main": "dist/logmi.js",
"module": "lib/index.js",
"scripts": {
"prepare": "husky install",
"build": "cross-env NODE_ENV=production webpack --config webpack.config.js --mode=production",
"test": "echo \"npm run test\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.14.3",
"@babel/preset-env": "^7.14.4",
"@commitlint/cli": "^12.1.4",
"@commitlint/config-conventional": "^12.1.4",
"babel-loader": "^8.2.2",
"cross-env": "^7.0.3",
"husky": "^6.0.0",
"standard-version": "^9.3.0",
"terser-webpack-plugin": "^5.1.3",
"webpack": "^5.38.1",
"webpack-cli": "^4.7.0"
},
"dependencies": {
"@babel/polyfill": "^7.12.1",
"idb-managed": "^1.0.9"
},
"bundledDependencies": [
"idb-managed"
]
}
pkg#main
作为第三方依赖包时,包的入口执行文件。
如果没有指定,默认为root
目录下的index.js
。
pkg#bin
作为命令行工具时,包的入口执行文件
安装该包时,node
会自动创建硬链接该包到全局执行环境。
String
:单执行文件Map
:多执行文件
pkg#module
非官方配置,rollup
、webpack
等打包工具提供的配置项。
指向的应该是一个基于ES6
模块规范书写的模块。
pkg#private
设置"private": true
,npm
拒绝发布该包。
pkg#workspaces
结合monorepo
的概念,创建工作区。
pkg#files
安装该包时,目录中包含在pkg.files
中指定的文件结构。
默认包含:
package.json
README
CHANGES / CHANGELOG / HISTORY
LICENSE / LICENCE
NOTICE
The file in the "main" field
pkg#bundledDependencies
通过fpt
、scp
等工具传输该包时,需要将该包的依赖打包在一起。
在
bundledDependencies
中指定依赖包的列表- 只需要指定包名,版本会在
dependencies
查找
- 只需要指定包名,版本会在
- 通过
npm pack
打包 - 通过传输工具传输打好的
*.tgz
包 - 通过
npm i *.tgz
安装该包及其依赖
Note: 定义在bundledDependencies
列表内的依赖,安装NPM包时,该依赖会嵌套在包文件下,而不会提升到node_modules
目录的根下
pkg#peerDependencies
表明该包对主包/主工具库的兼容性,而不是依赖性,这种关系称之为插件。
- 主包一般会对插件暴漏的接口指定标准
在peerDependencies
指定的包@版本号
表明,我们的包需要在指定包的环境下执行,需要一同安装。
打包
安装插件
npm i -D webpack-cli webpack cross-env terser-webpack-plugin
npm install --save-dev @babel/core babel-loader @babel/preset-env
npm install --save @babel/polyfill
配置babel.config.json
{
"presets": [
[
"@babel/env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": "3.6.5"
}
]
]
}
配置run-script
...
"build": "cross-env NODE_ENV=production webpack --config webpack.config.js --mode=production",
...
webpack.config.js
const path = require('path')
const webpack = require('webpack')
const TerserPlugin = require("terser-webpack-plugin")
const resolve = dir => path.join(__dirname, '.', dir)
const isProd = process.env.NODE_ENV === 'production'
module.exports = {
entry: {
logmi: './lib/index.js'
},
output: {
path: resolve('dist'), // 输出目录
filename: '[name].js', // 输出文件
libraryTarget: 'umd', // 采用通用模块定义
library: 'logmi', // 库名称
libraryExport: 'default', // 兼容 ES6(ES2015) 的模块系统、CommonJS 和 AMD 模块规范
globalObject: 'this' // 兼容node和浏览器运行,避免window is not undefined情况
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
},
optimization: {
minimize: true,
minimizer: [new TerserPlugin()],
}
}
配置可见目录结构
...
"files": [
"dist/"
]
...
发布
若使用nrm
维护多个npm
源,需要切换到发布的目标源。或者通过pkg#publishConfig
、.npmrc
指定目标源。
以npm
为例:
切换到
npm
源nrm use npm
- 在NPM官网注册账号
命令行中登录用户
npm login
在项目目录下发布包
npm publish
补充知识
The peerDependencies configuration was originally designed to address the problem of NPM packages that were ‘plugins’ for other frameworks.
删除CHangeLog
EIP1559与传统Gas定价模型转账逻辑
米花儿团儿阅读 281
如何发布一个 TypeScript 编写的 npm 包
chuck赞 6阅读 590
都2022 年了,你总不能还只会 npm i 吧? 🔥🔥🔥
荣顶赞 9阅读 2.5k
使用 github actions 实现 npm 包自动化发布
MrBigShot赞 1阅读 2.3k
Promise: 异步编程的理解和使用
后除赞 2阅读 793
浅谈浏览器端 WebGIS 开发可能会用到的、提升效率的 js 库
四季留歌赞 1阅读 535
麒麟操作系统 (kylinos) 从入门到精通 - 研发环境 - 第十一篇 Web前端开发及环境准备
码上世界阅读 1.4k评论 1
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。