前提:
- node已经安装(v14.20.0)、npm下载了源(https://registry.npmjs.org/)
目的:
- 发布自己的插件用于项目中
创建项目
- 创建文件夹
mkdir hell-lib
- 进入文件夹
cd hello-lib
//初始化成为一个node项目(初始化后生成一个package.json文件)
npm init -y
- package.json
{
//这个名称是项目名称-后面会与发布有关
"name": "@learningvue3/lib",
"version": "1.0.0",
"description": "A library demo for learningvue3.",
"author": "chengpeiquan <chengpeiquan@chengpeiquan.com>",
"homepage": "https://github.com/learningvue3/hello-lib",
"repository": {
"type": "git",
"url": "git+https://github.com/learningvue3/hello-lib.git"
},
"license": "MIT",
"files": ["dist"],
"main": "dist/index.cjs",
"module": "dist/index.mjs",
"browser": "dist/index.min.js",
"types": "dist/index.d.ts",
"keywords": ["library", "demo", "example"],
"scripts": {
"build": "vite build"
}
}
- 在该项目下全局下载vite
npm i -D vite
- 添加配置文件
// vite.config.ts
import { defineConfig } from 'vite'
// https://cn.vitejs.dev/config/
export default defineConfig({
build: {
// 输出目录
outDir: 'dist',
// 构建 npm 包时需要开启 “库模式”
lib: {
// 指定入口文件
entry: 'src/index.ts',
// 输出 UMD 格式时,需要指定一个全局变量的名称
name: 'hello',
// 最终输出的格式,这里指定了三种
formats: ['es', 'cjs', 'umd'],
// 针对不同输出格式对应的文件名
fileName: (format) => {
switch (format) {
// ES Module 格式的文件名
case 'es':
return 'index.mjs'
// CommonJS 格式的文件名
case 'cjs':
return 'index.cjs'
// UMD 格式的文件名
default:
return 'index.min.js'
}
},
},
// 压缩混淆构建后的文件代码
minify: true,
},
})
- 创建入口文件
//根据配置文件的信息我们需要在项目下创建入口文件=》src/index.ts
// src/index.ts
export default function hello(name: string) {
console.log(`Hello ${name}`)
}
- 构建项目
npm run build
- 生成如下项目
hello-lib
│ # 构建产物的输出文件夹
├─dist
│ ├─index.cjs
│ ├─index.min.js
│ └─index.mjs
│ # 依赖文件夹
├─node_modules
│ # 源码文件夹
├─src
│ │ # 入口文件
│ └─index.ts
│ # 项目清单信息
├─package-lock.json
├─package.json
│ # Vite 配置文件
└─vite.config.ts
编写npm包代码
1、前期准备
- 创建utils.ts(后面需要发布的内容)
// src/utils.ts
/**
* 生成随机数
* @param min - 最小值
* @param max - 最大值
* @param roundingType - 四舍五入类型
* @returns 范围内的随机数
*/
export function getRandomNumber(
min: number = 0,
max: number = 100,
roundingType: 'round' | 'ceil' | 'floor' = 'round'
) {
return Math[roundingType](Math.random() * (max - min) + min)
}
/**
* 生成随机布尔值
*/
export function getRandomBoolean() {
const index = getRandomNumber(0, 1)
return [true, false][index]
}
- 创建入口
//src/index.ts
export * from './utils'
- npm run build
可以看到构建的dist的文件中编译后的信息就是npm包内容了
2、npm包本地测试(重点)
- 创建本地软链接
//创建npm包的本地链接
npm link
//终端执行完会生成:
//(node_modules/@learningvue3/lib中的@learningvue3是package.json中的name)
// /Users/XXX/.nvm/versions/node/v14.20.0/lib/node_modules/@learningvue3/lib -> /Users/XX/XX/project/vue3/npm/hello-lib
- 在别的vue项目中根据软链接下载该项目包进行发布前的本地测试(@learningvue3/lib)
//链接下载@learningvue3/lib
npm link @learningvue3/lib
//然后在该vue的node-module中可以看到该包已经在了,然后就可以调用方法了
- 测试(在vue项目下载@learningvue3/lib后就可以直接引入调用如下方法)
//注意@learning-vue3/lib会报红色波浪线(下一步会解决:生成DTS文件)
import { getRandomNumber } from '@learning-vue3/lib'
const num = getRandomNumber()
console.log(num)
生成 DTS 文件
- typescript(hello-lib)
//安装
npm install -g typescript
//编译生成-tsconfig.json
tsc --init
- tsconfig.json修改以下几项配置
//其中 compilerOptions 三个选项的意思是:
// .ts 源文件不编译为 .js 文件,
// 只生成 .d.ts 文件并输出到 dist 目录;
// include 选项则告诉 TypeScript 编译器,只处理 src 目录下的 TS 文件。
{
"compilerOptions": {
"declaration": true,
"emitDeclarationOnly": true,
"declarationDir": "./dist"
},
"include": ["./src"]
}
- 编译
//编译后在dist中会看到 .d.ts 后缀文件
tsc
//去测试的vue项目中 执行 npm run build 就会看到 红色波浪线取消了
- hello-lib 项目的 package.json 已提前指定了类型声明文件指向:
{
"types": "dist/index.d.ts"
}
注意
由于上述的方式会导致每个文件都会生成一个.d.ts 声明文件,不是很好的解决方式,常用以下方式解决
生成 DTS Bundle
- 安装
npm i -D dts-bundle-generator
- 创建文件(文件夹scripts, 目录下再创建 buildTypes.mjs )
// scripts/buildTypes.mjs
import { writeFileSync } from 'fs'
import { dirname, resolve } from 'path'
import { fileURLToPath } from 'url'
import { generateDtsBundle } from 'dts-bundle-generator'
async function run() {
// 默认情况下 `.mjs` 文件需要自己声明 __dirname 变量
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
// 获取项目的根目录路径
const rootPath = resolve(__dirname, '..')
// 添加构建选项
// 插件要求是一个数组选项,支持多个入口文件
const options = [
{
filePath: resolve(rootPath, `./src/index.ts`),
output: {
noBanner: true,
},
},
]
// 生成 DTS 文件内容
// 插件返回一个数组,返回的文件内容顺序同选项顺序
const dtses = generateDtsBundle(options, {
preferredConfigPath: resolve(rootPath, `./tsconfig.json`),
})
if (!Array.isArray(dtses) || !dtses.length) return
// 将 DTS Bundle 的内容输出成 `.d.ts` 文件保存到 dist 目录下
// 当前只有一个文件要保存,所以只取第一个下标的数据
const dts = dtses[0]
const output = resolve(rootPath, `./dist/index.d.ts`)
writeFileSync(output, dts)
}
run().catch((e) => {
console.log(e)
})
- 运行buildTypes.mjs需要在package,json添加执行命令如下
{
"scripts": {
"build": "vite build && npm run build:types",
"build:types": "node scripts/buildTypes.mjs"
}
}
- npm run build
hello-lib
└─dist
├─index.cjs
├─index.d.ts
├─index.min.js
└─index.mjs
- 添加说明文档:(选用README .md,模版如下)
# 项目名称
写上项目用途的一句话简介。
## 功能介绍
1. 功能 1 一句话介绍
2. 功能 2 一句话介绍
3. 功能 3 一句话介绍
## 在线演示
如果有部署在线 demo ,可放上 demo 的访问地址。
## 安装方法
使用 npm : `npm install package-name`
使用 CDN : `https://example.com/package-name`
## 用法
告诉使用者如何使用 npm 包。
## 插件选项
如果 npm 包是一个插件,并支持传递插件选项,在这里可以使用表格介绍选项的作用。
| 选项名称 | 类型 | 作用 |
| :------: | :----: | :--------: |
| foo | string | 一句话介绍 |
| bar | number | 一句话介绍 |
更多内容请根据实际情况补充。
npm 注册
- 注册:https://www.npmjs.com
- 创建npm项目(https://www.npmjs.com/package)
注意:
- 这里的Name要与你发布的npm项目package.json相关
- 比如package,json的name是@learningvue3/lib,则npm创建的name就可以是learningvue3
- 不然的话会在发布的时候报错404(我的是这样解决的)
- 项目登陆
在你发布的npm的项目下打开终端进行命令登陆
npm login
//执行后会有填写账号密码邮箱和校验码信息
- npm 发布
npm publish --access public
注意
报错403
- 查看npm源是不是https://registry.npmjs.org/
报错404
- 查看项目的package.json中的name与npm创建的组织名称是否对应