npm发布js工具包

一、创建项目

  • 1、在github上创建一个项目,然后拉取至本地,进入项目目录
  • 2、执行 npm init 生成json文件
  • 3、创建 src/index.ts 入口文件和 src/isObject.ts 工具方法
· src/index.ts
export { default as isObject } from './isObject'
· src/isObject.ts
/**
 * @description 判断是否为对象
 * @param {*} variable
 * @returns {Boolean}
 */
function isObject(variable: any): boolean {
    return Object.prototype.toString.call(variable) === '[object Object]'
}

export default isObject

二、配置Rollup打包

  • 1、安装rollup和typescript npm install rollup typescript -D
  • 2、创建 tsconfig.json 配置文件:
{
    "compilerOptions": {
        "target": "es5" /* 编译目标 */,
        "module": "commonjs" /* 项目模块类型 */,
        "lib": ["ES2018", "DOM"],
        "allowJs": true /* 是否允许js代码 */,
        "checkJs": true /* 检查js代码错误 */,
        "declaration": true /* 自动创建声明文件(.d.ts) */,
        "declarationDir": "./lib/types" /* 声明文件目录 */,
        "sourceMap": true /* 自动生成sourcemap文件 */,
        "outDir": "lib" /* 编译输出目录 */,
        "rootDir": "./src" /* 项目源码根目录,用来控制编译输出的目录结构 */,
        "strict": true /* 启用严格模式 */
    },
    "include": ["src/*.ts"],
    "exclude": ["node_modules", "lib"],
}
  • 3、安装rollup插件
    · 处理路径 npm install @rollup/plugin-node-resolve -D
    · 支持ts npm install @rollup/plugin-typescript -D
    · 处理commonjs npm install @rollup/plugin-commonjs -D
    · 压缩umd规范的输出文件 npm install @rollup/plugin-terser -D
    · 重新打包代码清理 npm install rollup-plugin-delete -D
  • 4、创建 rollup.config.js 配置文件:
const resolve = require('@rollup/plugin-node-resolve') // 处理npm包的相关引入依赖
const typescript = require('@rollup/plugin-typescript')
const commonjs = require('@rollup/plugin-commonjs') // 将commonJS的语法转化成ES2015 Module
const terser = require('@rollup/plugin-terser') // 代码压缩
const del = require('rollup-plugin-delete')

module.exports = [
    {
        input: './src/index.ts',
        output: [
            {
                dir: 'lib',
                format: 'cjs',
                entryFileNames: '[name].cjs.js',
                sourcemap: true, // 是否输出sourcemap
            },
            {
                dir: 'lib',
                format: 'esm',
                entryFileNames: '[name].esm.js',
                sourcemap: true, // 是否输出sourcemap
            },
            {
                dir: 'lib',
                format: 'umd',
                entryFileNames: '[name].umd.js',
                name: 'Umob', // umd模块名称,自动挂载至window
                sourcemap: true,
                plugins: [terser()],
            },
        ],
        plugins: [
            del({ targets: 'lib/*' }),
            resolve(),
            commonjs(),
            typescript({ module: 'ESNext' }),
        ],
    },
]
  • 5、在package.json配置的scripts中增加构建脚本 "build": "rollup -c"
  • 6、执行 npm run build

三、手动发布

  • 1、完善配置文件
