总结
发布一个 npm 包的完整流程如下:
- 创建并初始化项目。
- 配置开发工具(如 Rollup、TypeScript、Jest 等)并编写源代码。
- 打包并生成类型声明文件(如果使用 TypeScript)。
- 配置 package.json,准备发布。
- 发布包到npm registry。
- 根据需求更新版本并继续发布更新
一、创建并初始化项目
- 在终端中创建一个新的文件夹,进入该文件夹。
mkdir my-npm-package
cd my-npm-package
- 使用 npm init 命令来初始化 package.json 文件。
npm init
二、配置开发依赖并编写源代码
配置开发相关依赖
1. TypeScript(可选,如果需要使用 TypeScript)
安装相关依赖
npm install typescript -D
配置tsconfig
{
"compilerOptions": {
"target": "es5", // 编译后的 JavaScript 代码目标版本为 ES5。
"module": "esnext", // 设置模块系统为 ESNext。
// 输出的目录
"outDir": "./lib", // 编译后的 JavaScript 和类型声明文件输出到 `lib` 目录。可以根据需要调整为其他目录名。
"strict": true, // 启用 TypeScript 的严格类型检查模式。
"noImplicitAny": false, // 允许隐式 `any` 类型。
// 模块的解析策略
"moduleResolution": "node", // 设置模块解析方式为 `node`。
"esModuleInterop": true, // 允许使用 CommonJS 模块的默认导入(即 `require`),并使其能够以 ES6 模块的语法进行导入。
"skipLibCheck": true, // 跳过库文件的类型检查。这可以提高编译速度,特别是对于包含大量类型定义的第三方库。
"forceConsistentCasingInFileNames": true, // 强制文件名的大小写一致性。
// 只生成类型文件,不转换代码
"declaration": true, // 启用类型声明文件的生成,生成 `.d.ts` 文件。
"emitDeclarationOnly": true, // 只生成类型声明文件,不生成 JavaScript 代码。这通常用于只发布类型声明的库。
},
// 只编译 src 目录下的文件
"include": [
"src"
],
"exclude": [
"tests" // 排除 `tests` 目录下的文件不进行编译。
]
}
2. ESLint(代码规范检查)
安装依赖
npm install eslint @eslint/js globals -D
-
@eslint/js: ESLint 的一个扩展包,包含了一组新的 JavaScript 编码规则,用于在项目中启用和定制特定的 JavaScript 规则(例如:ES6+ 语法支持、代码风格等)。
-
globals: 包含了常见 JavaScript 环境中预定义的全局变量列表。例如,浏览器环境中的 window 和 document,或者 Node.js 中的 process 和 Buffer 等。
若项目使用了ts,需要同步安装以下依赖
npm install eslint -D
配置eslint.config.js
在根目录新建eslint.config.js
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
/** @type {import('eslint').Linter.Config[]} */
export default [
{files: ["**/*.{js,mjs,cjs,ts}"]},
{languageOptions: { globals: globals.browser }},
pluginJs.configs.recommended,
...tseslint.configs.recommended,
];
3. Rollup 配置(打包工具)
安装rollup相关依赖
npm install rollup @rollup/plugin-commonjs @rollup/plugin-node-resolve @rollup/plugin-typescript -D
- @rollup/plugin-commonjs 这个插件用于将 CommonJS 模块转换为 ES 模块,使得 Rollup 可以处理和打包 CommonJS 格式的第三方库(例如 Node.js 模块)。 创建 rollup.config.js 文件,配置如何打包你的包。
- @rollup/plugin-node-resolve 这个插件让Rollup 能够正确解析并打包外部的依赖(例如:你安装的 npm 包),而不需要显式地指定模块路径
- @rollup/plugin-typescript 这个插件用于让 Rollup 处理 TypeScript 文件(.ts 和 .tsx)。此插件会使用 tsc(TypeScript 编译器)来编译 TypeScript 文件,并生成相应的 JavaScript 文件。
配置rollup
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import typescript from '@rollup/plugin-typescript';
import commonjs from '@rollup/plugin-commonjs';
import pkg from './package.json' assert { type: 'json' };
const footer = `
if (typeof window !== 'undefined') {
window._Dry_VERSION_ = '${pkg.version}'
}`;
export default {
input: './src/index.ts',//input 配置指定了打包的入口文件。
output: [
{
file: pkg.main,
format: 'cjs',// 输出一个 CommonJS 格式的文件,适合在 Node.js 环境中使用。该文件会被存储在 pkg.main 指定的路径中。
footer,
},
{
file: pkg.module,
format: 'esm',// 输出一个 ES模块 格式的文件,适用于现代 JavaScript 环境(包括浏览器和支持 ES模块的 Node.js)。
footer,
},
{
file: pkg.browser,
format: 'umd',// 输出一个 UMD 格式的文件,适合在浏览器和 Node.js 环境中使用(即兼容浏览器、Node.js 和 AMD 模块系统)。该文件会被存储在 pkg.browser 指定的路径中。
name: 'Dry',// 'Dry' 是指在浏览器环境下,UMD 模块会暴露一个全局变量 Dry,它指向模块的导出。
footer,// 在每个输出格式的文件结尾加上 footer 中定义的代码,以便在浏览器中使用时将版本号暴露给全局变量
},
],
plugins: [
typescript(),
commonjs(),
resolve(),
],
};
4. Jest(单元测试)
安装 Jest:
npm install jest ts-jest @types/jest -D
- 配置jest 在根路径下新建jest.config.js
// jest.config.js
/** @type {import('ts-jest').JestConfigWithTsJest} **/
module.exports = {
testEnvironment: "node",
transform: {
"^.+.tsx?$": ["ts-jest",{}],
},
};
- 编写测试文件
// src/__tests__/add.test.js
const { add } = require('../index');
test('adds 1 + 2 to equal 3', () => {
expect(add(1, 2)).toBe(3);
});
- 在 package.json 中配置构建脚本
"scripts": {
"test": "jest"
}
编写包的核心代码
创建一个 src 文件夹来存放源代码。比如,创建一个 src/index.ts 文件 示例代码(一个简单的函数)
// src/index.ts
/**
* Adds two numbers
* @param {number} a
* @param {number} b
* @returns {number} sum
*/
function add(a:number, b:number):number {
return a + b;
}
module.exports = { add };
三、打包并生成类型声明文件
- 在 package.json 中配置构建脚本,使用 Rollup 来打包代码。
"scripts": {
"build": "rollup -c",
}
- 构建运行与测试
npm run build # 打包项目
npm test # 运行测试
四、配置 package.json,准备发布
在 package.json 中配置必要的字段,确保包的名称、版本、入口文件等都设置正确。重要字段包括:
- name:包的名称,必须是唯一的。
- version:遵循语义版本控制(SemVer),如 1.0.0。
- main:CommonJS 入口文件。
- module:ESM 入口文件。
- types:类型声明文件的位置(如果使用 TypeScript)。
- files:发布时包含的文件或文件夹,通常包括 dist、lib 等。
{
"name": "my-npm-package",
"version": "1.0.0",
"main": "dist/bundle.cjs.js",
"module": "dist/bundle.esm.js",
"types": "dist/index.d.ts",
"files": [
"dist"
]
}
可供参考的package.json配置
{
"name": "your-package-name", // 包的名称,必须是唯一的,格式支持 scoped 包(如 @scope/package-name)
"version": "1.0.0", // 包的版本号,遵循语义版本控制(SemVer)
"main": "lib/bundle.cjs.js", // CommonJS 模块的入口文件,用于 Node.js 环境中的 `require`
"module": "lib/bundle.esm.js", // ES 模块的入口文件,用于现代 JS 环境中的 `import`
"browser": "lib/bundle.browser.js", // 浏览器环境的入口文件,通常用于前端项目
"types": "types/index.d.ts", // TypeScript 类型声明文件的位置,帮助 TypeScript 用户了解该包的类型
"type": "module", // 指定模块系统为 ES Modules (ESM)
"files": [ // 定义要包括在发布包中的文件,这里指定了 lib 文件夹
"lib"
],
"engines": {
"node": ">=14.0.0"//规定了包支持的 Node.js 版本。避免用户安装在不兼容的 Node.js 版本中。
},
"repository": { // 包的源代码仓库信息,通常用于指向 GitHub 或 GitLab 仓库
"type": "git", // 仓库类型
"url": "" // 仓库 URL,这里需要填写你的代码仓库地址
},
"homepage":"",//包的主页,可以是 GitHub 页面或文档页面等
"exports": { // 定义包对外提供的模块导出格式,适应不同环境(Node.js、浏览器)
".": {
"import": "./lib/bundle.esm.js", // ESM 模块的导出路径
"require": "./lib/bundle.cjs.js" // CommonJS 模块的导出路径
},
"./browser": {
"browser": "./lib/bundle.browser.js" // 浏览器环境下的导出路径
}
},
"scripts": { // 定义可以执行的脚本命令
"build": "rollup -c", // 执行构建任务,使用 Rollup 打包项目
"build:types": "tsc", // 生成 TypeScript 类型声明文件
"test": "jest", // 执行测试命令,使用 Jest 进行测试
"publish": "npm publish" // 执行发布任务,使用 npm 将包发布到 NPM Registry
},
"author": "", // 包的作者信息,通常是作者的名字或联系方式
"license": "ISC", // 包的开源许可证类型,通常是 `MIT` 或 `ISC` 等
"description": "", // 包的简短描述,说明包的用途
"keywords": [ // 包的关键词,帮助用户通过搜索找到你的包
],
"devDependencies": { // 开发依赖,包含用于开发、构建和测试的依赖
},
"dependencies": { // 运行时依赖,包含包正常运行所需要的依赖
},
"peerDependencies": {// 声明包所依赖的其他包版本
}
}
五、发布包到npm registry
- 在发布之前,确保已经注册了一个 npm 账户,并在终端中登录
npm login
- 发布包 运行以下命令来发布包:
npm publish
- 默认情况下,
npm publish
会将包发布到 npm 注册表,使用的是包的当前访问级别设置。 - 对于新包,默认是
public
访问级别,也就是说任何人都可以安装这个包。 - 对于已经存在的包,
npm publish
会遵循包当前的访问级别设置,不改变访问权限。
如果希望以公开访问的方式发布包,可使用以下命令:
npm publish --access public
六、根据需求更新版本并继续发布更新
如果需要发布更新,修改代码后增大版本号(遵循 SemVer),然后执行以下命令:
npm version patch # 或者 minor/major,根据更改的内容
npm publish