· .npmignore
src/
node_modules/
.babelrc
.gitignore
· package.json
{
	"name": "your project name",
	"version": "0.0.1",
	"description": "your project description",
	"browser": "lib/index.esm.js", // umd规范
	"module": "lib/index.esm.js", // 使用esm时,会使用这个包
	"jsnext:main": "lib/index.esm.js",  // 社区规范
	"main": "lib/index.cjs.js", // 当使用commonjs规范时会使用这个包
	"types": "lib/types/index.d.ts", // ts类型文件
	"files": ["lib"], // 用于约定在发包的时候NPM 会发布包含的文件和文件夹。
	"scripts": {
		"build": "rollup -c",
	},
	"keywords": [
		"modules",
		"stdlib",
		"util"
	],
	"author": "Unknow",
	"license": "MIT",
	"devDependencies": {
		"@rollup/plugin-commonjs": "^25.0.0",
		"@rollup/plugin-node-resolve": "^15.1.0",
		"@rollup/plugin-terser": "^0.4.3",
		"@rollup/plugin-typescript": "^11.1.1",
		"rollup": "^3.23.0",
		"rollup-plugin-delete": "^2.0.0",
		"tslib": "^2.5.2",
		"typescript": "~5.0.4"
	},
	"repository": {
		"type": "git",
		"url": "https://github.com/xxx.git"
	}
}
  • 2、登陆npm账号(没有去官网注册一个) npm login
  • 3、查看是否登录成功 npm who am i
  • 4、将包推送至服务器 npm publish
  • 5、package中的name不可与他人重复,否则会提示权限问题。如果使用@[scope]/package的命名形式,[scope]需要填账户名称

四、安装jest单元测试

  • 1、安装 install jest ts-jest @types/jest jest-environment-jsdom -D
  • 2、根目录下新增配置文件:
· .jest.config.js
/** @type {import('ts-jest').JestConfigWithTsJest} */

module.exports = {
	preset: 'ts-jest',
	testEnvironment: 'jsdom', 
    clearMocks: true,
    collectCoverage: true,
    coverageDirectory: 'coverage',
    coverageProvider: 'v8',
    moduleFileExtensions: ["ts", "js"],
    // 配置测试环境ua
    testEnvironmentOptions: {
        userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
    },
}

3、在 package.json 配置的scripts中增加测试脚本 "test": "jest"
4、编写单元测试:

· src/tests/isObject.test.ts
import { isObject } from '../index'

describe('isObject: ', () => {
    it('Determine the type of number', async () => {
        expect(isObject(1)).toEqual(false)
    })

    it('Determine the type of string', async () => {
        expect(isObject('1')).toEqual(false)
    })

    it('Determine the type of boolean', async () => {
        expect(isObject(false)).toEqual(false)
    })

    it('Determine the type of array', async () => {
        expect(isObject([])).toEqual(false)
    })

    it('Determine the type of undefined', async () => {
        expect(isObject(undefined)).toEqual(false)
    })

    it('Determine the type of null', async () => {
        expect(isObject(null)).toEqual(false)
    })

    it('Determine the type of symbol', async () => {
        const symbol2 = Symbol('this is symbol')
        expect(isObject(symbol2)).toEqual(false)
    })

    it('Determine the type of empty object', async () => {
        expect(isObject({})).toEqual(true)
    })
})
  • 5、增加单文件单元测试命令,用于团队本地开发测试使用 "test:single": "node env-dependencies.js"
  • 6、在根目录下创建 env-dependencies.js.env.json 文件
· env-dependencies.js
const execSync = require('child_process').execSync
const pkg = require('./package.json')
const fs = require('fs')
const path = require('path')
const JSON_FILE_NAME = '.env.json'
const DEFAULT_TEST_FILE_NAME = 'isObject'
const filePath = path.join(__dirname, JSON_FILE_NAME) // 文件路径

// 检查文件是否已存在
if (!fs.existsSync(filePath)) {
	const content = {
		TEST_FILE_NAME: DEFAULT_TEST_FILE_NAME,
	}

	const jsonContent = JSON.stringify(content, null, 4)

	try {
		fs.writeFileSync(filePath, jsonContent, 'utf8')
	} catch (err) {
		console.error('写入文件时发生错误:', err)
	}
}

if (!pkg.envDependencies) {
	process.exit(0)
}

let env = Object.assign({}, process.env)

try {
	Object.assign(env, require('./' + JSON_FILE_NAME))
} catch (err) {
	console.log('Could not read or parse JSON_FILE_NAME.')
}

if (typeof pkg.envDependencies.params === 'undefined') {
	console.log('pkg.envDependencies.params not found or empty. Passing.')
	process.exit(0)
}

if (
	!Array.isArray(pkg.envDependencies.params) ||
	!(pkg.envDependencies.params.every(item => typeof item === 'string'))
) {
	throw new Error('pkg.envDependencies.params should have a signature of String[]')
}

const parsed = pkg.envDependencies.params.map(item => item.replace(/${([0-9a-zA-Z_]*)}/g, (_, varName) => {
	if (typeof env[varName] === 'string') {
		return env[varName]
	} else {
		throw new Error('Could not read env variable ' + varName + ' in params ' + item)
	}
})).join(' ')

try {
	execSync(parsed, { stdio: [0, 1, 2] })
	process.exit(0)
} catch (err) {}
· .env.json
{
    "TEST_FILE_NAME": "isObject"
}
· 在package.json中增加字段
"envDependencies": {
    "params": ["jest ./src/__tests__/${TEST_FILE_NAME}.test.ts --coverage --collectCoverageFrom=./src/${TEST_FILE_NAME}.ts"]
}
  • 7、配置 .gitignore.npmignore,忽略 .env.json 的提交
  • 8、运行 npm run test:single,可测试 .env.jsonTEST_FILE_NAME 字段配置的文件名

五、安装eslint

  • 1、安装 install eslint eslint-config-airbnb @typescript-eslint/eslint-plugin @typescript-eslint/parser -D
  • 2、新增配置文件:
· .eslintrc.js
module.exports = {
    root: true,
    env: {
        browser: true,
        node: true,
        },
    extends: [
        'airbnb',
        'plugin:@typescript-eslint/recommended',
    ],
    parser: '@typescript-eslint/parser',
    plugins: [
        '@typescript-eslint',
    ],
    globals: {
        NodeJS: 'readonly',
    },
    settings: {
        'import/resolver': {
            node: {
                extensions: ['.js', '.ts']
            },
        },
        react: {
            version: '0.0.0',
        },
    },
    rules: {
        // 添加自定义规则
        'no-console': 2,
        'no-debugger': 2,
    },
}
  • 3、增加lint命令 "lint": "eslint --ext .ts src/"
  • 4、运行 npm run lint
  • 5、安装husky,在代码提交前自动执行eslint校验 npm install husky --save-dev
  • 6、启用git钩子 npx husky install
  • 7、向package.json文件设置prepare脚本 npm pkg set scripts.prepare="husky install"
  • 8、新增一个pre-commit钩子 npx husky add .husky/pre-commit "npm run lint"

六、自动化发布

  • 1、在npm中生成 Access Tokens
    在这里插入图片描述

  • 2、将token复制到github对应仓库的秘钥中
    在这里插入图片描述

  • 3、设置一个变量名 NPM_ACCESS_TOKEN,用于之后CI中通过 secrets.NPM_ACCESS_TOKEN 获取

  • 4、在根目录下创建 .github/workflows/node.js.yml 配置文件

name: Build CI

on:
  push:
    branches: [ "main" ]

jobs:
  build:

    runs-on: ubuntu-latest
    
    permissions:
      contents: write

    strategy:
      matrix:
        node-version: [16.20.0]

    steps:
      - name: 检出分支
        uses: actions/checkout@v3

      - name: 初始化缓存
        uses: actions/cache@v3
        id: cache-dependencies
        with:
          path: node_modules
          key: ${{runner.OS}}-${{hashFiles(\'**/package-lock.json\')}}

      - name: Use Node.js ${{ matrix.node-version }}
        # 使用actions/setup-node插件
        uses: actions/setup-node@v3
        with:
          # node版本
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      - run: npm ci
      # 生成测试覆盖率
      - run: npm run test
      - run: npm run build
      
      - name: 上报测试覆盖率
        id: coverRate
        uses: coverallsapp/github-action@master
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}

      - name: 读取版本号
        id: version
        uses: notiz-dev/github-action-json-property@release
        with:
          # 读取版本号
          path: './package.json'
          prop_path: 'version'

      - name: 打印版本号
        run: echo ${{steps.version.outputs.prop}}

      - name: 创建Release
        uses: softprops/action-gh-release@v1
        with:
          files: |
            ./lib/index.umd.js
            ./lib/index.esm.js
            ./lib/index.cjs.js
          name: v${{steps.version.outputs.prop}}
          tag_name: v${{steps.version.outputs.prop}}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: 发布NPM包
        run: |
          npm config set //registry.npmjs.org/:_authToken=$NPM_TOKEN
          npm publish
        env:
          # 配置 npm access token 环境变量
          NPM_TOKEN: ${{secrets.NPM_ACCESS_TOKEN}}

七、为readme添加测试覆盖率badge

  • 1、进入coveralls官网,授权 github,https://coveralls.io/
  • 2、授权后点击左侧侧边栏的 ADD REPOS,将需要生成badge徽章的库设置为on
  • 3、在readme中添加连接即可查看 <img src='https://coveralls.io/repos/github/{用户名}/{仓库名}/badge.svg?branch=main' />

八、整体目录结构

- .github
    - workflows
        - xx.yml        # git Actions
- .husky
    _
    pre-commit          # git提交钩子
- src
    - __test__          # 单元测试
    - index.ts          # 入口文件
    - isObject.ts
- .env.json             # 环境变量配置
- .eslintignore
- .eslintrc.js
- .gitignore
- .npmignore
- env-dependencies.js   # 环境变量读取脚本
- jest.config.js
- package.json
- rollup.config.js
- tsconfig.json

九、完整package.json配置

{
	"name": "your project name",
	"version": "0.0.1",
	"description": "your project description",
	"browser": "lib/index.esm.js",
	"module": "lib/index.esm.js",
	"jsnext:main": "lib/index.esm.js",
	"main": "lib/index.cjs.js",
	"types": "lib/types/index.d.ts",
	"files": ["lib"],
	"scripts": {
		"lint": "eslint --ext .ts src/",
		"build": "rollup -c",
		"test": "jest",
		"test:single": "node env-dependencies.js",
		"prepare": "husky install"
	},
	"envDependencies": {
		"params": ["jest ./src/__tests__/${TEST_FILE_NAME}.test.ts --coverage --collectCoverageFrom=./src/${TEST_FILE_NAME}.ts"]
	},
	"keywords": ["modules", "stdlib", "util"],
	"author": "Unknow",
	"license": "MIT",
	"devDependencies": {
		"@rollup/plugin-commonjs": "^25.0.0",
		"@rollup/plugin-node-resolve": "^15.1.0",
		"@rollup/plugin-terser": "^0.4.3",
		"@rollup/plugin-typescript": "^11.1.1",
		"@types/jest": "^29.5.2",
		"@typescript-eslint/eslint-plugin": "^5.59.9",
		"@typescript-eslint/parser": "^5.59.9",
		"babel-jest": "^29.5.0",
		"eslint": "^8.42.0",
		"eslint-config-airbnb": "^19.0.4",
		"husky": "^8.0.3",
		"jest": "^29.5.0",
		"jest-environment-jsdom": "^29.5.0",
		"rollup": "^3.23.0",
		"rollup-plugin-delete": "^2.0.0",
		"ts-jest": "^29.1.0",
		"tslib": "^2.5.2",
		"typescript": "~5.0.4"
	},
	"repository": {
		"type": "git",
		"url": "https://github.com/xxx.git"
	}
}

References

[1] 使用Typescript和Rollup从零开发一个工具库

[2] 一篇文章教会你如何在npm上传自己的包

[3] husky工具介绍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/289242.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AUTOSAR软件手册文档缩写描述,AUTOSAR_TR_PredefinedNames

由于AUTOSAR文档中的缩写太多&#xff0c;入门者看起开不方便。例如TR、SWS、SRS、EXP模块。 下载链接&#xff1a;https://www.autosar.org/fileadmin/standards/R21-11/FO/AUTOSAR_TR_PredefinedNames.pdf

终于学会听英文歌了:A Sad Me In Your Eyes

A Sad Me In Your Eyes 来源&#xff1a; https://lyricstranslate.com/en/ln-party-sad-me-your-eyes-lyrics.html Fire can’t burn in my eyes If without your smile Snow can cover your smile If without your love When you think of me, I’ve gone too far I can’t …

8K自动化测试面试题分享(有答案,非常详细)

关于自动化测试面试&#xff0c;会问到哪些问题呢&#xff1f;给大家简单总结了一下&#xff0c;每一个都是学员反馈过来的企业真题&#xff0c;相信对大家有帮助&#xff0c;最近有面试机会的&#xff0c;快来背一下答案吧 1、你会封装自动化测试框架吗&#xff1f; 这个问得…

单片机外设矩阵键盘之线反转法识别原理与示例

单片机外设矩阵键盘之线反转法识别原理与示例 1.概述 这篇文章主要介绍单片机接收 4X4矩阵键盘发出的指令&#xff0c;做出对应的反馈。其中主要介绍矩阵键盘线反转方式的识别原理和实操。 2.矩阵键盘线反转识别原理 2.1.矩阵键盘硬件接线原理 矩阵键盘的硬件接线方式有多种…

Nginx 中的日志

目录 1.定制访问日志记录格式 1.1 全部日志记录 1.2 每个网站独属一份日志 2.日志路径 3.错误日志 1.定制访问日志记录格式 1.1 全部日志记录 该配置处于nginx.conf 文件中 log_format compression $remote_addr - $remote_user [$time_local] "$request" $sta…

源支付V7最新修复版,V2.7.9最新版

源支付V7最新修复版&#xff0c;V2.7.9最新版 注&#xff1a;开发不易&#xff0c;仅限交流学习使用&#xff0c;如商业使用&#xff0c;请支持正版&#xff01; 轻量化的界面 UI, 提供更加便捷的操作体验&#xff0c;让您的系统一目了然 推荐支付宝当面付 - 免 CK - 商家版&a…

【ZYNQ入门】第三篇、双核AMP运行模式程序开发

目录 第一部分、基础知识 1、多核CPU三种主要运行模式 2、ZYNQ内部FSBL涉及到的启动过程 2.1、BootRom是啥&#xff1f; 2.2、FSBL是啥&#xff1f; 2.3、ARM与cortex的关系 2.4、本次实验的启动流程 第二部分、FSBL环境配置过程 1、vivado配置硬件 2、SDK新建FSBL配…

8天狂收6000+⭐️,可商用的开源Stream Diffusion

加州大学伯克利分校、东洋大学、东京工业大学、麻省理工学院和筑波大学等研究人员&#xff0c;联合开源了一款创新性实时交互图像生成框架——Stream Diffusion。 Stream Diffusion的技术创新点在于&#xff0c;将传统的顺序去噪变成流批处理去噪&#xff0c;消除了漫长的等待…

大模型实战营第二期——1. 书生·浦语大模型全链路开源开放体系

文章目录 1. 实战营介绍2. 书生浦语大模型介绍2.1 数据2.2 预训练2.3 微调2.4 评测2.5 部署2.6 智能体(应用) 1. 实战营介绍 github链接&#xff1a;https://github.com/internLM/tutorialInternLM&#xff1a;https://github.com/InternLM书生浦语官网&#xff1a;https://in…

使用Vue3开发学生管理系统模板7 科目信息的实现

字段设计 IDname&#xff1a;课程名称&#xff0c;字符串&#xff0c;最大36字符start_time&#xff1a;开设时间&#xff0c;日期类型teacher_total&#xff1a;该科目老师人数&#xff0c;数字类型master_id&#xff1a;负责人ID&#xff0c;字符串&#xff0c;最大36字符ma…

二、UI文件设计与运行机制

一、UI文件设计与运行机制 1、创建工程 2、添加控件&#xff0c;实现按钮点击 &#xff08;1&#xff09;添加控件 &#xff08;2&#xff09;添加信号和槽 2、分析项目结构 test_02test_02.pro Qt工程文件Headerswidget.h 设计的窗体类的头文件Sourcesmain.cpp 主程序入…

印象笔记03 衍生软件使用

印象笔记03 衍生软件使用 Verse 以下内容来源于官方介绍 VERSE是一款面向未来的智能化生产力工具&#xff0c;由印象笔记团队诚意推出。 你可以用VERSE&#xff1a; 管理数字内容&#xff0c;让信息有序高效运转&#xff1b;搭建知识体系&#xff0c;构建你的强大知识库&am…

高防ip适合防御网站和游戏类的攻击吗?

​  作为站长&#xff0c;要学会并承受得住网站外来攻击的压力&#xff0c;尤其是所属为 DDoS 攻击高发行业的网站类业务及游戏行业&#xff0c;是很容易被竞争对手或者一些伪黑客爱好者盯上的。 加上&#xff0c;有些站长并没有提前了解&#xff0c;就盲目进军了这两个行业&…

看板表格样式,去掉element表格背景

<div class"ml-20"><el-input v-model.trim"queryParams.wipOrderNo" size"small" clearable style"width:150px" placeholder"请输入工单号" /><el-select class"ml-20" v-model"queryParam…

[数据结构 C++] AVL树的模拟实现

文章目录 1、AVL树1.1 AVL树的概念 2、AVL树节点的定义3、AVL树的插入和旋转3.1 左单旋左旋代码实现 3.2 右单旋右旋代码实现 3.3 右左双旋右左双旋的代码实现 3.4 左右双旋左右双旋的代码实现 3.5 insert接口实现 4、判断是否为AVL树判断AVL树的代码实现 5、AVL树的性能 问题引…

金和OA c6 uploadfileeditorsave接口存在任意文件上传漏洞

产品简介 金和网络是专业信息化服务商&#xff0c;为城市监管部门提供了互联网监管解决方案&#xff0c;为企事业单位提供组织协同OA系统升开发平台&#xff0c;电子政务一体化平台智慧电商平合等服务 漏洞概述 金和-c6 uploadfileeditorsave 任意文件上传&#xff0c;攻击者…

计算机网络(9):无线网络

无线局域网 WLAN 无线局域网常简写为 WLAN (Wireless Local Area Network)。 无线局域网的组成 无线局域网可分为两大类。第一类是有固定基础设施的&#xff0c;第二类是无固定基础设施的。所谓“固定基础设施”是指预先建立起来的、能够覆盖一定地理范围的一批固定基站。 …

6个关键词,回顾网络安全行业的 2023!

话不多说&#xff0c;直接上 01 生成式人工智能 AIGC 热度&#xff1a;⭐️⭐️⭐️⭐️⭐️ AIGC 的发展不仅降低了内容创作的门槛&#xff0c;还为聊天机器人、数字人、元宇宙等领域提供了新的发展机遇。2023 年 8 月&#xff0c;首届人工智能生成内容国际会议在上海落地&…

Paddle3D 2 雷达点云CenterPoint模型训练

2 Paddle3D 雷达点云CenterPoint模型训练–包含KITTI格式数据地址 2.0 数据集 百度DAIR-V2X开源路侧数据转kitti格式。 2.0.1 DAIR-V2X-I\velodyne中pcd格式的数据转为bin格式 参考源码&#xff1a;雷达点云数据.pcd格式转.bin格式 def pcd2bin():import numpy as npimport…

C++面向对象语法总结(三)

目录 《C面向对象语法总结(一&#xff09;》《C面向对象语法总结(二&#xff09;》 二十一、多继承 C允许一个类可以有多个父类&#xff08;不建议使用&#xff0c;会增加程序设计复杂度&#xff09;在多继承中&#xff0c;会按照继承顺序将父类的成员变量放到子类成员变量的…